2014-01-17 113 views
0

編輯: 所以這是我使用查詢:優化MySQL查詢與IN子句爲10000條記錄

SELECT * 
    FROM contacts 
    WHERE id in 
     (
    SELECT DISTINCT contacts.id 
    from contacts INNER 
    JOIN contacts2tags ON contacts.id = contacts2tags.contactid 
    WHERE (tagid in (178))) 

它運行很慢。建議優化它? 我已經添加了索引,但它仍然需要改進!

聯繫人表包含id,first_name,last_name,..and 標籤表包含id,name。 contacts2tags表中包含的ContactID和標籤識別哪些是相同contacts.id和tags.id分別 說明: enter image description here

請看看:optimise mysql query with LIKE operator for 10k records

這是愚蠢的我張貼的一部分在這裏查詢。對不起:P

+2

你可以把創建語法表格聯繫人和聯繫人標籤以及查詢中的解釋。既然你使用了會有一個文件夾和臨時表。所以,這也取決於你的服務器容量。 –

+0

我希望你有一個關於c.id和t.tagid索引的索引,在這種情況下,我希望MySQL能夠找到contacts2tags表上的記錄,然後將這些記錄與聯繫人聯繫起來。如果在t.tagid上沒有索引,而是在t.contactid上有一個索引,則它必須在一個或另一個表上執行非鍵控搜索,具體取決於它首先使用哪個索引。 – Kickstart

+0

謝謝。我確實在索引編號和編號 – user415

回答

0

我剛剛比較了查詢
select benchmark(1000000,1 in(1,2,3,4,5));花費0.122秒
選擇基準(1000000,(1 = 1或1 = 2或1 = 3或1 = 4或1 = 5));花了0.088秒

所以,你可以嘗試使用或代替我不知道,但在索引也沒有使用,所以只是試一試。

0

使用或代替IN。

您的查詢應該是: SELECT c.id FROM接觸℃的內部加入contacts2tags噸上c.id = t.contactid WHERE (t.tagid = 7或t.tagid = 4) GROUP BY c.id HAVING count(distinct t.tagid)= 2

0

您向我們顯示的計劃表示優化器只希望獲取3行數據。如果它的「緩慢」(你沒有說速度有多慢),那麼大概這個計劃並不是最優的,或者你的數據是非常不正確的。

我要檢查的第一件事是索引統計是否是最新的。然後我試試...

SELECT count(*) 
    FROM contacts c 
inner join contacts2tags t 
    on c.id = t.contactid 
    WHERE t.tagid in (7,4) 

要了解DBMS實際處理多少行以解決查詢。如果這個數字非常高,那麼你不可能通過調整查詢來獲得很大的性能提升。

....但一個潛在的解決方案將....

SELECT c.id 
FROM contacts c, 
    contacts2tags t4, 
    contacts2tags t7, 
WHERE c.id = t4.contactid 
AND c.id = t7.contactid 
AND t4.contactid=t7.contactid 
AND t4.tagid=4 
AND t7.tagid=7; 
+0

上都有索引,對不起,實際的行數是11000.我正在編輯與實際快照(如在實際服務器上)的帖子 – user415

+0

你真的沒有主鍵在contacts.id? ?? !!!! – symcbean

+0

of course我擁有它 – user415

0

不能看到你更新的查詢使用子查詢的需要。嘗試以下(儘管最好使用來自聯繫人而非聯繫人的所需列的名稱。*)。

SELECT DISTINCT contacts.* 
FROM contacts 
INNER JOIN contacts2tags ON contacts.id = contacts2tags.contactid 
WHERE tagid IN (178) 

確保contacts2tags表上的tagid上有一個索引。

如果contacts2tags上的contactid/tagid是唯一的(我希望),那麼不需要DISTINCT。這可以通過在tagid/contactid上添加一個唯一的覆蓋索引來強制執行(以便允許在WHERE子句中使用此密鑰)。

+0

那不好?!假設每個標籤有多個ID,您將獲得多個聯繫人記錄,然後您可以再次使用DISTINCT「修復」這些記錄,從而爲服務器提供比嚴格需要的更多工作。 – deroby

+0

另一種方法是針對子查詢使用連接,這會導致連接未被編入索引,或者使用IN作爲原始文章中的子查詢,這將再次變爲非索引。在這種情況下,它可能會針對對索引tagid列的contacts2tags進行查詢,然後將其與使用主鍵id字段的聯繫人進行連接。如果IN子句中有多個tagid,則區別是一個令人討厭的問題,但不能真正避免任何效率。 – Kickstart

0

我想知道爲什麼你會先在子查詢中加入聯繫人和contacts2tags,然後再用它來過濾聯繫人!

我推測原因是你已經將DISTINCT優化​​到了id(精簡)id字段,而不是之後在整個聯繫人*記錄中進行。

不管怎麼說,你實際上應該做恕我直言如下:

SELECT * 
FROM contacts 
WHERE EXISTS (SELECT * 
       FROM contacts2tags 
       WHERE contacts2tags.contactid = contacts.id 
        AND tagid in (178)) 

這不會雙觸點記錄作爲查詢處理器知道它可以停止搜索,一旦發現在contacts2tags表中的第一次打擊。

至於使用IN()對使用或者......我懷疑它將使一個很大的區別,作爲內部它可能被轉換爲同樣的事情呢(?!)

+0

嘿,請看看http://stackoverflow.com/questions/21154636/optimise-mysql-query-with-like-operator-for-10k-records/21155012#21155012我想因爲在contacts2tags中有很多記錄表以及,當我使用WHERE EXISTS(..)或者可能是其他原因時,查詢變得更慢。我是MySQL的業餘愛好者。感謝您對這篇文章的支持。 :D – user415

+0

另一篇文章主要關注LIKE和文本匹配;我懷疑WHERE EXISTS()與那個有什麼關係。在我的(基於MSSQL的)經驗中,WHERE EXISTS()永遠不應該比JOINING慢,尤其是當那個JOIN稍後再需要額外的DISTINCT時。但也許MySQL是奇特的? – deroby