2011-04-09 44 views
0

這是一個問題的兩個部分,但首先一些背景資料:SQL查詢執行時間快,但在讀取行緩慢

我在Sybase一個TSQL查詢報告的0.328秒的執行時間,但其採取大約20-30秒才能檢索大約5000行。該查詢有兩個子查詢和一個左外部聯接。

查詢看起來大致是這樣的:

SELECT CustomerContact.Id, Customer.Name, ... 
    , CustomerContacts.LastName, CustomerContacts.FirstName 
    , (SELECT max(LastModified) 
      FROM ContactPhone 
      WHERE ContactPhone.ContactID = CustomerContact.ID 
     ) as PhoneLastModified 
    , (SELECT max(LastModified) 
      FROM ContactEmail 
      WHERE ContactEmail.ContactID = CustomerContact.ID 
     ) as EmailLastModified 
    FROM CustomerContacts 
    LEFT OUTER JOIN Customer 
     ON Customer.ID = CustomerContact.CustomerId 
    WHERE (PhoneLastModified > '2011-01-01' 
     OR EmailLastModified > '2011-01-01') 

我在做基於任何相關的聯繫信息的最後修改日期選擇的客戶記錄。 ContactPhone和ContactEmail可以包含CustomerContact中任何給定行的x個記錄。 Customer表與CustomerContact是一對一的。

現在我的問題:

  1. 怎麼來的Sybase報告的0.328秒的執行時間,但它實際上正在接近30秒的檢索查詢的行?

  2. 如何優化此查詢?

我的第一個想法是添加索引到LastModified列,但我正在處理少量的記錄。

我的第二個想法是,子查詢正在放慢速度,我應該將它們轉換爲連接。但是我無法在連接條件中使用聚合函數max,那麼如何才能獲得連接中的最大行?

感謝

+0

您正在使用什麼版本的SQL Server?如果您使用2005+,我會發布更快的CTE版本 – Hogan 2011-04-09 17:53:54

+0

您應該提供查詢計劃/成本分析以及任何優化查詢的幫助請求。請參閱http://infocenter.sybase.com/help/topic/com.sybase.infocenter.dc00976.1502/html/statistics/statistics25.htm – eevar 2011-04-09 18:31:09

+0

@Hogan - 使用Sybase,但感謝您花時間提供答案。 – dmck 2011-04-09 18:40:47

回答

2

我猜測,在SELECT子句中的2個相關子查詢不執行,直到返回的行。一般而言,相關的子查詢應該避免,因爲它們往往很慢,當然總會有例外!

嘗試移動聯繫人電話和聯繫人電子郵件到加入的子查詢中。

SELECT 
    cc.Id, 
    c.Name, 
    ... , 
    cc.LastName, CustomerContacts.FirstName, 
    cp.LastModified PhoneLastModified 
    ce.LastModified EmailLastModified 
FROM 
    CustomerContacts cc 
LEFT OUTER JOIN 
    Customer c 
ON 
    c.ID = cc.CustomerId 
INNER JOIN 
    (SELECT 
     ContactId, 
     max(LastModified) as LastModified 
    FROM 
     ContactPhone 
    WHERE 
     LastModified > '2011-01-01' 
    GROUP BY 
    ContactId) cp 
ON 
    cp.ContactID = cc.ID 
INNER JOIN 
    (SELECT 
     ContactId, 
     max(LastModified) as LastModified 
    FROM 
     ContactEmail 
    WHERE 
     LastModified> '2011-01-01' 
    GROUP BY 
    ContactId) ce 
ON 
    ce.ContactID = cc.ID 
+0

Typo - 在select語句中有兩個名爲EmailLastModified的字段:D – Hogan 2011-04-09 18:04:06

+0

@Hogan,很好發現:) – 2011-04-09 18:05:54

+0

這個工作,看起來像你正確的關於select語句中的子查詢 – dmck 2011-04-09 18:44:25

1

我現在看到他使用SYBASE沒有SQL服務器(TSQL可能是因爲存在),但我會離開其他人誰正在使用的MS產品的答案。

這是CTE版本。作品同保羅的版本,但稍微容易閱讀:

WITH MaxContactPhone AS 
(
    SELECT max(LastModified) as LastModified, ContactID 
    FROM ContactPhone 
    WHERE LastModified> '2011-01-01' 
    GROUP BY ContactID 
), MaxContactEmail AS 
(
    SELECT max(LastModified) as LastModifed, ContactID 
    FROM ContactEmail 
    WHERE LastModified> '2011-01-01' 
    GROUP BY ContactID 
) 
SELECT CustomerContact.Id, Customer.Name, ... , CustomerContacts.LastName, 
     CustomerContacts.FirstName, 
     MaxContactPhone.LastModified as PhoneLastModified, 
     MaxContactEmail.LastModified as EmailLastModified 
    FROM CustomerContacts 
    LEFT OUTER JOIN Customer ON Customer.ID = CustomerContact.CustomerId 
    JOIN MaxContactPhone ON CustomerContact.CustomerId = MaxContactPhone.ContactID AND 
    JOIN MaxContactEmail ON CustomerContact.CustomerId = MaxContactEmail.ContactID 
+0

CTE的任何地方都支持sybase,但不支持ASE,我想,雖然不確定。 – 2011-04-09 18:09:38

+0

不確定ASE是什麼? – Hogan 2011-04-09 18:17:48

+0

Adaptive Server Enterprise,sybase的一個版本 – 2011-04-09 18:23:40

0
SELECT cc.ID, cu.Name, ... 
    , cc.LastName, cc.FirstName 
    , g.PhoneLastModified 
    , g.EmailLastModified 
    FROM CustomerContacts cc 
    LEFT JOIN Customer cu 
     ON cu.ID = cc.CustomerID 
    JOIN 
     (SELECT cc.ID 
      , max(cp.LastModified) 
       AS PhoneLastModified 
      , max(ce.LastModified) 
       AS EmailLastModified 
      FROM CustomerContacts cc 
      LEFT JOIN ContactPhone cp 
       ON cp.ContactID = cc.ID 
      LEFT JOIN ContactEmail ce 
       ON ce.ContactID = cc.ID 
      GROUP BY cc.ID 
      HAVING (PhoneLastModified > '2011-01-01' 
        OR EmailLastModified > '2011-01-01') 
    ) AS g 
     ON g.Id = cc.id 
+0

這會給出錯誤。 – Hogan 2011-04-10 01:16:01

+0

@霍根:什麼是錯誤? – 2011-04-10 07:07:58

+0

類似cc.LastName和cc.FirstName的東西不包含在GROUP BY子句或加重的目標中。 – Hogan 2011-04-10 09:47:04