Mysql – Can’t get rid of “temporary; Using filesort”

join;MySQL

I can't get rid-off "temporary; Using filesort" when ordering columns from the second table

explain SELECT * 
          FROM post 
          JOIN post_plus 
          ON post_plus.news_id = post.id 
         WHERE category regexp '[[:<:]](131|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|171|172|134|136|137|23|123)[[:>:]]' 
           AND approve=1 
           AND allow_main=1 
      ORDER BY kp_votes DESC, 
               kp_rating DESC LIMIT 30;
+----+-------------+---------------+------+--------------------------------------+------------+---------+--------------------+-------+----------------------------------------------+
| id | select_type | table         | type | possible_keys                        | key        | key_len | ref                | rows  | Extra                                        |
+----+-------------+---------------+------+--------------------------------------+------------+---------+--------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | post          | ref  | PRIMARY,allow_main,approve,approve_2 | allow_main | 1       | const              | 12273 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | post_plus     | ref  | news_id                              | news_id    | 5       | online.post.id     |     1 | NULL                                         |
+----+-------------+---------------+------+--------------------------------------+------------+---------+--------------------+-------+----------------------------------------------+

as you can see here, without the order kp_votes DESC kp_rating DESC I don't get "temporary; Using filesort"

explain SELECT *            FROM post            JOIN post_plus            ON post_plus.news_id = post.id           WHERE category regexp '[[:<:]](131|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|171|172|134|136|137|23|123)[[:>:]]'             AND approve=1             AND allow_main=1    LIMIT 30;
+----+-------------+---------------+------+--------------------------------------+------------+---------+--------------------+-------+-------------+
| id | select_type | table         | type | possible_keys                        | key        | key_len | ref                | rows  | Extra       |
+----+-------------+---------------+------+--------------------------------------+------------+---------+--------------------+-------+-------------+
|  1 | SIMPLE      | post      | ref  | PRIMARY,allow_main,approve,approve_2 | allow_main | 1       | const              | 13521 | Using where |
|  1 | SIMPLE      | post_plus | ref  | news_id,top_order                    | news_id    | 5       | online.post.id |     1 | NULL        |
+----+-------------+---------------+------+--------------------------------------+------------+---------+--------------------+-------+-------------+

SHOW INDEX FROM post_plus;

+-----------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name         | Seq_in_index | Column_name      | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| post_plus |          0 | PRIMARY          |            1 | pid              | A         |       32317 |     NULL | NULL   |      | BTREE      |         |               |
| post_plus |          1 | user_id          |            1 | user_id          | A         |          26 |     NULL | NULL   |      | BTREE      |         |               |
| post_plus |          1 | news_id          |            1 | news_id          | A         |       32317 |     NULL | NULL   | YES  | BTREE      |         |               |
| post_plus |          1 | kp_votes         |            1 | kp_votes         | A         |        4616 |     NULL | NULL   | YES  | BTREE      |         |               |
| post_plus |          1 | kp_rating        |            1 | kp_rating        | A         |        5386 |     NULL | NULL   | YES  | BTREE      |         |               |
| post_plus |          1 | kp_id            |            1 | kp_id            | A         |       16158 |     NULL | NULL   | YES  | BTREE      |         |               |
| post_plus |          1 | post_uuid        |            1 | post_uuid        | A         |       32317 |     NULL | NULL   | YES  | BTREE      |         |               |
| post_plus |          1 | blockedCountries |            1 | blockedCountries | A         |          10 |     NULL | NULL   | YES  | BTREE      |         |               |
| post_plus |          1 | kp_votes_2       |            1 | kp_votes         | A         |        5386 |     NULL | NULL   | YES  | BTREE      |         |               |
+---------------+------------+------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

describe post;

