MariaDB 10.1 Order By + Limit inconsistencies - mysql

When running an order by query with a limit on MariaDB 10.1.18, I get back a wrong order.
Observe the query without the LIMIT statement:
select advert_id, published, id from vacancies order by published asc;
+-----------+-----------+----+
| advert_id | published | id |
+-----------+-----------+----+
| 328377 | 0 | 70 |
| 328844 | 0 | 80 |
| 325263 | 0 | 41 |
| 325774 | 0 | 40 |
| 325775 | 0 | 39 |
| 325929 | 0 | 38 |
| 325885 | 0 | 37 |
| 325901 | 0 | 36 |
| 325920 | 0 | 35 |
| 325917 | 0 | 34 |
| 325922 | 0 | 33 |
| 325889 | 0 | 32 |
| 325927 | 0 | 31 |
| 325238 | 0 | 43 |
| 325244 | 0 | 45 |
| 328365 | 0 | 71 |
| 328446 | 0 | 72 |
| 328362 | 0 | 68 |
| 323602 | 0 | 55 |
| 324250 | 0 | 54 |
| 324254 | 0 | 53 |
| 324911 | 0 | 52 |
With the LIMIT statement:
select advert_id, published, id from vacancies order by published asc limit 10;
+-----------+-----------+----+
| advert_id | published | id |
+-----------+-----------+----+
| 327830 | 0 | 1 |
| 326865 | 0 | 18 |
| 327328 | 0 | 9 |
| 326877 | 0 | 16 |
| 326783 | 0 | 21 |
| 326779 | 0 | 17 |
| 326774 | 0 | 15 |
| 326864 | 0 | 20 |
| 326788 | 0 | 14 |
| 326767 | 0 | 19 |
+-----------+-----------+----+
The order by on published is different in both queries.
For comparison, I ran the same queries on MariaDB 5.5.50 and found the order by + limit correctly returns the same result as the order by query. So from what I understand is that this issue is MariaDB specific, and only exists on newer versions.
Additionally I also ran the same queries, but ordering on a varchar field with a lot of different values, in that case the order was correct. So I'm thinking the problem only applies to ordering with limit on a field that has a lot of the same values.
Does anyone know if there is a way around this? Perhaps a setting in MariaDB?
FYI:
Table structure:
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| advert_id | int(11) | YES | | NULL | |
| published | tinyint(1) | NO | | 0 | |
| (other fields omitted)
Explain on query:
explain select advert_id, published, id from vacancies order by published asc;
+------+-------------+-----------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | vacancies | ALL | NULL | NULL | NULL | NULL | 52 | Using filesort |
+------+-------------+-----------+------+---------------+------+---------+------+------+----------------+
explain select advert_id, published, id from vacancies order by published asc limit 10;
+------+-------------+-----------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | vacancies | ALL | NULL | NULL | NULL | NULL | 52 | Using filesort |
+------+-------------+-----------+------+---------------+------+---------+------+------+----------------+
Version with order by issue:
mysql Ver 15.1 Distrib 10.1.18-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Version without order by issue:
mysql Ver 15.1 Distrib 5.5.50-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

You do not specify which ten first rows you want to obtain. As there are a lot of rows for which published equals 0 MariaDB is free to choose some of them. If you want a specific order try:
SELECT advert_id, published, id FROM vacancies ORDER BY published asc, id LIMIT 10;

Related

Complex INSERT or UPDATE MariaDB tables with data from other MariaDB tables using JOIN or UNION

