这是一个两部分问题,但首先是一些背景信息:
我在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一对一。
现在我的问题:
为什么Sybase报告的执行时间为0.328秒,但实际上需要接近30秒来检索查询中的行?
如何优化此查询?
我的第一个想法是为LastModified列添加索引,但我正在处理少量记录。
我的第二个想法是,子查询正在减慢速度,我应该将它们转换为连接。但是我不能在Join条件中使用聚合函数max,那么如何才能获得我的join中的最大行?
由于
答案 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