2011-04-09 74 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