2013-04-11 280 views
5

我是新來的高級查詢,所以我可能有一些概念錯誤的,因爲當數據庫有超過100萬的記錄,我得到這樣的迴應ROM我的查詢......MySQL查詢時間太長

ERROR 2013: Lost connection to MySQL server during query

是!它實際上需要很長時間才能在它結束之前嘔吐。

我的查詢是這樣的......

SELECT users.username, 
    table_1.field_abc, table_1.field_def, 
    table_2.field_ghi, table_2.field_jkl 
FROM users 
LEFT JOIN table_1 ON table_1.username = users.username 
LEFT JOIN table_2 ON table_2.username = users.username 
WHERE 
    table_1.field_abc REGEXP "(spork|yellow)" OR 
    table_1.field_def REGEXP "(spork|yellow)" OR 
    table_2.field_ghi REGEXP "(spork|yellow)" OR 
    table_2.field_jkl REGEXP "(spork|yellow)" 
GROUP BY users.username 
ORDER BY 
(
    (CASE WHEN table_1.field_abc LIKE "%spork%" THEN 1 ELSE 0 END) + 
    (CASE WHEN table_1.field_abc LIKE "%yellow%" THEN 1 ELSE 0 END) + 
    (CASE WHEN table_1.field_def LIKE "%spork%" THEN 1 ELSE 0 END) + 
    (CASE WHEN table_1.field_def LIKE "%yellow%" THEN 1 ELSE 0 END) + 
    (CASE WHEN table_2.field_ghi LIKE "%spork%" THEN 1 ELSE 0 END) + 
    (CASE WHEN table_2.field_ghi LIKE "%yellow%" THEN 1 ELSE 0 END) + 
    (CASE WHEN table_2.field_jkl LIKE "%spork%" THEN 1 ELSE 0 END) + 
    (CASE WHEN table_2.field_jkl LIKE "%yellow%" THEN 1 ELSE 0 END) 
)DESC; 

我在http://sqlfiddle.com/#!2/cbbda/28

,因爲只有少數記錄在sqlfiddle樣品運行快,但發佈了一個樣本數據集(只有少數記錄)我嘗試在自己的服務器上覆制記錄,並且查詢只運行了幾條記錄,並且在添加一百萬條記錄後非常緩慢。

是否有任何可能的方法讓我的結果更快?

+0

這看起來像一個有趣的查詢......嘿......你有比較列上的索引? – 99823

+0

+1實際上花時間縮進你的sql很好 –

+0

@Loren請原諒我...我是新的...索引? –

回答

0

我不這麼認爲 - 對於這張表,我懷疑你會讓它快速運行,所有這些LIKE都在其上。那些必須經歷荒謬的次數。

如果這些值是固定的,那麼您可以在名爲abc_like_yellowabc_like_spork等的表中添加新列,然後填充這些值一次,然後您就可以輕鬆地從該列中查詢。

但是,如果你想動態地做到這一點,你可能會運氣不好。

+0

不是固定的數據....只是樣本假數據。每條記錄中的實際數據不同。 –

+0

我認爲他的意思是固定在查詢中 - 你總是在尋找'spork'和'yellow',所以你可以爲這些添加布爾列? – Barmar

0

由於我們加入username,本專欄的索引很可能會加快速度。

另外,你能夠使用內連接而不是左連接嗎?這也可以在很大程度上加快查詢速度。

最後,如有必要,可以在內存中完成排序,而不是要求數據庫執行該操作(即在返回結果集後對其進行排序)。

+0

我不能使用INNER JOIN ...我試過...請參閱http://stackoverflow.com/questions/15958386/not-all-data-coming-back-from-mysql-query –

0

好夥計......有了您的幫助下,我們有一個解決方案...查看... http://sqlfiddle.com/#!2/fcfbd/5 但我仍舊有一個問題...

我改變了表中添加索引...

ALTER TABLE `users` ADD FULLTEXT (`username`); 
ALTER TABLE `table_1` ADD FULLTEXT (`field_abc`,`field_def`); 
ALTER TABLE `table_2` ADD FULLTEXT (`field_ghi`,`field_jkl`); 

我然後把@Barmar的建議,改變了代碼,這...

SELECT users.username, 
    table_1.field_abc, table_1.field_def, 
    table_2.field_ghi, table_2.field_jkl 