I need to INSERT or UPDATE data in a table using data from other tables; I understand the basic
insert into table (a,b,c)
select h, i, j
from otherTable
where........
My challenge comes from the fact that the data is spread across multiple tables and in one of the tables the data is metadata stored in rows, not columns. Therefore I need to use JOIN and possible UNION to get what is needed.
Unfortunately after trying everything I read in both the Maria manual, on the Maria forum and on Stack overflow I can not get it to work.
Here is what I am attempting to do:
insert data into dbc_jot_groupmembers in the following fields using source data as shown:
jot_grpid = dbc_bp_groups_members.group_id
jot_bbmemid = dbc_bp_groups_members.user_id
jot_grpmemname = dbc_bp_xprofile_data.value where field_id=3
jot_grpmemnum = dbc_bp_xprofile_data.value where field_id=4
I need the final result to look like this:
select * from dbc_jot_groupmembers;
+--------------+-----------+----------------+---------------+---------------------+-------------+
| jot_grpmemid | jot_grpid | jot_grpmemname | jot_grpmemnum | jot_grpmemts | jot_bbmemid |
+--------------+-----------+----------------+---------------+---------------------+-------------+
| 1 | 17 | hutchdad | +17047047045 | 2021-06-15 14:56:19 | 14 |
| 2 | 24 | hutchdad | +17047047045 | 2021-06-15 19:49:58 | 14 |
| 3 | 25 | hutchdad | +17047047045 | 2021-06-15 19:49:58 | 14 |
| 4 | 17 | hutchmom | +17773274355 | 2021-06-15 19:49:58 | 15 |
| 5 | 24 | hutchmom | +17773274355 | 2021-06-15 19:49:58 | 15 |
| 6 | 16 | ledwards | +14567655645 | 2021-06-15 19:49:58 | 11 |
| 7 | 16 | medwards | +12223334545 | 2021-06-15 19:49:58 | 10 |
| 7 | 20 | medwards | +12223334545 | 2021-06-15 19:49:58 | 10 |
SAMPLE DATA FROM SOURCE TABELS AND TABLE DEFINITIONS:
MariaDB [devDisciplePlaceCom]> describe dbc_bp_groups_members;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| group_id | bigint(20) | NO | MUL | NULL | |
| user_id | bigint(20) | NO | MUL | NULL | |
| inviter_id | bigint(20) | NO | MUL | NULL | |
| is_admin | tinyint(1) | NO | MUL | 0 | |
| is_mod | tinyint(1) | NO | MUL | 0 | |
| user_title | varchar(100) | NO | | NULL | |
| date_modified | datetime | NO | | NULL | |
| comments | longtext | NO | | NULL | |
| is_confirmed | tinyint(1) | NO | MUL | 0 | |
| is_banned | tinyint(1) | NO | | 0 | |
| invite_sent | tinyint(1) | NO | | 0 | |
+---------------+--------------+------+-----+---------+----------------+
12 rows in set (0.002 sec)
describe dbc_bp_xprofile_data;
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| field_id | bigint(20) unsigned | NO | MUL | NULL | |
| user_id | bigint(20) unsigned | NO | MUL | NULL | |
| value | longtext | NO | | NULL | |
| last_updated | datetime | NO | | NULL | |
+--------------+---------------------+------+-----+---------+----------------+
5 rows in set (0.001 sec)
THIS IS THE LIST OF GROUPS AND WHAT USERS THEY ARE IN.
select group_id,user_id from dbc_bp_groups_members ;
+----------+---------+
| group_id | user_id |
+----------+---------+
| 16 | 13 |
| 16 | 12 |
| 16 | 11 |
| 16 | 10 |
| 17 | 14 |
| 17 | 15 |
| 17 | 16 |
| 17 | 17 |
| 17 | 18 |
| 17 | 19 |
| 20 | 10 |
| 24 | 14 |
| 24 | 16 |
| 24 | 15 |
| 24 | 17 |
| 24 | 19 |
| 25 | 19 |
| 25 | 14 |
| 1 | 14 |
| 11 | 14 |
+----------+---------+
20 rows in set (0.000 sec)
THIS IS THE TABLE CONTAINING THE USERS METADATA. IN MY CASE I NEED THE PHOEN NUMBER AND NAME WHICH ARE IN THE value FIELD WITH A field_id of 3 and 4.
select * from dbc_bp_xprofile_data where user_id > 9 and field_id > 2 AND field_id < 5;
+-----+----------+---------+---------------+---------------------+
| id | field_id | user_id | value | last_updated |
+-----+----------+---------+---------------+---------------------+
| 31 | 3 | 10 | medwards | 2021-06-24 03:11:59 |
| 34 | 3 | 11 | ledwards | 2021-06-24 03:11:24 |
| 37 | 3 | 12 | nedwards | 2021-04-24 14:47:18 |
| 40 | 3 | 13 | iedwards | 2021-04-24 14:47:52 |
| 43 | 3 | 14 | hutchdad | 2021-06-21 14:53:08 |
| 46 | 3 | 15 | hutchmom | 2021-06-24 03:10:58 |
| 49 | 3 | 16 | hutchdaughter | 2021-04-24 16:54:48 |
| 52 | 3 | 17 | hutchson1 | 2021-04-24 16:55:43 |
| 55 | 3 | 18 | hutchson2 | 2021-04-24 16:57:42 |
| 58 | 3 | 19 | hutchson3 | 2021-04-24 16:58:44 |
| 78 | 3 | 25 | demoadmin | 2021-06-08 02:01:39 |
| 158 | 4 | 14 | 7047047045 | 2021-06-21 14:53:08 |
| 190 | 3 | 58 | dupdup | 2021-06-23 19:46:19 |
| 191 | 4 | 15 | 7773274355 | 2021-06-24 03:10:58 |
| 193 | 4 | 11 | 4567655645 | 2021-06-24 03:11:24 |
| 195 | 4 | 10 | 2223334545 | 2021-06-24 03:11:59 |
+-----+----------+---------+---------------+---------------------+
16 rows in set (0.000 sec)
If this can not be done is a single INSERT then I can use an INSERT with subsequent UPDATE statements. I also understand that this is not best practice and violates 3nf and probably several other best practice principles. Unfortunately, I am at the mercy of the application and can not change the code, so the only way to get this to work is to put duplicate data in the database as described below:
It can be done with a single INSERT. However, there are some information need to be addressed as what I've posted in a the comment. In the meantime, here is an example query that you can use to do the operation that you want:
SELECT ROW_NUMBER() OVER (ORDER BY A.group_id, A.user_id) AS 'jot_grpmemid',
A.group_id AS 'jot_grpid',
MAX(CASE WHEN B.field_id=3 THEN B.value ELSE '' END) AS 'jot_grpmemname',
MAX(CASE WHEN B.field_id=4 THEN CONCAT('+',B.value) ELSE '' END) AS 'jot_grpmemnum',
A.user_id AS 'jot_bbmemid'
FROM
dbc_bp_groups_members A JOIN dbc_bp_xprofile_data B
ON A.user_id=B.user_id
GROUP BY A.group_id, A.user_id;
Like I said in the comment, I'm not sure how you get/generate jot_grpmemid because you have two 7 in the expected result so I assume it's a typo. I guess, at this point it's up to you to modify the query accordingly.
Demo fiddle

