2010-04-15 79 views
1

我在查詢中遇到性能問題。查詢時的性能問題

第一張表是一張客戶表,其中有數百萬條記錄。客戶表有一列電子郵件地址和一些其他有關客戶的信息。

第二個表是一個CommunicationInfo表,其中只包含電子郵件地址。

而我在這裏想要的是; CommunicationInfo表中的電子郵件地址在Customers表中重複多少次。什麼可能是最執行者的查詢。

我可以解釋這種情況的基本查詢是;

Select ci.Email, count(*) from Customer c left join 
CommunicationInfo ci on c.Email1 = ci.Email or c.Email2 = ci.Email 
Group by ci.Email 

但肯定的是,它大約需要5,6分鐘的執行時間。

在此先感謝。

+1

'CommunicationInfo'中有多少條記錄? – Quassnoi 2010-04-15 17:49:23

+0

'Customer'和'CommunicationInfo'之間的關係是什麼?我在考慮每個'Customer'行有很多'CommunicationInfo'行,是這種情況嗎? – 2010-04-15 17:55:50

+0

@KM:*第二個表是一個CommunicationInfo表,其中只包含電子郵件地址*。我相信這是一個查詢表,每個電子郵件只添加一次。 – Quassnoi 2010-04-15 17:57:54

回答

3

這個查詢大約是一樣好,如果你在CommunicationInfo.Email

Select 
    c.Email, count(*) 
    from Customer c 
     left join CommunicationInfo ci on c.Email1 = ci.Email 
     left join CommunicationInfo ci2 on c.Email2 = ci2.Email 
    Group by c.Email 
+2

鍵是索引。確保電子郵件列正確編入索引。 – Raja 2010-04-15 17:26:00

+0

如果'ci.Email'是'PRIMARY KEY',則此查詢是'SELECT email,COUNT(*)FROM customer'的同義詞。如果不是,這個查詢是一個凌亂的笛卡爾連接。 – Quassnoi 2010-04-15 17:33:20

1

對Customer.Email和另一索引得到使用OR條件搶奪機會的優化器使用HASH JOINMERGE JOIN

使用此:

SELECT ci.Email, SUM(cnt) 
FROM (
     SELECT ci.Email, COUNT(c.Email) AS cnt 
     FROM CommunicationInfo ci 
     LEFT JOIN 
       Customer c 
     ON  c.Email1 = ci.Email 
     GROUP BY 
       ci.Email 
     UNION ALL 
     SELECT ci.Email, COUNT(c.Email) AS cnt 
     FROM CommunicationInfo ci 
     LEFT JOIN 
       Customer c 
     ON  c.Email2 = ci.Email 
     GROUP BY 
       ci.Email 
     ) q2 
GROUP BY 
     ci.Email 

或本:

SELECT ci.Email, COUNT(*) 
FROM CommunicationInfo ci 
LEFT JOIN 
     (
     SELECT Email1 AS email 
     FROM Customer c 
     UNION ALL 
     SELECT Email2 
     FROM Customer 
     ) q 
ON  q.Email = ci.Email 
GROUP BY 
     ci.Email 

請確保您有Customer(Email)索引和Customer(Email2)

第一個查詢將是,如果你的電子郵件大多是更有效沒有填充,第二個 - 如果大多數電子郵件被填充。

+0

我有一種感覺,因爲Customer表中有數百萬條記錄,所以兩次擊中IO不一定會讓它跑得更快,但是這個想法也跨越了我的想法。 – Jeremy 2010-04-15 17:38:57

+0

@Jeremy:只要'Email'和'Email2'被編入索引,就會以順序方式從兩個索引中獲取所有的密鑰。如果所有或幾乎所有的字段都被填充並且匹配,則只需要以效率較低的嵌套循環(隨機讀取)方式完成相同的事情。 – Quassnoi 2010-04-15 17:47:42

+0

啊,是的,你提到索引需要在列上。我的錯。 – Jeremy 2010-04-15 18:12:58

1

你提到:

什麼,我想在這裏;多少 倍 中的電子郵件地址CommunicationInfo表在 客戶表中重複。什麼可能是最執行者查詢的 。

對我來說,這聽起來像你可以很容易地使用INNER JOIN--這很可能會快很多,因爲它會將搜索範圍限制在真正有電子郵件的客戶身上 - 任何人根本沒有電子郵件(因此count(*)= 0)甚至不會被查看 - 即使SQL Server必須計數和分組的行數也可能會有很大差異。

那麼試試這個:

SELECT 
    ci.Email, COUNT(*) 
FROM 
    dbo.Customer c 
INNER JOIN dbo.CommunicationInfo ci 
    ON c.Email1 = ci.Email OR c.Email2 = ci.Email 
GROUP BY 
    ci.Email 

如何在你的情況下進行?

+0

它需要很多時間來執行。 – 2010-04-15 17:35:41

0

根據您的環境,您可以做的不多,以優化這一點。

幾個問題:

  1. 在CommunicationInfo多少記錄?
  2. 你真的需要多久運行一次查詢?這是一次性分析,還是多人會每10分鐘運行一次?
  3. 字段索引?我會猜測Email1和Email2字段都沒有索引。但是,如果不考慮整個系統的平衡性,我不會建議增加索引。
  4. 爲什麼使用左連接?你真的需要客戶表中的所有東西嗎?你在計數,所以在做INNER JOIN時沒有任何傷害。

建議:

  1. 運行通過查詢優化嚮導查詢,看看是否有什麼SQL Server的建議。
  2. 一個極端的建議是將Email1和Email2列轉儲到臨時表中並加入到該表中。由於特定表上的大量壓力,我發現查詢運行緩慢,所以有時將記錄複製到臨時表中速度更快,但此技術非常依賴於有多少內存,IO的速度以及特定桌子上的壓力量。