FROM users 
LEFT JOIN table_1 ON table_1.username = users.username 
LEFT JOIN table_2 ON table_2.username = users.username 
WHERE 
    MATCH(table_1.field_abc,table_1.field_def,table_2.field_ghi,table_2.field_jkl) 
    AGAINST ("spork yellow" IN BOOLEAN MODE) 
GROUP BY users.username 
ORDER BY 
(
    (CASE WHEN MATCH(table_1.field_abc) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END) + 
    (CASE WHEN MATCH(table_1.field_abc) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END) + 

    (CASE WHEN MATCH(table_1.field_def) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END) + 
    (CASE WHEN MATCH(table_1.field_def) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END) + 

    (CASE WHEN MATCH(table_2.field_ghi) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END) + 
    (CASE WHEN MATCH(table_2.field_ghi) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END) + 

    (CASE WHEN MATCH(table_2.field_ghi) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END) + 
    (CASE WHEN MATCH(table_2.field_ghi) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END) 
)DESC; 

上百萬的記錄在我的真正的數據庫,我得到了我6結果。 5027秒。這是一個很好的比......好吧,花了這麼長時間,它嘔吐!

我現在唯一的問題是......爲什麼它只能在BOOLEAN MODE中工作,而不是在http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html#function_matchhttp://dev.mysql.com/doc/refman/5.5/en/fulltext-search.html提到的其他2個選項?

+0

也許是因爲這樣: _另外,出現在50%或更多行中的單詞被認爲是常見的並且不匹配._ – Barmar

+0

我不認爲您需要在「用戶名」列上使用全文索引。 – Barmar

+0

@Barmar對不起,我感到困惑...不工作,我不是說我沒有得到任何結果,我的意思是我得到一個語法錯誤。顯然這是一個無效的查詢,沒有'IN BOOLEAN MODE'。我似乎無法得到其他模式的工作。 –

0

我正在使用我的第一個解決方案,但發現它給出了一些我無法弄清楚的誤報,所以我想出了這個...

(SELECT username, MATCH(field_abc,field_def) AGAINST ("spork yellow" IN BOOLEAN MODE) AS score FROM table_1 HAVING score>0) 
UNION ALL 
(SELECT username, MATCH(field_ghi,field_jkl) AGAINST ("spork yellow" IN BOOLEAN MODE) AS score FROM table_2 HAVING score >0) 

由於每個記錄被單獨返回,我不能用我GROUP BY加入這個PHP代碼我的查詢結束後:

while($row = mysql_fetch_array($result)) 
{ 
    if(in_array($row['username'],$usernames)) 
    { 
     $usernames_count[$row['username']] += $row['score']; 
    } 
    else 
    { 
     array_push($usernames,$row['username']); 
     $usernames_count[$row['username']]=$row['score']; 
    } 
} 
arsort($usernames_count); // Sort the results high->low 

foreach($usernames_count as $key=>$value) 
{ 
    echo "Username: ".$key." had a score of ".$value." in the search results<br/>"; 
} 

現在看來如此簡單相比,我做其他的嘗試。

0

當您的服務器必須掃描數百萬個條目時,它的功能可能不足以快速處理查詢。

一般來說,要提高網站的速度,你可以嘗試CloudFlare

如果你特別想加快你的SQL,Google Cloud SQL可能能夠幫助。 Google功能強大的服務器旨在掃描數十億條SQL條目,例如執行Google搜索時。

只要沒有返回錯誤,上述兩項服務將有助於顯着加快您的查詢時間。

我希望我能幫忙!

VCNinc 
0

如果你有機會到SQL Server,突出在SQL Server的完整的查詢,並單擊+ L

這將顯示查詢執行計劃。根據這些結果優化查詢;

如果例如您看到表掃描,那麼索引可能會有所幫助。 編寫不使用術語不同的查詢。 如果訂單不重要,請勿訂購結果。

在您的示例中,複雜的最後一組訂單是非常昂貴的。

而是按照下列步驟: 填充核心數據,然後拉動芯信息到一個臨時表,9個額外的列(int型,intially設置爲0) ,更新各自基於0或8列的1個標準 更新的最後一列的其他8列 從表中檢索信息的總和,只有一個單一的「訂單由」基於列的9

在我的經驗,這種方法只需要20%與在內部進行訂單的時間相比。