使用临时的 MYSQL 优化;使用文件排序!!! -> 帮助

Posted

技术标签:

【中文标题】使用临时的 MYSQL 优化;使用文件排序!!! -> 帮助【英文标题】:MYSQL optimization for Using temporary; Using filesort!!! -> HELP 【发布时间】:2011-01-20 13:56:33 【问题描述】:

伙计们,我正在尝试一段时间,但我无法优化 Using 临时;使用我的 EXPLAIN 查询中的文件排序。 好的,我有这个查询:

 SELECT a.adid, a.adtitle, a.addesc, scat.subcatname
FROM ads a
INNER JOIN cities ct ON a.cityid = ct.cityid
INNER JOIN subcats scat ON a.subcatid = scat.subcatid
INNER JOIN cats cat ON scat.catid = cat.catid
WHERE a.enabled = '1'
AND a.verified ='1'
GROUP BY a.adid
ORDER BY a.createdon DESC
LIMIT 16;

当我解释时......我明白了:

    EXPLAIN SELECT a.adid, a.adtitle, a.addesc, scat.subcatname 
FROM ads a 
INNER JOIN cities ct ON a.cityid = ct.cityid 
INNER JOIN subcats scat ON a.subcatid = scat.subcatid 
INNER JOIN cats cat ON scat.catid = cat.catid 
WHERE a.enabled = '1' 
AND a.verified ='1' 
GROUP BY a.adid 
ORDER BY a.createdon DESC LIMIT 16;

+----+-------------+-------+--------+----------------------------------+----------+---------+--------------------------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys                    | key      | key_len | ref                            | rows | Extra                           |
+----+-------------+-------+--------+----------------------------------+----------+---------+--------------------------------+------+---------------------------------+
|  1 | SIMPLE      | cat   | system | PRIMARY                          | NULL     | NULL    | NULL                           |    1 | Using temporary; Using filesort | 
|  1 | SIMPLE      | scat  | ref    | PRIMARY,catid                    | catid    | 2       | const                          |    7 |                                 | 
|  1 | SIMPLE      | a     | ref    | subcatid,cityid,verified,enabled | subcatid | 2       | bakecai_incontri.scat.subcatid |  954 | Using where                     | 
|  1 | SIMPLE      | ct    | eq_ref | PRIMARY                          | PRIMARY  | 2       | bakecai_incontri.a.cityid      |    1 | Using index                     | 
+----+-------------+-------+--------+----------------------------------+----------+---------+--------------------------------+------+---------------------------------+
4 rows in set (0.00 sec)

我尝试了一些KEY,但没有结果:例如我为createdon和adid创建了一个索引,但mysql不会使用它。

这是我桌子的钥匙:

SHOW INDEX FROM ads;

+-------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
|Table| Non_unique | Key_name           | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| ads |          0 | PRIMARY            |            1 | adid        | A         |        8592 |     NULL | NULL   |      | BTREE      |         | 
| ads |          1 | subcatid           |            1 | subcatid    | A         |           9 |     NULL | NULL   |      | BTREE      |         | 
| ads |          1 | cityid             |            1 | cityid      | A         |         103 |     NULL | NULL   |      | BTREE      |         | 
| ads |          1 | verified           |            1 | verified    | A         |           2 |     NULL | NULL   | YES  | BTREE      |         | 
| ads |          1 | enabled            |            1 | enabled     | A         |           2 |     NULL | NULL   | YES  | BTREE      |         | 
| ads |          1 | idx_createdon_adid |            1 | createdon   | A         |        8592 |     NULL | NULL   |      | BTREE      |         | 
| ads |          1 | idx_createdon_adid |            2 | adid        | A         |        8592 |     NULL | NULL   |      | BTREE      |         | 
| ads |          1 | srch_text          |            1 | adtitle     | NULL      |           1 |     NULL | NULL   | YES  | FULLTEXT   |         | 
| ads |          1 | srch_text          |            2 | addesc      | NULL      |           1 |     NULL | NULL   | YES  | FULLTEXT   |         | 
| ads |          1 | srch_text          |            3 | nome        | NULL      |           1 |     NULL | NULL   | YES  | FULLTEXT   |         | 
+-------------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
10 rows in set (0.00 sec)

这里是对表格的一些简要说明:

 DESCRIBE ads
    -> ;
+-----------+----------------------+------+-----+---------------------+----------------+
| Field     | Type                 | Null | Key | Default             | Extra          |
+-----------+----------------------+------+-----+---------------------+----------------+
| adid      | int(10) unsigned     | NO   | PRI | NULL                | auto_increment | 
| nome      | varchar(255)         | YES  |     | NULL                |                | 
| eta       | varchar(255)         | YES  |     | NULL                |                | 
| adtitle   | varchar(100)         | YES  | MUL | NULL                |                | 
| addesc    | text                 | YES  |     | NULL                |                | 
| email     | varchar(50)          | YES  |     | NULL                |                | 
| phone     | varchar(255)         | YES  |     | NULL                |                | 
| showemail | enum('0','1','2')    | YES  |     | NULL                |                | 
| code      | varchar(35)          | YES  |     | NULL                |                | 
| first     | varchar(255)         | YES  |     | NULL                |                | 
| cityid    | smallint(5) unsigned | NO   | MUL | 0                   |                | 
| subcatid  | smallint(5) unsigned | NO   | MUL | 0                   |                | 
| price     | decimal(10,2)        | NO   |     | 0.00                |                | 
| hits      | int(10) unsigned     | NO   |     | 0                   |                | 
| ip        | varchar(15)          | YES  |     | NULL                |                | 
| link      | varchar(255)         | YES  |     | http://             |                | 
| verified  | enum('0','1')        | YES  | MUL | NULL                |                | 
| abused    | int(10) unsigned     | NO   |     | 0                   |                | 
| enabled   | enum('0','1')        | YES  | MUL | NULL                |                | 
| createdon | datetime             | NO   | MUL | 0000-00-00 00:00:00 |                | 
| expireson | datetime             | NO   |     | 0000-00-00 00:00:00 |                | 
| timestamp | timestamp            | NO   |     | CURRENT_TIMESTAMP   |                | 
+-----------+----------------------+------+-----+---------------------+----------------+
22 rows in set (0.02 sec)

DESCRIBE cities
    -> ;
+-----------+----------------------+------+-----+-------------------+----------------+
| Field     | Type                 | Null | Key | Default           | Extra          |
+-----------+----------------------+------+-----+-------------------+----------------+
| cityid    | smallint(5) unsigned | NO   | PRI | NULL              | auto_increment | 
| cityname  | varchar(50)          | YES  |     | NULL              |                | 
| regionid  | smallint(5) unsigned | NO   | MUL | 0                 |                | 
| pos       | smallint(5) unsigned | NO   | MUL | 0                 |                | 
| enabled   | enum('0','1')        | YES  | MUL | NULL              |                | 
| timestamp | timestamp            | NO   |     | CURRENT_TIMESTAMP |                | 
+-----------+----------------------+------+-----+-------------------+----------------+
6 rows in set (0.00 sec)

DESCRIBE cats
    -> ;
+-----------+----------------------+------+-----+-------------------+----------------+
| Field     | Type                 | Null | Key | Default           | Extra          |
+-----------+----------------------+------+-----+-------------------+----------------+
| catid     | smallint(5) unsigned | NO   | PRI | NULL              | auto_increment | 
| catname   | varchar(50)          | YES  |     | NULL              |                | 
| pos       | smallint(5) unsigned | NO   |     | 0                 |                | 
| enabled   | enum('0','1')        | YES  | MUL | NULL              |                | 
| timestamp | timestamp            | NO   |     | CURRENT_TIMESTAMP |                | 
+-----------+----------------------+------+-----+-------------------+----------------+
5 rows in set (0.00 sec)

任何帮助,我很感激!

【问题讨论】:

【参考方案1】:
SELECT  a.adid, a.adtitle, a.addesc, scat.subcatname
FROM    ads a
INNER JOIN
        subcats scat
ON      a.subcatid = scat.subcatid
WHERE   a.enabled = '1'
        AND a.verified ='1'
ORDER BY a.createdon
        DESC
LIMIT 16

删除了不需要的连接并摆脱了不需要的GROUP BY

要摆脱filesort,请创建以下索引:

CREATE INDEX ix_ads_e_v_created ON ads (enabled, verified, createdon)

【讨论】:

好的,改进了,但是...我还有一个小问题,现在查询正在扫描所有行【参考方案2】:

您需要使用强制索引 - here you will find more information。但是,在您的情况下,它不会有太大帮助,因为您对连接和组使用不同的索引,因此 mysql 没有机会“重用”它们。

【讨论】:

【参考方案3】:

好的,它有所改进,但现在查询正在扫描所有行: --hmm 我认为这是因为所有行都已启用并验证等于 1...

EXPLAIN SELECT a.adid, a.adtitle, a.addesc, scat.subcatname
    -> FROM ads a
    -> INNER JOIN subcats scat 
    -> ON a.subcatid = scat.subcatid
    -> WHERE a.enabled = '1'
    -> AND a.verified ='1'
    -> ORDER BY a.createdon DESC
    -> LIMIT 16;
+----+-------------+-------+--------+----------------------------------------------+--------------------+---------+-----------------------------+------+-------------+
| id | select_type | table | type   | possible_keys                                | key                | key_len | ref                         | rows | Extra       |
+----+-------------+-------+--------+----------------------------------------------+--------------------+---------+-----------------------------+------+-------------+
|  1 | SIMPLE      | a     | ref    | subcatid,verified,enabled,ix_ads_e_v_created | ix_ads_e_v_created | 4       | const,const                 | 8485 | Using where | 
|  1 | SIMPLE      | scat  | eq_ref | PRIMARY                                      | PRIMARY            | 2       | bakecai_incontri.a.subcatid |    1 |             | 
+----+-------------+-------+--------+----------------------------------------------+--------------------+---------+-----------------------------+------+-------------+
2 rows in set (0.00 sec)

据我所知,我必须建立一个索引,对吗?但是在哪一列/列上?

【讨论】:

该查询没有扫描所有行:它使用具有ref 访问权限的索引并按索引顺序输出记录,而没有filesort。另外,请更新您的原始问题,不要发布更新作为答案。谢谢。【参考方案4】:

只是为了笑……改成

SELECT STRAIGHT_JOIN(查询的其余部分)

通过使子类别表变小,优化器引擎将尝试使用它作为查询的基础,而不是查询中的第一个表...这个关键字“STRAIGHT_JOIN”在过去帮助我做 gov't查询 14+ 百万条记录加入 15+ 查找表,从 30+ 小时后挂起进程到不到 2 小时完成。

【讨论】:

以上是关于使用临时的 MYSQL 优化;使用文件排序!!! -> 帮助的主要内容,如果未能解决你的问题,请参考以下文章

Mysql(20)—临时表的原理以及优化手段

Mysql查询使用索引使用文件排序使用临时

Mysql using filesort 优化

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

如何优化这个 MySQL 查询

mysql性能分析与优化