簡體   English   中英

MySQL:相同的查詢,相同的結果行數,無連接,慢10倍?

[英]Mysql: same query, same number of resulting rows, no joins, 10x slower?

我正在包含〜3M行的innodb表上運行以下兩個查詢。 由於某種原因,第一個查詢花費不到一秒鍾的時間才能返回168,199行,而第二個查詢花費8秒並返回167,159行? 返回幾乎相同結果所需的時間增加了10倍?

SELECT count(idActivities) as amt 
FROM Activities 
WHERE Data_Type='email' 
      AND Status='sent' 
      AND (Created > '2019-07-17 00:00:00' 
           AND Created <= '2019-08-17 00:00:00');

SELECT count(idActivities) as amt 
FROM Activities 
WHERE Data_Type='email' 
      AND Status='sent' 
      AND (Created > '2019-08-17 00:00:00' 
           AND Created <= '2019-09-17 00:00:00');

如果我從第二條語句中刪除其他where子句,例如

SELECT count(idActivities) as amt 
FROM Activities 
WHERE (Created > '2019-08-17 00:00:00' 
       AND Created <= '2019-09-17 00:00:00');

查詢時間下降到半秒。 如果我在語句中添加一個額外的where子句,例如Data_Type =或Status =,它將跳回到8加秒。

我也嘗試過將日期向任一方向移動幾天,但這不會影響查詢時間。

該表在idActivities,Data_Type,Status和Created上建立索引。

該服務器運行5GB Ram,8核,並且具有innodb_buffer_pool_size = 3G,InnoDB緩沖區使用率為49%。

我在不同的服務器上嘗試了相同的查詢,結果大約在大約4秒的同一時間,這仍然很慢。

我注意到的唯一區別是,即使表實際上是相同的,Data_Type列的基數也有所不同(這是前一天的備份)。

在理解如何縮短查詢時間方面會有所幫助或幫助,我將不勝感激。 運行“ DISTINCT(Data_Type)”僅返回整個表的13行。

編輯謝謝Salman A,通過添加以下復合索引,極大地提高了兩個查詢的性能:

CREATE INDEX ix_1 ON活動(已創建,Data_Type,狀態);

我建議創建以下覆蓋索引:

 CREATE INDEX ix_1 ON t (Data_Type, Status, Created)

列的順序很重要。 高基數列通常放在最前面,但是對於此特定查詢,您需要將創建的列放在最后,因為它涉及范圍比較(前兩個需要相等比較)。

您需要在此處定義具有特定列順序的組合索引。 一般的經驗法則是:

  1. 應該為WHERE子句內並由AND子句連接的所有列賦予第一優先級,並使用=IS NULL<=>它們與常量值進行比較 因此,在您的查詢中,此后有兩列: Data_TypeStatus

  2. 可以優先考慮以下三種情況:

    • 列具有范圍條件。
    • GROUP BY子句中特定順序的列(如果存在)。
    • ORDER BY子句中特定順序的列(如果存在)

在這種情況下, Created是一個Range條件,因此我們將在最后將該列添加到索引中,因為在遇到range條件時,MySQL在該列處停止,並且不再訪問索引中的其他列。

因此,您基本上需要定義以下索引:

ALTER TABLE Activities ADD INDEX(Data_Type, Status, Created);

引用里克·詹姆斯的筆記

當您具有可以按任意順序排列的復合索引時,各個列的基數在選擇順序時都沒有關系。 整個索引的基數很重要。

當您遇到此類意外行為時,我總是通過讓服務器解釋其工作情況來檢查服務器的工作情況。

您可以在查詢開始時使用EXPLAIN關鍵字進行此操作。 我猜較慢的查詢正在掃描整個表以獲取結果集

https://dev.mysql.com/doc/refman/8.0/zh-CN/using-explain.html

順便提一下:除非您的data_type和status列具有很高的選擇性(可能不會)。 我猜他們是毫無意義的索引。 通常,在狀態狀態列占很大比例時,索引狀態列只是一個好主意。 即95%關閉“狀態”和5%“打開”,您有一個查詢要查找所有打開狀態。

暫無
暫無

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

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