簡體   English   中英

具有連接,限制和順序的MySQL查詢非常慢(filesort)

[英]Mysql query with join, limit and order is very slow (filesort)

我有以下查詢:

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 |                             | 
+----+-------------+-------+------+------------------------+--------+---------+------------------------------+-------+-----------------------------+

已知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,在這種特定情況下,我認為它可能會起作用,因為它可以使用user_name索引進行排序。

您還有其他選擇:

  • 增加sort_buffer_size的大小
  • 增加read_rnd_buffer_size的大小(請謹慎!)
  • 不管他有多少dls ,僅在users表上進行分頁,僅應用JOIN
  • 處理代碼中的分頁。 假設用戶從一個頁面跳到另一個頁面,則應該存儲每個頁面的第一個和最后一個用戶名。 如果用戶單擊下一頁-添加WHERE user_name > "{LastPageLastUsername} LIMIT 0,16"用戶名WHERE user_name > "{LastPageLastUsername} LIMIT 0,16"則會增加

對於其他優化,請閱讀ORDER BY優化極限優化

嘗試使用以下幾列向用戶表添加索引

status, acc, user_name

要么

acc, status, user_name

哪個更快

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM