MySQL:无法在简单查询中摆脱“使用文件排序”

lpa*_*lpa 5 mysql performance query-performance

简单查询但无法摆脱“using filesort”:

CREATE TABLE IF NOT EXISTS `online` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,
  `expiration` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `uid` (`uid`),
  KEY `expiration` (`expiration`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1925234 ;

mysql> explain SELECT i.id, i.uid, i.expiration, u.nick, u.mainpicture
    -> FROM online i join usertable u on i.uid = u.id
    -> order by i.expiration DESC limit 0,12;

+----+-------------+-------+--------+---------------+---------+---------+----------------+------+----------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref            | rows | Extra          |
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+----------------+
|  1 | SIMPLE      | i     | ALL    | uid           | NULL    | NULL    | NULL           | 1020 | Using filesort |
|  1 | SIMPLE      | u     | eq_ref | PRIMARY       | PRIMARY | 4       | dbasen01.i.uid |    1 |                |
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+----------------+
2 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

"usertable"列上有索引"id"。尝试按"i.id"(主键)排序,但相同 - 查询仍然使用文件排序。

RolandoMySQLDBA 回答后更新:

+----+-------------+-----------------+--------+---------------+---------+---------+-------+------+----------------+
| id | select_type | table           | type   | possible_keys | key     | key_len | ref   | rows | Extra          |
+----+-------------+-----------------+--------+---------------+---------+---------+-------+------+----------------+
|  1 | PRIMARY     | <derived2>      | ALL    | NULL          | NULL    | NULL    | NULL  |   12 |                |
|  1 | PRIMARY     | u               | eq_ref | PRIMARY       | PRIMARY | 4       | i.uid |    1 |                |
|  2 | DERIVED     | online          | ALL    | NULL          | NULL    | NULL    | NULL  | 1009 | Using filesort |
+----+-------------+-----------------+--------+---------------+---------+---------+-------+------+----------------+
Run Code Online (Sandbox Code Playgroud)

解决方案:

我删除了“id”列,因为它没有被使用。然后修改索引:

ALTER TABLE online ADD INDEX expiration (expiration,uid);
Run Code Online (Sandbox Code Playgroud)

结果:

+----+-------------+-------+--------+---------------+------------+---------+----------------+------+-------------+
| id | select_type | table | type   | possible_keys | key        | key_len | ref            | rows | Extra       |
+----+-------------+-------+--------+---------------+------------+---------+----------------+------+-------------+
|  1 | SIMPLE      | i     | index  | uid           | expiration | 8       | NULL           |   12 | Using index |
|  1 | SIMPLE      | u     | eq_ref | PRIMARY       | PRIMARY    | 4       | dbasen01.i.uid |    1 |             |
+----+-------------+-------+--------+---------------+------------+---------+----------------+------+-------------+
Run Code Online (Sandbox Code Playgroud)

谢谢大家。

小智 2

我没有时间去检查;但是,只要查看查询,我预计文件排序是由 ORDER BY/LIMIT 触发的。当仍然需要执行 O(n) 数据文件查找,然后进行外部排序以在执行 12 之前提取前 12 个数据时,对 uid 索引执行顺序 O(n) 传递并没有多大用处) eq_ref 连接到 usertable 的 id 索引,然后探测 usertable 的数据文件以提取 select 所需的字段。

我希望 Mysql 认为(正确地)最好对数据文件执行一次顺序 O(n) 传递,然后进行外部排序、eq_ref 连接和探测。

您需要的是预先为 mysql 执行外部排序,因此它不必自己执行。这意味着您需要一个覆盖连接/where 条件的索引。

IE。

ALTER TABLE online ADD INDEX expiration (expiration,uid,id);
Run Code Online (Sandbox Code Playgroud)

话又说回来,鉴于在线只有 1020 行,你为什么现在担心这个呢?