2013-12-17 214 views
1

我想要統計一個表中的記錄數。 該表被稱爲從屬關係,只有4列(其中2個是外鍵)更好/更有效的方式來寫這個查詢

我想統計附屬列爲0且business_id與特定account_email相關的記錄數。

我知道如何使用IN關鍵字執行此查詢,但我想知道是否有更好或更有效的方法來執行此操作。

這是版本的查詢:

SELECT COUNT(1) FROM affiliations 
WHERE business_id IN (
    SELECT business_id 
    FROM affiliations 
    WHERE account_email = '[email protected]' 
) AND affiliated = 0 

我知道我大概可以用EXISTS替換此:

SELECT COUNT(1) FROM affiliations 
WHERE EXISTS (
    SELECT 1 FROM affiliations 
    WHERE account_email = '[email protected]' 
) AND affiliated = 0 

將與EXISTS工作的聲明?正如以前所問,是否有更好的方法來做到這一點?

提前致謝!

+0

一些額外的信息: business_id不在此表中是唯一的。數據庫中的帳戶和業務之間存在多對多關係,並且此表包含相關的account_emails和business_ids。我選擇了ACCOUNT_EMAIL,並希望得到所有的帳戶是關係到business_ids,再算上 –

+0

請張貼也與每個這些企業的賬戶數量的EXPLAIN分析這個查詢 – hd1

+0

的輸出如何計算business_id如何對於account_email ='[email protected]'和affiliated = 0 – faisal

回答

0

從與IN子句的問題的第一個查詢是不等同於第二與EXIST

要第一查詢轉換與IN,則必須使用子查詢相關:

SELECT COUNT(1) FROM affiliations a1 
WHERE EXISTS (
    SELECT 1 FROM affiliations a2 
    WHERE account_email = '[email protected]' 
     AND a1.business_id = a2.business_id 
) AND affiliated = 0 

重視這一情況:AND a1.business_id = a2.business_id

上面的查詢是語義eqivalent您與IN第一個查詢。
他們的表現是一樣的好,因爲MySQL,在optimalization階段,intenrally轉換這種形式的條件:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

成這樣:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)

請參閱此鏈接detalis:http://dev.mysql.com/doc/refman/5.0/en/subquery-optimization-with-exists.html
特別注意關於NULL值的討論以及NULL如何影響優化器。

簡而言之 - 如果business_id列被聲明爲NOT NULL,那麼MySql能夠優化這兩個查詢。
見定論(頁面在這個環節的底部):

爲了幫助查詢優化器更好地執行你的查詢,使用這些技巧:

  • 列必須聲明爲如果它是真的,則爲NOT NULL。 (這也有助於優化器的其他方面。)

  • 如果您不需要將NULL與FALSE子查詢結果區分開來,則可以輕鬆避免執行緩慢的路徑。更換的比較,看起來像這樣:

    outer_expr IN(SELECT inner_expr FROM ...)

    這個表達式:

    (outer_expr IS NOT NULL)AND(outer_expr IN(SELECT inner_expr FROM ...))

    然後NULL IN(SELECT ...)永遠不會因爲MySQL停止只要表達式的結果是明確的評估和評價部分。

+0

可以看到顯着的性能提升。感謝您提供的信息,這很有幫助和有趣。 –

-1

使用JOIN而不是IN。 IN是可怕的性能,如果你想匹配很多值

SELECT COUNT(1) 
FROM affiliations AS ABB2 
    JOIN (SELECT business_id 
      FROM affiliations 
      WHERE account_email = '[email protected]') AS ABB1 
     ON ABB1.business_id = ABB2.business_id 
WHERE affiliated = 0 
+0

@Lloyd,JOIN在語義上不等同於SEMI JON(存在/中),請參閱此演示:http://www.sqlfiddle.com/#!2/b228c/1注意查詢結果和查詢結果答案。此外,當IN包含一個巨大的值列表(常量)時,IN的性能可能很差,但這不適用於具有「IN(子查詢)」的查詢,MySql能夠優化這樣的查詢,並且它可能甚至會更快地傷害喬寧。 – krokodilko

+0

好的,謝謝你的信息。我可能會堅持IN聲明。我猜IN關鍵字存在的原因,這似乎是一個很好的情況下使用它。 –

+0

@kordirko我以爲business_id是唯一的假設。如果沒有,您可以在子查詢中添加一個GROUP BY,您將獲得相同的結果。我知道一些IN情況下IN可能比直接JOIN快一點,但在絕大多數情況下,如果不比IN快,JOIN是相同的。在較舊版本的MySQL或那些不運行InnoDB的版本中尤其如此。 –

1

我會使用存在的,還記得到下面的子查詢關聯到主表。

SELECT COUNT(1) FROM affiliations a 
WHERE exists (
    SELECT 1 
    FROM affiliations a1 
    WHERE account_email = '[email protected]' 
    and a1.business_id=a.business_id 
) AND affiliated = 0 
相關問題