2010-12-16 55 views
2
SELECT COUNT(*) AS cnt 
FROM products 
WHERE ExternalProductId IS NOT NULL 
GROUP BY SourceId, ExternalProductId 
HAVING cnt > 1 

在(ExternalProductId,SourceId,AnotherField)上有一個索引。解釋顯示使用了索引。這是在「額外」列印解釋:爲什麼下面的查詢複製表數據?

Using where; Using index; Using temporary; Using filesort 

當我運行通過SHOW PROCESSLIST查詢我看到:

Copying to tmp table on disk 

我可以調整這個查詢在地方工作的指標?我也不介意由於其他進程同時在這個表上工作,我得到的結果稍微不準確 - 我可以更改隔離級別來提高查詢的性能嗎?

+2

我想你有一些誤解。臨時表並不意味着從表中複製所有數據以完成其工作。它只意味着它將一些中間結果複製到臨時表中以供進一步處理。臨時表可能包含ExternalProductID不爲空和cnt列的所有記錄,因此它可以評估'HAVING'子句。其次,事務隔離與臨時表無關。 – bot403 2010-12-16 15:37:15

+0

@ bot403 - 我剛剛和我們的DBA交談過,他同意你的意見。我相信你的評論實際上是迄今爲止這個問題的最佳答案。 – ripper234 2010-12-16 17:40:05

+0

是的,我認爲答案是我的#1和阿杰里爾的指數建議。 – bot403 2010-12-16 19:04:11

回答

3

如果您將GROUP BY中的列反向對應於複合索引前兩個字段的排序,它將更有效地使用您的複合索引。

SELECT COUNT(*) AS cnt 
FROM products 
WHERE ExternalProductId IS NOT NULL 
GROUP BY ExternalProductId, SourceId 
HAVING cnt > 1 

你的查詢執行平原應該變成'Using where; Using index',並擺脫這兩個臨時表和文件排序引起其他GROUP BY的。

您仍然可以得到相同的結果,但它會略有不同。

+0

看起來不錯,解釋實際上現在不顯示臨時表。我將測量查詢運行時以查看是否有差異。 – ripper234 2010-12-17 01:09:05

0

幾件事情要嘗試:

  1. MySQL將自動排序與一組通過。如果您不關心排序順序,請添加'ORDER BY NULL'子句。這將取出filesort和可能的臨時表。

  2. 刪除計數(*)並使用索引中列的名稱而不是通配符。

另外。你的索引是什麼?你能向我們展示完整的表格創建語句嗎?

+0

ORDER BY NULL仍使用臨時表 - 請參閱接受的答案。 – ripper234 2010-12-17 13:58:34

相關問題