在我們進入提前優化模式之前,查看下面的查詢模板可能很有用。如果沒有其他可以用來作爲衡量可能的優化效果的基線。
SELECT T.Tagid, TagInfo.TagName, COUNT(*)
FROM Items I
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId
JOIN ItemTagMap T ON I.ItemId = T.ItemId
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId
WHERE I.ItemId IN
(
SELECT ItemId
FROM Items
WHERE -- Some typical initial search criteria
Title LIKE 'Bug Report%' -- Or some fulltext filter instead...
AND ItemDate > '02/22/2008'
AND Status = 'C'
)
--AND T1.TagId = 'MySql'
GROUP BY T.TagId, TagInfo.TagName
ORDER BY COUNT(*) DESC
子查詢是「驅動查詢」,即對應於最終用戶的初始標準的那個。 (請參閱下面有關此查詢的詳細信息,需要多次才能適用於整體優化流程) 註釋爲T1上的JOIN(並且可能在選擇多個標記時T2,T3),並且使用WHERE子句相關標準。當用戶選擇特定標籤時,無論是作爲初始搜索的一部分還是通過細化,都需要這些。 (這可能是更有效的放置這些連接,並且其中所述子查詢中的條款;更多關於這些下文)
討論... 「驅動查詢」,或其變體需要用於兩個不同用途:
1,以提供所需要枚舉所有相關聯的標籤項目Id的完整列表。
2提供前N個ItemId值(N是顯示頁面大小),用於在Item表中查找Item詳細信息。
注意,完整列表不需要進行排序(或者也可以從不同的順序排序中獲益),從而使第二列表需要根據用戶的選擇進行排序(比如按日期,降序或標題,按字母順序升序)。還要注意的是,如果需要任何排序順序,查詢的代價將意味着處理完整列表(由SQL本身避免奇怪的優化,和/或一些非規範化,SQL需要「查看」該列表上的最後記錄,如果它們屬於頂部,按照順序)。
這後一個事實是贊成爲兩個目的有相同的查詢,相應的列表可以存儲在臨時表中。一般流程是快速查找含有詳細信息的前N個項目記錄,並立即將其返回給應用程序。然後,應用程序可以獲取ajax-fashion用於細化的標籤列表。這個列表將產生一個類似於上面的查詢,其中子查詢被替換爲「select * from temporaryTable」。 SQL優化器會決定對此列表進行排序(在某些情況下),讓我們讓它做到這一點,而不是第二次猜測它並明確排序。
另一個要考慮的問題是,可能會將ItemTagMap表上的連接帶入「驅動查詢」中,而不是像上面所示。這可能是最好的,無論是爲了表現,還是因爲它會產生#2目的的正確列表(顯示一頁的項目)。
即使在相對適中的硬件上,上述查詢/流程也可能相當順利;暫定爲1/2 Million +項目,持續的用戶搜索量可能高達每秒10個。其中一個關鍵因素是初始搜索標準的選擇性。
優化思路
- [根據典型的搜索案件和數據統計]可能是有意義將通過使(確實複製)一些項目字段到ItemTagMap表的非規範化。特別是短的領域可能是'受歡迎的'那裏。隨着數據量在百萬以上的項目中增長,我們可以利用一些標籤(例如:在SO中,PHP通常與MySql一起出現,通常沒有任何理由...)和各種技巧的強關聯。例如,引入「多標籤」TagIds可能會使輸入邏輯稍微複雜一些,但也可能會顯着縮小映射的大小。
- '不說了! -
應根據實際要求和有效的數據統計資料選擇適當的體系結構和優化...
來源
2009-10-07 02:30:43
mjv
在增加要求的風險下,是不是也很好地顯示COUNT每個標籤,對應一個特定的搜索? – mjv 2009-10-07 02:04:53
是的,我會這樣做 - 我甚至統計每個標籤存儲在單獨的表中。 – 2009-10-07 02:11:25