MySQL get running difference for unique titles with date

I have some data in MySQL table. Its primary key is domain name and tstamp (date). This table is updated just once a week. Now I want to get a difference of one domain in consecutive weeks on UrduCount column.
Following is the table sample data (for just three weeks but will grow in future)
mysql> select * from domainStats order by domain_name limit 10;
+-----------------------+------------+---------+------------+------------+-----------+------------+------+
| domain_name | TotalLinks | Succeed | NotSucceed | NotFetched | UrduCount | tstamp | src |
+-----------------------+------------+---------+------------+------------+-----------+------------+------+
| 107.170.52.240 | 59574 | 30226 | 1688 | 27660 | 60000 | 2019-10-04 | use2 |
| 107.170.52.240 | 59027 | 30315 | 1689 | 27023 | 40000 | 2019-09-27 | use2 |
| 107.170.52.240 | 59027 | 30315 | 1689 | 27023 | 10000 | 2019-09-20 | use2 |
| www.dunyapakistan.com | 66542 | 20608 | 4844 | 41090 | 30000 | 2019-10-04 | use2 |
| www.dunyapakistan.com | 66542 | 20608 | 4844 | 41090 | 30000 | 2019-09-27 | use2 |
| www.dunyapakistan.com | 65380 | 20192 | 5293 | 39895 | 20000 | 2019-09-20 | use2 |
| www.urdupoint.com | 129751 | 20746 | 494 | 108511 | 50000 | 2019-10-04 | use2 |
| www.urdupoint.com | 129751 | 20746 | 494 | 108511 | 50000 | 2019-09-27 | use2 |
| www.urdupoint.com | 126879 | 20779 | 455 | 105645 | 10000 | 2019-09-20 | use2 |
+-----------------------+------------+---------+------------+------------+-----------+------------+------+
Expected out similar to following (consecutive difference of same domains in consecutive weeks)
www.urdupoint.com | 2019-10-04 | 20000
www.urdupoint.com | 2019-09-27 | 30000
www.urdupoint.com | 2019-09-20 | 10000
...
In MySQL 5.x you can use a correlated sub-query:
SELECT domain_name, tstamp, UrduCount - COALESCE((
SELECT UrduCount
FROM t AS x
WHERE x.domain_name = t.domain_name
AND x.tstamp < t.tstamp
ORDER BY x.tstamp DESC
LIMIT 1
), 0) AS diff
FROM t
In MySQL 8 or later you could simply use the LAG function.

