2010-07-19 57 views
2

我有一個關於mysql基本數據庫優化的問題。 我有3個表格,文章,標籤和標籤(這是一個連接表)。針對mysql的索引進行基本優化

Articles   Taggings    Tags 
id    id     id 
name    article_id   name 
       tag_id 

我檢索恰好匹配指定標籤的物品,用下面的查詢

SELECT *, COUNT(*) AS c 
FROM articles AS a 
JOIN taggings AS tng ON a.id = tng.article_id 
JOIN tags AS t ON t.id = tng.tag_id 
WHERE t.name IN ("Red","Green") 
GROUP BY a.id 
HAVING c = 2 

這個查詢很慢,所以我做了講解,並得到了以下結果:

alt text http://dl.dropbox.com/u/2306276/EXPLAIN%20results.png

現在,我真的不明白我在這裏做什麼,但我認爲「類型:ALL」不好,所以我以爲我會添加索引(BT REE)添加到taggings表中的article_id和tag_id中,然後再次運行查詢。 alt text http://dl.dropbox.com/u/2306276/EXPLAIN%20results%202.png 那麼這對我沒有受過教育的眼睛來說看起來沒有什麼更好的,與前一行相同的行數,並且類型在兩種情況下仍然是ALL。

所以有人可以告訴我哪裏出錯了嗎?索引不會幫助我解決這個問題嗎?

我的標籤表將保持相對較小,所以我認爲查詢應該掃描標籤表以查找我指定的標籤,然後(通過索引)能夠立即檢索關聯的屬性,它應該都是很快,我的想法顯然是錯誤的。

感謝

[編輯] - 周杰倫的評論

我加入10K的文章,30K引用的Tagging和6個標籤,還增加了tag.name和taggings.tag_id 2個指數法,查詢還是花了長時間運行,0.5-1秒,EXPLAIN在下面。 alt text http://dl.dropbox.com/u/2306276/EXPLAIN%20results%203.png

+0

是tags.name索引? – Naktibalda 2010-07-19 20:52:37

+1

我必須[想知道GROUP BY是否由於MySQL對隱藏列的支持而導致性能不佳](http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden -columns.html) – 2010-07-19 20:55:10

+0

你有一個tags.name的索引嗎?如果你的數據庫有很多記錄 – 2010-07-19 20:57:01

回答

2

因爲tags.name是真的減少了許多在結果集中的行僅列,它必須被索引作出任何基於標記的搜索查詢速度更快。

更新:嘗試運行此查詢

SELECT a.* 
FROM articles AS a 
JOIN taggings AS tng ON a.id = tng.article_id 
JOIN tags AS t ON t.id = tng.tag_id 
WHERE t.name IN ("Red","Green") 
GROUP BY a.id 
HAVING COUNT(DISTINCT t.id) = 2 
+0

tags表格相對較小,我按照你的建議添加了索引,並且它對查詢時間沒有任何影響。 – dangerousdave 2010-07-20 07:38:13

+0

它會影響EXPLAIN的輸出嗎? – Naktibalda 2010-07-20 08:10:46

+0

使用EXPLAIN編輯我的原始文章時,可以看到向tags.name添加索引的效果以及其他一些更改。 – dangerousdave 2010-07-20 09:12:39

1

你也可以嘗試兩次連接到表而不是GROUP BY。這有時會產生更快的查詢:

SELECT a.* 
FROM articles AS a 
JOIN taggings AS tng1 ON a.id = tng1.article_id 
JOIN tags AS t1 ON t1.id = tng1.tag_id AND t1.name = "Red" 
JOIN taggings AS tng2 ON a.id = tng2.article_id 
JOIN tags AS t2 ON t2.id = tng2.tag_id AND t2.name = "Green" 
+0

不需要WHERE - 將它們移動到JOIN上......但是,實際上,如果您需要支持所有匹配的不同數量的標籤,這並不是那麼友好。 – 2010-07-19 20:55:52

+0

感謝您的回覆Mark,但不幸的是我需要支持不同數量的標籤。 – dangerousdave 2010-07-20 07:39:04

+1

我剛剛發現了這個artilce http://joinfu.com/presentations/tagging.pdf,它與您的建議相同,我將面臨的問題是如何動態創建這樣一個不同數量的標籤的查詢。 – dangerousdave 2010-07-20 10:16:06

1

有幾件事情怎麼回事。

首先,您的表格目前顯然非常小。當表很小時,DBMS經常會發現它讀取整個事物的速度更快,而不是使用任何索引。要獲得有意義的EXPLAIN結果,您需要在表中獲得實際的記錄數。

它也看起來像你有「id」字段聲明爲主鍵。主鍵是索引的一個子類,所以這些應該是可用的。注意解釋計劃表明它使用主鍵來查找標記記錄。

此查詢的顯而易見的起點是標籤。所以,如果這是一個重要的查詢,我會創建一個索引標籤(名稱)。然後它不需要順序搜索標籤表。

從那裏它應該通過tag_id查找標籤。所以你應該有一個索引。

然後它可以通過article_id查找文章。這是主要關鍵,所以它應該已經在那裏。

所以我想你會得到最有效的計劃與兩個索引:標籤(名稱)和標籤(tag_id)。

+0

感謝您的回覆Jay,我按照您的建議做了,並添加了10k文章,30k標籤和6個標籤。我添加了你建議的索引,但查詢仍然需要0.5-1秒運行。我編輯了我的原始帖子以顯示新的解釋。 – dangerousdave 2010-07-20 07:30:26

+1

嗯。它在兩個表格上執行eq_ref,這與將要獲得的一樣好。所以剩下的問題就是它決定閱讀表格的順序。儘管你有一個Tag.name的索引,但它決定在Taggings上進行完整的文件搜索。這有點好奇。如果你有6個標籤,並且你正在搜索其中的2個標籤,那麼也許DBMS不認爲它縮小到足夠有用。哦,添加所有記錄後,您應該運行Analyze以獲取統計信息更新。這可能有幫助。如果沒有,這可能會達到它所能達到的水平。 – Jay 2010-07-20 14:31:55