我有以下查询:
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
Run Code Online (Sandbox Code Playgroud)
这导致以下解释;
+----+-------------+-------+------+------------------------+-------------+---------+---------------------------------+-------+---------------------------------+
| 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)
Run Code Online (Sandbox Code Playgroud)
这个查询真的非常慢,我不知道如何解决它。我从阅读有关如何优化 order by / limit 查询的文章中尝试了各种索引,但结果仍然相同。有人可以帮忙吗?
编辑:架构:
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`)
)
Run Code Online (Sandbox Code Playgroud)
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 | |
+----+-------------+-------+------+------------------------+--------+---------+------------------------------+-------+-----------------------------+
Run Code Online (Sandbox Code Playgroud)
众所周知,MySql 存在LIMIT使用大偏移量的问题。
该STRAIGHT_JOIN关键字,告诉MySQL首先扫描用户表,然后为每一位用户,查找行的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
Run Code Online (Sandbox Code Playgroud)
除非需要,否则不建议使用 STRAIGHT_JOIN,在这种特定情况下,我相信它可能会起作用,因为它可以使用user_name索引进行排序。
您还有其他选择:
sort_buffer_sizeread_rnd_buffer_size(小心!)users只在表上做分页,不管dls他有多少,只比应用JOIN.WHERE user_name > "{LastPageLastUsername} LIMIT 0,16"这将增加对于其他优化,请阅读ORDER BY 优化和限制优化