SQL查询执行时间很快,但获取行的速度很慢

时间:2011-04-09 17:43:48

标签: sql database tsql database-design sybase

这是一个两部分问题,但首先是一些背景信息:

我在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. 如何优化此查询?

  3. 我的第一个想法是为LastModified列添加索引,但我正在处理少量记录。

    我的第二个想法是,子查询正在减慢速度,我应该将它们转换为连接。但是我不能在Join条件中使用聚合函数max,那么如何才能获得我的join中的最大行?

    由于

3 个答案:

答案 0 :(得分:2)

我猜测在返回行之前,select子句中的2个相关子查询不会执行。一般来说,应该避免相关的子查询,因为它们往往很慢,当然总有例外!

尝试将ContactPhone和Contact Email移动到已连接的子查询中。

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

答案 1 :(得分:1)

我现在看到他正在使用SYBASE而不是SQL Server(也可能是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

答案 2 :(得分: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