开发者

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 ta开发者_如何转开发king around 20-30 seconds to retrieve approximately 5000 rows. 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. 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?

  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.

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?

Thanks


I'm guessing that the 2 correlated subqueries in the select clause don't execute until the rows are returned. 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.

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.

Here is the CTE version. Works the same as Paul's version but slightly easier to read:

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