MySQL Simple query took to long to return result

My simple query took too long to return result.
Here is my query:
select count(*) from f_logs as a
where a.id = (
select max(id)
from f_logs
where f_id = a.f_id
group by f_id
) and log_status = 'In storage';
This is my sample data from my table:
+----+-------+------------+------------+-----------------+-------------+----------------+-------------+
| id | f_id | log_date | log_action | log_destination | log_remarks | log_status | log_account |
+----+-------+------------+------------+-----------------+-------------+----------------+-------------+
| 1 | 1-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 2 | 2-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 3 | 3-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 4 | 4-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 5 | 5-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 6 | 1-EC | 2017-05-03 | Released | Treasury | | Not in Storage | Person A |
| 7 | 7-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 8 | 8-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 9 | 2-EC | 2017-05-03 | Released | Registrar | | Not in Storage | Person A |
| 10 | 10-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 11 | 11-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 12 | 12-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 13 | 3-EC | 2017-05-03 | Released | Registrar | | Not in Storage | Person B |
| 14 | 14-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 15 | 15-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 16 | 16-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 17 | 17-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 18 | 18-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 19 | 19-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
| 20 | 1-EC | 2017-05-03 | Receive | Records Unit | | In storage | Records |
+----+-------+------------+------------+-----------------+-------------+----------------+-------------+
Using explain returns the following:
+----+--------------------+--------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+--------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------+
| 1 | PRIMARY | a | NULL | ALL | NULL | NULL | NULL | NULL | 46439 | 10.00 | Using where |
| 2 | DEPENDENT SUBQUERY | f_logs | NULL | ALL | NULL | NULL | NULL | NULL | 46439 | 10.00 | Using where; Using temporary; Using filesort |
+----+--------------------+--------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------+
2 rows in set, 2 warnings (0.00 sec)
Note (Code 1276): Field or reference 'gsis_new.a.f_id' of SELECT #2 was resolved in SELECT #1
Note (Code 1003):
/* select#1 */
select count(0) AS count(*)
from gsis_new.f_logs a
where ((gsis_new.a.id = (
/* select#2 */
select max(gsis_new.f_logs.id)
from gsis_new.f_logs
where (gsis_new.f_logs.f_id = gsis_new.a.f_id)
group by gsis_new.f_logs.f_id)
) and (gsis_new.a.log_status = 'In storage'))
Here is what i want to happen:
I have a table named f_logs, it is used for logging of files.
I want to return the total count of records in the table.
From my sample table data. It should return '14' since 2-EC and 3-EC is marked as not in storage from row 9 and 13.
While 1-EC is already mark as In storage again in row 20.
Note: My mySql query is working fine when the table is not populated.
Is there any chance to optimize my query?
Additional Information:
Here is the index of my f_logs table
+--------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| f_logs | 0 | PRIMARY | 1 | id | A | 46439 | NULL | NULL | | BTREE | | |
| f_logs | 1 | acountIndex | 1 | log_account | A | 1 | NULL | NULL | YES | BTREE | | |
+--------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
Your explain shows there might be no indices on the table.
ALTER TABLE f_logs ADD INDEX (id), ADD INDEX (f_id);

Inconsistency between MariaDB and MySQL

I've found a different behaviour in how a query is interpreted between these 2 databases and wondered if anyone could shed any light on what is happening here. The query looks like this:
SELECT t1.id, t2.album_id
FROM t1
LEFT OUTER JOIN t2
ON t1.data_id = t2.id
AND t1.event_type IN (1002, 1001, 1000)
WHERE
t1.event_type IN (1000, 1001, 1002, 1200, 1201, 1202, 1203)
GROUP BY t1.id
ORDER BY t1.id DESC
LIMIT 0, 20;
The MariaDB result looks like this:
+-----+----------+
| id | album_id |
+-----+----------+
| 623 | NULL |
| 622 | NULL |
| 621 | NULL |
| 620 | NULL |
| 619 | NULL |
| 618 | NULL |
| 617 | NULL |
| 616 | NULL |
| 615 | NULL |
| 614 | NULL |
| 613 | NULL |
| 612 | 194 |
| 611 | NULL |
| 610 | NULL |
| 609 | NULL |
| 608 | 193 |
| 607 | NULL |
| 606 | NULL |
| 605 | NULL |
| 604 | NULL |
+-----+----------+
And the Oracle MySQL result looks like this:
+-----+----------+
| id | album_id |
+-----+----------+
| 623 | NULL |
| 622 | NULL |
| 621 | NULL |
| 620 | NULL |
| 619 | NULL |
| 618 | NULL |
| 617 | NULL |
| 616 | 196 |<-- different
| 615 | NULL |
| 614 | NULL |
| 613 | NULL |
| 612 | 194 |
| 611 | 194 |<-- different
| 610 | NULL |
| 609 | NULL |
| 608 | 193 |
| 607 | 193 |<-- different
| 606 | NULL |
| 605 | NULL |
| 604 | NULL |
+-----+----------+
Additionally, when I EXPLAIN the queries, I can see that the two databases are interpreting the query differently. (See the "Extra" column)
MariaDB
+------+-------------+-------+--------+---------------+---------+---------+------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+---------------+---------+---------+------------------------+------+-------------+
| 1 | SIMPLE | t1 | index | NULL | PRIMARY | 4 | NULL | 20 | Using where |
| 1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | foo.t1.data_id | 1 | Using where |
+------+-------------+-------+--------+---------------+---------+---------+------------------------+------+-------------+
Oracle MySQL
+----+-------------+-------+--------+---------------+---------+---------+---------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------------+------+-------------+
| 1 | SIMPLE | t1 | index | NULL | PRIMARY | 4 | NULL | 20 | Using where |
| 1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | foo.t1.data_id | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+---------------------------+------+-------------+
I have found workarounds for this but would really like to know what is going on here. Does anyone have any ideas?
If you want to try it yourself, a dump of the data I used in this example can be found here.
Thanks.
edit: It have been pointed out in the comments that the query is invalid SQL in most databases but that MySQL allows it - but that the database is free to return any aggregated value from the GROUP BY. I'd just like to point out that what appears to be happening here is different, because the values are not ambiguous. There is only a single matching row, but that does not correspond to the value that MariaDB is returning.
SELECT t1.id, t2.album_id
FROM t1
JOIN t2
ON t1.data_id = t2.id
WHERE
t1.id = 616
;
+-----+----------+
| id | album_id |
+-----+----------+
| 616 | 196 |
+-----+----------+
1 row in set (0.00 sec)
It turns out this is actually a bug in MariaDB which can produce the wrong results when using group by and a left join on 2 conditions.
This query is using a so caled MySql extension to GROUP BY
See this link for details: http://dev.mysql.com/doc/refman/5.7/en/group-by-extensions.html
They clearly said that:
MySQL extends the use of GROUP BY so that the select list can refer to
nonaggregated columns not named in the GROUP BY clause. This means
that the preceding query is legal in MySQL. You can use this feature
to get better performance by avoiding unnecessary column sorting and
grouping. However, this is useful primarily when all values in each
nonaggregated column not named in the GROUP BY are the same for each
group. The server is free to choose any value from each group, so
unless they are the same, the values chosen are indeterminate.
Taking the above into account, this behaviour is with accordance with specification.

