2011-01-10 83 views
0

感謝您的關注。在查詢中使用GROUP BY時,MySQL表索引的幫助

有兩個InnoDB表:

作者

id  INT 
nickname VARCHAR(50) 
status ENUM('active', 'blocked') 
about  TEXT 

author_id INT 
title  VARCHAR(150) 

我正在針對這些表的查詢,以獲得每個作者和他擁有的書籍數量:

SELECT a. * , COUNT(b.id) AS book_count 
FROM authors AS a, books AS b 
WHERE a.status != 'blocked' 
AND b.author_id = a.id 
GROUP BY a.id 
ORDER BY a.nickname 

此查詢非常慢(需要大約6秒鐘才能執行)。我有一個books.author_id索引,它的工作原理完美,但我不知道如何在authors表上創建索引,以便此查詢可以使用它。

下面是當前EXPLAIN外觀:

id select_type table type possible_keys    key   key_len ref  rows Extra 
1 SIMPLE  a  ALL  PRIMARY,id_status_nickname NULL   NULL  NULL 3305 Using where; Using temporary; Using filesort 
1 SIMPLE  b  ref  key_author_id    key_author_id 5   a.id 2  Using where; Using index 

我已經看了MySQL manual on optimizing queries with group by,但無法弄清楚如何我可以把它在我的查詢。

我將不勝感激任何幫助和暗示 - 有什麼必須是索引結構,以便MySQL可以使用它?

編輯

我曾嘗試:

(id, status, nickname) 
(status, nickname) 

都導致了同樣的情況。

+0

建立索引的基本經驗法則是您在連接和/或where子句中使用的任何字段都應該被索引。對於你的查詢,這意味着a.id,b.author_id和a。所有狀態都應該被索引。 – 2011-01-10 16:53:02

回答

3

我假設id_status_nickname是一個複合索引(id,status,暱稱)。在你的查詢中,你通過說a.status!= blocking來過濾行。這有以下問題:

  1. 您沒有可用於此的索引。 (身份,狀態,暱稱)不能使用,因爲狀態不是該索引的前綴
  2. 假設你有一個狀態索引,它在使用!=時不能使用。你必須改變狀態='活躍'
  3. 此外,狀態是一個枚舉字段只有兩個值的基數將很低。所以mysql可能最終不會使用索引。

你可以試試這個:create index as(status,id,nickname)並使用status ='active'。我的猜測是,既然你使用'=',status是索引的前綴,它應該選擇這個索引,然後將它用於group by,然後排序。希望這有助於。

更新: 看起來,當WHERE子句沒有在ORDER BY中使用字段時,不可能避免使用filesort。

0

我會嘗試索引(狀態,暱稱)。這應該擺脫「使用filesort」的必要性。