2016-10-26 86 views
0

我有一個SQL查詢需要大量時間來評估,因爲它在一個非常大的數據集上運行。當試圖提高執行時間,我發現了以下工作:訂購空集時,SQL查詢變得非常慢

當執行下面的查詢MySQL服務器需要花費很多的時間(最多100secs)

SELECT some_data 
FROM table 
     INNER JOIN anothertable 
       ON (table.value = 
           anothertable.value) 
WHERE (table.parent = 56521 
     AND table.date >= 
      '2016-10-19 08:37:45.606947') 
ORDER BY table.date DESC 
LIMIT 1 

所以我猜它的分開部該需要這麼多的執行時間和我手動移除以排序,看看在執行差異的查詢:

SELECT some_data 
FROM table 
     INNER JOIN anothertable 
       ON (table.value = 
           anothertable.value) 
WHERE (table.parent = 56521 
     AND table.date >= 
      '2016-10-19 08:37:45.606947') 
LIMIT 1 

上述查詢需要0.45秒,並導致空查詢集。

我得出的結論是,我的查詢在評估WHERE-Clause之前命令WHOLE數據集。我應該如何形成查詢以防止這種行爲?爲什麼會出現這種行爲?

這些都是解釋表的緩慢和快速查詢:

Slow 
+----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+ 
    | id | select_type | table | partitions | type | possible_keys       | key    | key_len | ref       | rows | filtered | Extra  | 
    +----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+ 
    | 1 | SIMPLE  | A  | NULL  | index | PRIMARY,D4b797d14e515242e7251754c57b7701 | date    | 5  | NULL       | 1325 |  0.08 | Using where | 
    | 1 | SIMPLE  | B  | NULL  | eq_ref | PRIMARY         | PRIMARY   | 4  | value      | 1 | 100.00 | NULL  | 
    +----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+ 

Fast: 
    +----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+ 
    | id | select_type | table | partitions | type | possible_keys       | key        | key_len | ref       | rows | filtered | Extra | 
    +----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+ 
    | 1 | SIMPLE  | A  | NULL  | ref | PRIMARY,D4b797d14e515242e7251754c57b7701 | D4b797d14e515242e7251754c57b7701 | 4  | const      | 5175 | 100.00 | NULL | 
    | 1 | SIMPLE  | B  | NULL  | eq_ref | PRIMARY         | PRIMARY       | 4  | value      | 1 | 100.00 | NULL | 
    +----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+ 
+1

大概,添加/刪除'ORDER BY ...'會導致執行計劃改變。你應該在兩種情況下嘗試'EXPLAIN SELECT ...',看看它有什麼不同。另外:table.parent,table.date,table.value和/或anothertable.value是否已編入索引? – Sasha

+0

所有這三個字段都被編入索引。 –

+0

另一種觀察:不是每次執行此查詢都會導致執行時間過長。一些是立即執行的,一些需要更多的時間 - 相同的查詢,父母/日期的不同值 –

回答

1

MySQL使用上date指數爲第一個查詢。它可以部分評估where條件(table.date >= '2016-10-19 08:37:45.606947'),如果符合的話,它會從您的表中讀取parent(相對較慢)以查看它是否合適。它可以在找到結果後立即停止(因爲order bylimit 1)。

您的第二個查詢使用parent(即具有長名稱的索引)上的索引,查找適合的行,然後從表中讀取date-部分並檢查它是否也適合。它必須繼續,直到它檢查了所有具有正確parent值的行(它使用索引找到),並且找到的所有行都必須經歷一個文件夾,並且將返回最新的行。 (我忽略了MySQL也必須檢查/執行join,但在兩次查詢中都是一樣的)。

你顯然有更多的行適合你的date條件比你的parent條件,所以它必須做更多的相對較慢的表查找,這將需要更長的時間。

在這種情況下。根據您的數據,實際上可能發生的情況是,通過date上的索引檢查的第一行已經滿足parent條件,並且可以在此停止。如果它使用parent上的索引,MySQL將被迫檢查所有具有parent值的行,然後執行一個文件。 MySQL根據一些統計數據決定,值得冒這個風險。那麼,它選錯了。

你可以做到以下幾點:

  • optimize table `table`(第二table是你的表名)更新的統計數據。這有時會有所幫助,但通常不會(因爲統計數據非常有限)。
  • 力MySQL使用你知道指數是更好的(... FROM table force index (D4b797d14e515242e7251754c57b7701) inner join ...
  • 加上完美的索引查詢:table(parent, date)應該(不包括join的潛在影響)的複合指數讓你更快的結果比你的無序查詢,MySQL將自己使用它。
+0

感謝您的迴應。看起來好像你的第三個技巧(複合索引)解決了我的問題。該數據庫是非常快,因爲我添加了複合索引。非常感謝你! –