Slow query with where like, order by and limit

I'm having an issue with the speed of a query I wan't to do.
The rooms table has 2685588 rows, and the room_active has less than 100, but it isn't slow with normal queries.
The query is:
SELECT rooms.*, room_active.active_users
FROM rooms LEFT JOIN room_active ON (room_active.roomid = rooms.id)
WHERE caption LIKE '%room%' ORDER BY room_active.active_users LIMIT 50
Runtime: 4.3s
It takes more than 5 seconds to execute when it should take less than one like does this one:
SELECT rooms.*, room_active.active_users
FROM rooms LEFT JOIN room_active ON (room_active.roomid = rooms.id)
WHERE caption LIKE '%room%' LIMIT 50
Runtime: 0.3s
The describe for the first query is this:
+----+-------------+-------------+--------+----------------+---------+---------+----------------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+--------+----------------+---------+---------+----------------+---------+----------------------------------------------+
| 1 | SIMPLE | rooms | ALL | NULL | NULL | NULL | NULL | 2210576 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | room_active | eq_ref | PRIMARY,roomid | PRIMARY | 4 | xukys.rooms.id | 1 | NULL |
+----+-------------+-------------+--------+----------------+---------+---------+----------------+---------+----------------------------------------------+
Indexes:
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rooms | 0 | PRIMARY | 1 | id | A | 2210613 | NULL | NULL | | BTREE | | |
| rooms | 1 | owner | 1 | owner | A | 2210613 | NULL | NULL | | BTREE | | |
| rooms | 1 | roomtype | 1 | roomtype | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | caption | 1 | caption | A | 2210613 | NULL | NULL | | BTREE | | |
| rooms | 1 | category | 1 | category | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | users_now | 1 | users_now | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | tags | 1 | tags | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | users_max | 1 | users_max | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | description | 1 | description | A | 368435 | NULL | NULL | | BTREE | | |
| rooms | 1 | state | 1 | state | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | model_name | 1 | model_name | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | public_ccts | 1 | public_ccts | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | score | 1 | score | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | password | 1 | password | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | icon_bg | 1 | icon_bg | A | 954 | NULL | NULL | | BTREE | | |
| rooms | 1 | icon_fg | 1 | icon_fg | A | 18 | NULL | NULL | | BTREE | | |
| rooms | 1 | badge_id | 1 | badge_id | A | 804 | NULL | NULL | | BTREE | | |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
+-------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| room_active | 0 | PRIMARY | 1 | roomid | A | 116 | NULL | NULL | | BTREE | | |
| room_active | 0 | roomid | 1 | roomid | A | 116 | NULL | NULL | | BTREE | | |
| room_active | 1 | active_users | 1 | active_users | A | 29 | NULL | NULL | | BTREE | | |
+-------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
The ORDER BY is removing the advantage of LIMIT 50 because to be able to order by the 50 first elements he has to fetch all the records.
maybe if you tell us what exactly you want, we can help with the query. For example do you really need to do a LEFT JOIN and get all the rooms who don't have a room_active ?
not sure if it helps, but try this one
SELECT rooms.*, room_active.active_users
FROM room_active ra JOIN rooms r ON (room_active.roomid = rooms.id)
WHERE r.caption LIKE '%room%' ORDER BY ra.active_users LIMIT 50
It will ignore the rooms that don't have a room_active, reducing the fetched records
Follow following steps and check performance.
Create index on field 'caption' for its first 4 characters and on 'active_users'.
Instead of "rooms.*", select fields explicitly.
Use "caption LIKE 'room%'" instead of "caption LIKE '%room%'".
If this still slow, you should create a view for your joined query and then perform simple select statement on your view.
1 you might want a index perhaps on the order?
2 You don't need %room% do you? room% would be faster, your effectivly searching all files if you don't
3 don't left join if you can and only want active? instead inner join because it will require less joins (it doesnt join the ones that are null)
4 dont select .* unless needed?
5. Maybe you can use a differnt function such as Contains if you are using oracle
6. Put a index on caption its being mass searched thats probably the problem