2013-03-26 59 views
1

我有一個MySQL查詢,我需要優化,儘可能(應低於5秒加載時間,如果可能的話)優化數據庫查詢最多10MIL行作爲結果

查詢如下:

SELECT domain_id, COUNT(keyword_id) as total_count 
FROM tableName 
WHERE keyword_id IN (SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X) 
GROUP BY domain_id 
ORDER BY total_count DESC 
LIMIT ... 
  • X是來自一個輸入
  • 域ID和keyword_id被索引
  • 數據庫是在本地主機的整數,所以網絡速度應該是最大

WHERE子句中的子查詢最多可以獲得10密耳的結果。另外,對於MySQL來說,看起來真的很難計算COUNT和ORDER BY這個計數。

我試圖混合此查詢與SOLR,但沒有結果,獲得如此高的行數在一次給了硬時間MySQL和SOLR

我正在尋找一個解決方案,具有相同的結果,無論我是否需要使用不同的技術或對此MySQL查詢的改進。

謝謝!


查詢邏輯是這樣的:

我們有一個域,我們正在尋找正在該域名上使用的所有關鍵字(這是子查詢)。然後,我們將所有使用至少一個在第一個查詢中找到的關鍵字(按域分組)的關鍵字與每個關鍵字使用的關鍵字數進行比較,並且我們必須根據所用關鍵字的數量顯示它的有序DESC。

我希望這是有意義的

+0

爲什麼你需要內部查詢你可以在where子句中使用domain_id = x?並在domain_id上添加索引(如果不存在) – shola 2013-03-26 08:19:42

+0

@shola請仔細查看查詢,這是關於相關數據 – GabrielCol 2013-03-26 08:22:58

+0

您能否發佈EXPLAIN? – 2013-03-26 08:25:02

回答

1

您可以嘗試JOIN代替子查詢:

SELECT tableName.domain_id, COUNT(tableName.keyword_id) AS total_count 
FROM tableName 
INNER JOIN tableName AS rejoin 
ON rejoin.keyword_id = tableName.keyword_id 
WHERE rejoin.domain_id = X 
GROUP BY tableName.domain_id 
ORDER BY tableName.total_count DESC 
LIMIT ... 
+0

感謝您的回答,雖然沒有幫助.. – GabrielCol 2013-03-26 09:48:25

+1

@GabrielCol你可以發佈EXPLAIN輸出(原始和我的)查詢? – kernel 2013-03-26 09:55:14

+0

執行查詢應用您的方法需要187.6582秒才能執行,這與我原來的查詢非常相似。 – GabrielCol 2013-03-26 10:02:33

0

我不是100%肯定,但你可以試試這個請

SELECT t1.domain_id, COUNT(t1.keyword_id) as total_count 
FROM tableName AS t1 LEFT JOIN 
(SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X) AS t2 
ON t1.keyword_id = t2.keyword_id 
WHERE t2.keyword_id IS NTO NULL 
GROUP BY t1.domain_id 
ORDER BY total_count DESC 
LIMIT ... 

的目標是用INNER JOIN取代WHERE IN條款,這將使它更快。子句總是讓Mysql服務器掙扎,但當你使用大量的數據時它更加明顯。使用WHERE IN只有當它讓你的查詢看起來更容易閱讀/理解,你有一個小的數據集或以其他方式不可能(但你可能會有另一種方式來做到這一點:))

0

在MySQL的條款你可以做的就是使用覆蓋索引來最小化查詢的磁盤IO,並重寫它以提高效率,這樣查詢就會從中受益。

由於keyword_id在表的另一個副本中有匹配,因此COUNT(keyword_id)變爲COUNT(*)

您使用的子查詢類型是MySQL最糟糕的情況(它爲每行執行子查詢),但我不確定這裏是否應該用JOIN代替它,因爲它可能是一個合適的您的數據策略。

正如你可能知道,像查詢:

SELECT domain_id, COUNT(*) as total_count 
FROM tableName 
WHERE keyword_id IN (X,Y,Z) 
GROUP BY domain_id 
ORDER BY total_count DESC 

將有一個覆蓋綜合指數(keyword_id, domain_id [,...])最好的性能,所以這是必須的。從另一個側面,像查詢:

SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X 

將有一個覆蓋綜合指數(domain_id, keyword_id [,...])最佳性能。所以你需要他們兩個。

希望但我不確定,當你有後者​​的索引時,MySQL可以理解你不需要在子查詢中選擇所有這些keyword_id,但是你只需要檢查索引中是否有條目,如果你不使用DISTINCT,我相信它會更好地表達出來。

所以,我會嘗試添加這兩個指標和重寫查詢爲:

SELECT domain_id, COUNT(*) as total_count 
FROM tableName 
WHERE keyword_id IN (SELECT keyword_id FROM tableName WHERE domain_id = X) 
GROUP BY domain_id 
ORDER BY total_count DESC 

另一個選擇是重寫查詢如下:

SELECT domain_id, COUNT(*) as total_count 
FROM (
    SELECT DISTINCT keyword_id 
    FROM tableName 
    WHERE domain_id = X 
) as kw 
JOIN tableName USING (keyword_id) 
GROUP BY domain_id 
ORDER BY total_count DESC 

再次,你需要這兩個複合索引。

哪一個查詢更快取決於tableName中的統計信息。