簡體   English   中英

MySQL以DESC順序比ASC順序查詢更快

[英]MySQL query faster in DESC order than ASC order

我制作了一個簡單的數據庫(innodb版本5.7.9),其中包含2個表post和post_tag。

帖子具有設置為主鍵的單個字段ID(大整數)(約120,000個條目)。 Post_tag有2個字段,post_id(大整數)和tag_id(整數),主鍵位於[post_id,tag_id]上。

以下查詢在〜1ms內運行:

SELECT 
   SQL_NO_CACHE p.id 
FROM 
   post as p 
STRAIGHT_JOIN 
   post_tag t
WHERE  
   t.post_id = p.id AND t.tag_id = 25 
ORDER BY 
   p.id DESC
LIMIT 0, 100

但是,如果我將ORDER BY更改為ASC,它的運行速度將慢100倍! 我感興趣的那種...

知道為什么嗎?

最初,我希望ID對DESC進行排序,但我發現它比ASC慢。 我讀到,索引的自然排序是ASC,所以我還原了所有ID(通過執行ID = SOMETHING BIG-ID),但是由於它現在在ASC中的速度較慢,因此它沒有任何改變。

如果有用,我在這里上傳了數據庫。

在此先感謝任何可以提供幫助的人。

這是解釋: 在此處輸入圖片說明

如果有“其他限制”,則所有下注均無效。

同時,看看你有什么...

STRAIGHT_JOINUSE INDEX等是以下情況的拐杖:(a)您沒有“正確”的索引,或者(b)優化器無法確定“正確”的事情。 也就是說,尋找其他解決方案。

在您的示例中,最好使用普通的JOININDEX(tag_id, post_id) 這將post_tag 首先進入post_tag因為有一個WHERE子句可對其進行過濾。 優化器可能會看到t.post_idp.id相同,因此在索引中以(25, post_id)的結尾(對於DESC )開始,然后進行掃描。 然后檢查,看看是否有一個post進入(這是對於唯一明顯的使用post -如果再有“其他方面的限制”,所有的賭注都關閉)。

所以,回到原來的問題。 STRAIGHT_JOIN 強制先查找post 但是25年代在哪里? 顯然接近年底 post_tag 因此,與從另一端開始掃描相比, ASC需要更長的時間才能找到其中的100個(請參閱LIMIT )!

假設這是一個多對多映射表,請執行以下操作:

CREATE TABLE post_tag (
    post_id ...,
    tag_id ...,
    PRIMARY KEY(post_id, tag_id),
    INDEX      (tag_id, post_id)
) ENGINE=InnoDB;

我在博客中討論了許多原因。

如果按照建議的方式添加(tag_id, post_id DESC) ,請不要(tag_id, post_id DESC)以為DESC意味着什么-它可以識別,但可以忽略。 這兩部分都將存儲為ASC 將會發生的事情是,優化器足夠聰明,可以在25秒結束時開始並向后掃描。 這里是“證明”:

US INDEX(state, population)

mysql> FLUSH STATUS;
mysql> SELECT city, population FROM US
          WHERE state = 'OH'
          ORDER BY population DESC LIMIT 5;
+------------+------------+
| city       | population |
+------------+------------+
| Columbus   |     736836 |
| Cleveland  |     449514 |
| Toledo     |     306974 |
| Cincinnati |     306382 |
| Akron      |     208414 |
+------------+------------+
mysql> SHOW SESSION STATUS LIKE 'Handler%';
| Handler_read_key           | 1     |  -- get started at end of Ohio
| Handler_read_prev          | 4     |  -- read (5-1) more, scanning backwards

MySQL通過忽略INDEX聲明中的DESC來丟失船只的唯一情況是: ORDER BY a ASC, b DESC無法使用INDEX(a,b)

大概您在post(id)上有一個索引(例如,它是為主鍵自動創建的)。 當對ORDER BY使用索引時,MySQL有時會注意索引的順序。

通過更改順序,您將以需要排序的方式更改查詢計划。

我建議僅使用一個表來編寫查詢:

SELECT t.post_id 
FROM post_tag t
WHERE t.tag_id = 25 
ORDER BY t.post_id DESC
LIMIT 0, 100;

假定post_id所有值都引用有效的帖子(這似乎是一個非常合理的假設),則此查詢不需要JOIN

對於此查詢, post_tag(tag_id, post_id desc)上的索引是最佳的,MySQL對於降序排序可能會做正確的事情。

暫無
暫無

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

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