简体   繁体   English

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

[英]SQL Query execution time fast, but fetching rows is slow

This is a two part question, but first some background information: 这是一个两部分的问题,但首先是一些背景信息:

I have a TSQL query in Sybase that reports an execution time of 0.328 seconds, however its taking around 20-30 seconds to retrieve approximately 5000 rows. 我在Sybase中有一个TSQL查询,报告执行时间为0.328秒,但是检索大约5000行需要大约20-30秒。 The query has two subquery's and a left outer join. 该查询具有两个子查询和一个左外部联接。

The query looks roughly like this: 查询大致如下所示:

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')

What I am doing is selecting customer records based on the last modified date of any associated contact information. 我正在做的是根据任何关联的联系信息的最后修改日期选择客户记录。 ContactPhone and ContactEmail can contain x number of records for any given row in CustomerContact. ContactPhone和ContactEmail可以包含x个客户联系人中给定行的记录数。 The Customer table is one-to-one with CustomerContact. 客户表与客户联系人是一对一的。

Now my question: 现在我的问题是:

  1. How come Sybase reports an execution time of 0.328 seconds, but it's actually taking closer to 30 seconds to retrieve the rows in the query? Sybase为何报告执行时间为0.328秒,但实际上要花费近30秒才能检索查询中的行?

  2. What can I do to optimize this query? 我该怎么做才能优化此查询?

My first thought is to add indexes to the LastModified columns, but I'm dealing with a small number of records. 我的第一个想法是将索引添加到LastModified列中,但是我正在处理少量记录。

My second thought is that the subquery's are slowing things down, and that I should convert them into joins. 我的第二个想法是子查询正在减慢速度,因此我应该将它们转换为联接。 But I can't use the aggregate function max in the Join condition, so how do I get only the max row in my join? 但是我不能在Join条件下使用聚合函数max,那么如何在join中仅获取max行?

Thanks 谢谢

I'm guessing that the 2 correlated subqueries in the select clause don't execute until the rows are returned. 我猜想select子句中的2个相关子查询在返回行之前不会执行。 In general correlated subqueries should be avoided, as they tend to be slow, of course there are always exceptions! 通常,应避免使用相关的子查询,因为它们往往很慢,当然总会有例外!

Try moving ContactPhone and Contact Email into a joined subquery. 尝试将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

I see now he is using SYBASE not SQL Server (TSQL could be either), but I'll leave the answer for others who are using the MS product. 我现在知道他使用的是SYBASE而不是SQL Server(也可以是TSQL),但我将把答案留给其他正在使用MS产品的人。

Here is the CTE version. 这是CTE版本。 Works the same as Paul's version but slightly easier to read: 与Paul的版本相同,但更易于阅读:

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
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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM