我需要优化查询。我有两张桌子:
tblcard
(CardID int, SerialNumber varchar(15), clientID
)
tblTransaction
(TransactionID int, SerialNumber Varchar(15), Transactiondate datetime, ...
)
我需要列出日期间隔所有参与交易的卡片,客户名称以及所有卡片的首次交易日期
以下是我所做的:
select
tra.serialNumber,
cli.clientName,
(select top 1 tra.Transactiondate
from tblTransaction tra
where tra.SerialNumber = car.SerialNumber
order by tra.TransactionDate)
from
tblTransaction tra
left join
tblCard car on car.SerialNumber = tra.SerialNumber
left join
tblClient cli on car.ClientID = cli.ClientID
where
--date conditions
但鉴于事务是非常多的事务,此查询运行速度非常慢(超过3分钟)。你对如何优化它有什么想法吗?
答案 0 :(得分:0)
执行计划会有所帮助。开箱即用,如果可能,将left
联接替换为inner
联接可能会有所帮助。从性能角度来看,使用子查询也是一个糟糕的想法。相反,您可能想要使用视图或CTE:
with LatestTransactions (SerialNumber, TransactionDate)
as
(
select
SerialNumber, max(TransactionDate) as TransactionDate
from tblTransaction
group by SerialNumber
)
select
tra.serialNumber,
cli.clientName,
lt.TransactionDate
from tblTransaction tra
left join LatestTransactions lt on lt.SerialNumber = tra.SerialNumber
left join tblCard car on car.SerialNumber = tra.SerialNumber
left join tblClient cli on car.ClientID = cli.ClientID
where
--date conditions
当然,如果你没有使用正确的指数,它可能没有多大帮助。这就是为什么查看查询执行计划很重要。查询花费时间在哪里?为什么?你能以合理的方式限制数据集吗?是否会在某些列帮助中引入新索引?你为什么加入序列号,这是一个15字符长的字符串,而不是一些标识列?
答案 1 :(得分:0)
Luaan,你的答案很好,这里有一个更具可读性(在我看来)的答案(更多的是缺少tblclient表)
select tblTransaction.TransactionDate, Mindate.SerialNumber, Mindate.TransactionDate
from tblTransaction
outer apply (select MIN(tra.Transactiondate) TransactionDate, car.SerialNumber
from tblTransaction tra
INNER JOIN tblCard car on car.SerialNumber = tra.SerialNumber
where car.SerialNumber = tblTransaction.SerialNumber group by car.SerialNumber) Mindate
where tblTransaction.TransactionDate between '2013-05-05' and '2014-05-05'
答案 2 :(得分:0)
尝试用DENSE_RANK
聚合(oracle语法)替换子查询:
select
tra.serialNumber,
cli.clientName,
MIN(tra.Transactiondate)
KEEP (DENSE_RANK FIRST ORDER BY tra.TransactionDate)
OVER (PARTITION BY tra.SerialNumber) AS transactiondate
from
tblTransaction tra
left join
tblCard car on car.SerialNumber = tra.SerialNumber
left join
tblClient cli on car.ClientID = cli.ClientID
where
--date conditions
可能错过了一些索引。执行计划可以澄清这一点。