SQL查询性能改进

时间:2014-07-18 07:38:55

标签: sql performance query-optimization

我需要优化查询。我有两张桌子:

  • tblcardCardID int, SerialNumber varchar(15), clientID

  • tblTransactionTransactionID 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分钟)。你对如何优化它有什么想法吗?

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

可能错过了一些索引。执行计划可以澄清这一点。