带连接,限制和顺序的Mysql查询非常慢(filesort)

时间:2011-02-16 01:54:34

标签: mysql

我有以下查询:

explain select * from users, dls where dls.user_id=users.id and users.status = 'accepted' and users.acc = 0 order by users.user_name desc limit 18416, 16

导致以下解释;

+----+-------------+-------+------+------------------------+-------------+---------+---------------------------------+-------+---------------------------------+
| id | select_type | table | type | possible_keys          | key         | key_len | ref                             | rows  | Extra                           |
+----+-------------+-------+------+------------------------+-------------+---------+---------------------------------+-------+---------------------------------+
|  1 | SIMPLE      | dls   | ALL  | PRIMARY,user_id         | NULL        | NULL    | NULL                            | 19910 | Using temporary; Using filesort | 
|  1 | SIMPLE      | users  | ref  | PRIMARY,id_user_name | id_user_name | 4       | dls.user_id |     1 | Using where                     | 
+----+-------------+-------+------+------------------------+-------------+---------+---------------------------------+-------+---------------------------------+
2 rows in set (0.00 sec)

这个查询非常非常慢,我无法弄清楚如何修复它。我尝试了各种索引,阅读有关如何通过/限制查询优化顺序的文章,但结果保持不变。有人可以帮忙吗?

编辑:架构:

CREATE TABLE `users` (

  `id` int(10) unsigned NOT NULL auto_increment,
  `user_name` varchar(100) character set utf8 NOT NULL,
`status` enum('accepted','rejected') character set utf8 NOT NULL,
`acc` varchar(6) character set utf8 NOT NULL,
 PRIMARY KEY  (`id`),
  KEY `user_name` (`user_name`),
 KEY `id_user_name` (`id`,`user_name`)
)

CREATE TABLE `dls` (
 `user_id` int(10) unsigned NOT NULL,
 `category_id` bigint(20) NOT NULL,

`download_url` varchar(255) character set utf8 NOT NULL,
  PRIMARY KEY  (`user_id`,`category_id`),
  KEY `user_id` (`user_id`)
)

Scrummeister的查询输出;

+----+-------------+-------+------+------------------------+--------+---------+------------------------------+-------+-----------------------------+
| id | select_type | table | type | possible_keys          | key    | key_len | ref                          | rows  | Extra                       |
+----+-------------+-------+------+------------------------+--------+---------+------------------------------+-------+-----------------------------+
|  1 | SIMPLE      | u  | ALL  | PRIMARY,id_user_name | NULL   | NULL    | NULL                         | 10838 | Using where; Using filesort | 
|  1 | SIMPLE      | dls   | ref  | PRIMARY,user_id         | user_id | 4       | u.id |     2 |                             | 
+----+-------------+-------+------+------------------------+--------+---------+------------------------------+-------+-----------------------------+

2 个答案:

答案 0 :(得分:3)

已知MySql使用大偏移量LIMIT存在问题。

STRAIGHT_JOIN关键字告诉MySql首先扫描users表,然后为每个用户查找dls表中的行。

SELECT STRAIGHT_JOIN *
FROM users u JOIN dls ON dls.user_id = users.id
WHERE u.status = 'accepted' and u.acc = 0
ORDER BY users.user_name desc 
LIMIT 18416, 16

除非需要使用STRAIGHT_JOIN,否则不建议使用STRAIGHT_JOIN。在这种特定情况下,我认为它可能有效,因为它可以使用user_name索引进行排序。

您有其他选择:

  • 增加sort_buffer_size
  • 的尺寸
  • 增加read_rnd_buffer_size的尺寸(小心!)
  • 仅在users表格上进行分页,无论他有多少dls,只应用JOIN
  • 处理代码中的分页。假设一个用户从一个页面跳到另一个页面,跳过很多,你应该存储第一个&每个页面的最后一个用户名。如果用户点击下一页 - 添加WHERE user_name > "{LastPageLastUsername} LIMIT 0,16",则会增加

要进行其他优化,请阅读ORDER BY OptimizationLimit Optimization

答案 1 :(得分:0)

尝试使用以下列

向users表添加索引
status, acc, user_name

acc, status, user_name

哪个更快