SQL Server - 减少读取次数

时间:2011-08-09 14:29:33

标签: sql sql-server tsql stored-procedures query-optimization

我有一个关于SQL Server优化的一般问题:如何减少存储过程中的读取次数?

我对以下的良好做法感兴趣: - 在物理和临时表中创建索引 - 使用临时表,而不是在程序中使用相同的表 - DML之前的DDL - 在存储过程开始时设置NOCOUNT ON - ......

由于存储过程引起的大量读取而导致使用的磁盘空间存在问题,我需要对其进行优化。

“最贵”的存储过程的一部分是:

create table #stavke   
(  
    Id_Br int identity(1, 1), IDStavke int, 
    HeaderID int, Currency varchar(3),  GLAcct varchar(20), id varchar(20), Trnuid varchar(60), 
    ReferenceID varchar(20), DocumentID varchar(20),
    DtAvail varchar(10), DtBooking varchar(10), DatePosted varchar(10),
    Amount money, AmountLcl money, 
    Description varchar(250), Type varchar(10), DP int  )
insert into #stavke   
  (  
    IDStavke, HeaderID, GLAcct, Currency, id , Trnuid , 
    ReferenceID, DocumentID ,
    DtAvail , DtBooking , DatePosted,
    Amount , AmountLcl , 
    Description , Type , DP 
  )  

SELECT S.ID as IDStavke,
   z.RB as HeaderID,  
   z.KONTO AS GLAcct,
   z.OZNVAL AS Currency,
   Si.BROJNALOGA as ID,
   D.TRN as Trnuid, 
   case substring(SI.BROJNALOGA,1,4)
        when '0746' then O.REFERENCA
        when '1450' then D.REFERENCA
        when '0743' then L.REFERENCA
        when '2021' then N.REFERENCA
   end   ReferenceID,
   case substring(SI.BROJNALOGA,1,4)
        when '3000' then 'Kursna razlika'
        when '2200' then 'PP-'+SI.BROJNALOGA
        when '2201' then 'KDP-'+SI.BROJNALOGA
        else SI.BROJNALOGA
   end DocumentID,
   dvalute as DtAvail, 
   si.dknizenja as DtBooking, 
   '' as DatePosted,        
   case si.teret
        when 0 then si.korist
        else si.teret 
   end Amount, 
   case SI.DINTERET
        when 0 then si.dinkorist
        else si.dinteret 
   end AmountLcl, 
   '' as Description,
   case substring(SI.BROJNALOGA,1,4)
        when '0746' then '0746'
        when '1450' then '1450'
        when '0743' then '0743'
        when '2021' then  'Ostalo'
   end  Type,
   case SI.DINTERET
        when 0 then 1
        else -1 
   end DP
FROM       A I
inner join B st on i.transfer=st.transfer and i.partija=st.partija 
INNER JOIN C SI ON st.RB=Si.RB
inner join D z on z.rb=st.rb
inner join E s on z.rb=s.rb AND s.BROJNALOGA = si.BROJNALOGA 
LEFT JOIN  F D ON  D.BROJ=SI.BROJNALOGA
LEFT JOIN  G L ON L.BROJ=SI.BROJNALOGA
LEFT JOIN  H O ON O.BROJ=SI.BROJNALOGA
LEFT JOIN  I N ON N.BROJ=SI.BROJNALOGA 
WHERE I.novi_izvod=convert(int,@StatementNumber) AND i.PARTIJA=@Account 
ORDER BY I.PARTIJA,z.RB,SI.id, z.KONTO,z.OZNVAL, SI.DKNIZENJA

表B,G,H和I(我为此示例更改了表的实名以使其更易于阅读)非常大,即具有许多列和大量数据。

1 个答案:

答案 0 :(得分:5)

我希望你说的是通过一个程序来减少磁盘活动。

首先,您可以使用

对当前的IO活动进行基准测试
set statistics IO on;

掌握了这些信息并使用SET SHOWPLAN_ALL或XML获取执行计划,或者您可以使用ssms以符合人体工程学的方式获得相同的信息。您可以使用DTA进行基本调整。

尝试将SP作为一堆临时语句执行,并查看IO的重点并集中在该段上。有很多好的做法可能符合你的要求。