+------------------+-----------------------+------+-----+---------------------+----------------+
| Field            | Type                  | Null | Key | Default             | Extra          |
+------------------+-----------------------+------+-----+---------------------+----------------+
| id               | int(11)               | NO   | PRI | NULL                | auto_increment |
| autor            | varchar(40)           | NO   | MUL |                     |                |
| date             | datetime              | NO   | MUL | 0000-00-00 00:00:00 |                |
| full_story       | text                  | NO   | MUL | NULL                |                |
| xfields          | text                  | NO   |     | NULL                |                |
| title            | varchar(255)          | NO   | MUL |                     |                |
| descr            | varchar(200)          | NO   | MUL |                     |                |
| keywords         | text                  | NO   |     | NULL                |                |
| category         | varchar(200)          | NO   | MUL | 0                   |                |
| alt_name         | varchar(200)          | NO   | MUL |                     |                |
| comm_num         | mediumint(8) unsigned | NO   | MUL | 0                   |                |
| allow_comm       | tinyint(1)            | NO   |     | 1                   |                |
| allow_main       | tinyint(1) unsigned   | NO   | MUL | 1                   |                |
| approve          | tinyint(1)            | NO   | MUL | 0                   |                |
| fixed            | tinyint(1)            | NO   |     | 0                   |                |
| allow_br         | tinyint(1)            | NO   |     | 1                   |                |
| symbol           | varchar(3)            | NO   | MUL |                     |                |
| tags             | varchar(255)          | NO   | MUL |                     |                |
| metatitle        | varchar(255)          | NO   |     |                     |                |
| FileTempUUID     | varchar(11)           | YES  |     | NULL                |                |
| titleAlternative | varchar(255)          | YES  |     | NULL                |                |
+------------------+-----------------------+------+-----+---------------------+----------------+
21 rows in set (0.01 sec)

mysql> describe post_plus;

+------------------+--------------+------+-----+---------+----------------+
| Field            | Type         | Null | Key | Default | Extra          |
+------------------+--------------+------+-----+---------+----------------+
| pid              | int(11)      | NO   | PRI | NULL    | auto_increment |
| news_id          | int(11)      | YES  | MUL | NULL    |                |
| kp_votes         | int(11)      | YES  | MUL | NULL    |                |
| kp_rating        | decimal(5,3) | YES  | MUL | NULL    |                |
| kp_id            | varchar(100) | YES  | MUL | NULL    |                |
| pdate            | datetime     | YES  |     | NULL    |                |
| news_read        | int(11)      | NO   |     | 0       |                |
| user_id          | int(11)      | NO   | MUL | 0       |                |
| allow_rate       | tinyint(1)   | NO   |     | 1       |                |
| rating           | mediumint(8) | NO   |     | 0       |                |
| vote_num         | mediumint(8) | NO   |     | 0       |                |
| votes            | tinyint(1)   | NO   |     | 0       |                |
| editdate         | int(11)      | YES  |     | NULL    |                |
| view_edit        | tinyint(1)   | NO   |     | 0       |                |
| editor           | varchar(40)  | NO   |     |         |                |
| reason           | varchar(255) | NO   |     |         |                |
| access           | varchar(150) | NO   |     |         |                |
| cover            | text         | YES  |     | NULL    |                |
| quality          | varchar(100) | YES  |     | NULL    |                |
| post_uuid        | varchar(11)  | YES  | MUL | NULL    |                |
| encoded          | int(1)       | YES  |     | NULL    |                |
| embed_views      | int(11)      | NO   |     | 0       |                |
| blockedCountries | varchar(128) | YES  | MUL | NULL    |                |
+------------------+--------------+------+-----+---------+----------------+
25 rows in set (0.00 sec)

I also tried using STRAIGHT_JOIN

explain SELECT * FROM post STRAIGHT_JOIN post_plus ON post_plus.news_id = post.id WHERE category in(130,3,4,5,6,7,8,9,10,11,                                                                                                                                            C, post_plus.kp_rating DESC LIMIT 10;
+----+-------------+---------------+------+-----------------------------------------------+------------+---------+--------------------+-------+----------------------------------------------+
| id | select_type | table         | type | possible_keys                                 | key        | key_len | ref                | rows  | Extra                                        |
+----+-------------+---------------+------+-----------------------------------------------+------------+---------+--------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | post      | ref  | PRIMARY,category,allow_main,approve,approve_2 | allow_main | 1       | const              | 13521 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | post_plus | ref  | news_id,top_order                             | news_id    | 5       | online.post.id |     1 | NULL                                         |
+----+-------------+---------------+------+-----------------------------------------------+------------+---------+--------------------+-------+----------------------------------------------+

EDIT

I think I'm hitting the following limit:

If there is an ORDER BY clause and a different GROUP BY clause, or if
the ORDER BY or GROUP BY contains columns from tables other than the
first table in the join queue, a temporary table is created.

https://dev.mysql.com/doc/refman/5.0/en/where-optimizations.html

But what are my alternatives than?

Best Answer

It can't use two indexes on the same table, some DBMS can in some circumstances but I'm pretty sure mySQL never does (and I don't think any could in this case).

It is using the index on news_id to perform the join so can't use indexes on kp_votes and kp_rating to perform the ORDER BY and the LIMIT.

An index covering news_id, kp_votes DESC, kp_rating DESC may help it, though mySQL currently ignors the DESC hint on indexes (see https://stackoverflow.com/questions/10109108/how-do-i-create-a-desc-index-in-mysql) so maybe not, so test and see.