需要查询优化建议

时间:2012-05-15 14:00:44

标签: sql-server-2008 query-optimization

我编写了一个大约需要15个小时才能执行的脚本。我需要一些查询优化技术或建议,以使这个脚本尽可能快... 如果有人可以提供帮助,请查看脚本:

declare @max_date date
declare @client_bp_id int

Select @max_date=MAX(tran_date) from All_Share_Txn

DELETE FROM Client_Share_Balance

DECLARE All_Client_Bp_Id CURSOR FOR
SELECT Bp_id FROM  Client       --Take All Client's BPID 
    OPEN All_Client_Bp_Id
    FETCH NEXT FROM All_Client_Bp_Id
        INTO @client_bp_id
    WHILE @@FETCH_STATUS = 0
    BEGIN

    Insert Client_Share_Balance(Bp_id,Instrument_Id,Quantity_Total,Quantity_Matured,Quantity_Pledge,AVG_Cost,Updated_At,Created_At,Company_Id,Created_By,Updated_By)
    select @client_bp_id,Instrument_Id,
       sum(case when Is_buy='True' then Quantity when Is_buy='False'  then -quantity end), --as Total Quantity
       sum(case when Mature_Date_Share <= @max_date then (case Is_buy when '1' then quantity when '0' then -quantity end) else 0 end),  --as Free Qty
       ISnull((select sum(case pu.IsBuy when '1' then -pu.quantity else pu.quantity end) from
            (Select * from Pledge UNION Select * from Unpledge) pu
                where pu.Client_Bp_id=@client_bp_id and pu.Instrument_Id=t1.Instrument_Id and pu.Txn_Date<=@max_date
                group by pu.Client_Bp_id,pu.Instrument_Id),0),  -- as Pledge_Quantity
       dbo.Avg_Cost(@client_bp_id,Instrument_Id), --as Avg_rate
       GETDATE(),GETDATE(),309,1,1

    from All_Share_Txn t1
    where Client_Bp_id=@client_bp_id and Instrument_Id is not null 
    group by Instrument_Id
    having sum(case Is_buy when '1' then quantity when '0' then -quantity end)<> 0
    or sum(case when Mature_Date_Share <= @max_date then (case Is_buy when '1' then quantity when '0' then -quantity end) else 0 end) <> 0

    FETCH NEXT FROM All_Client_Bp_Id
        INTO @client_bp_id

END

CLOSE All_Client_Bp_Id
DEALLOCATE All_Client_Bp_Id

只需要验证代码是否可以更有效地编写..

3 个答案:

答案 0 :(得分:2)

如果我理解你的代码。光标是代码中的瓶颈。所以我会跳过光标并执行以下操作:

Insert Client_Share_Balance(Bp_id,Instrument_Id..)
select Client_Bp_id,
......
from All_Share_Txn t1
where EXISTS(SELECT NULL FROM Client WHERE Client_Bp_id=t1.Bp_id) 
and Instrument_Id is not null 
group by Instrument_Id,Client_Bp_id
.......

答案 1 :(得分:2)

  1. 用您的ColumnNames Select * from Pledge 替换*。它应该像是 的 Select Instrument_Id from Pledge

  2. 排除Cursor的使用。

  3. 您是否在PledgeUnpledge表中有唯一记录,如果是,则应使用UNION ALL。因为它与UNION

  4. 相比更快
  5. All_Share_Txn中插入Local Temporary Table的记录。

  6. 创建另一个Local Temporary table,其中包含基于Instrument_Id列和Instrument_Id的字段“总数量”信息。现在评估基于Switch案例的条件,并在此表中插入数量信息的记录。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。

  7. 创建另一个Local Temporary table,其中包含基于Instrument_Id列和Instrument_Id的字段“免费数量”信息。现在评估基于Switch案例的条件,并在此表中插入Free Qty信息的记录。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。

  8. 创建另一个Local Temporary table,其中包含基于Instrument_Id列和Instrument_Id的字段'Pledge_Quantity'信息。现在评估基于Switch案例的条件并插入记录 for Pledge_Quantity此表中的信息。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。

  9. 创建另一个Local Temporary table,其中包含基于Instrument_Id列和Instrument_Id的字段'Avg_rate'信息。现在评估基于Switch案例的条件并插入记录 for Avg_rate此表中的信息。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。

  10. 现在,在步骤3,4,5,6,7中创建的表格之间加入了Joins。您可以立即获得结果集。

答案 2 :(得分:0)

除非您关心您正在读取COMMITTED数据,否则您可以告诉SQL Server按原样查看数据,而不对对象保持任何锁定...基本上与WITH(NOLOCK)相同,但Microsoft建议不要使用对象提示并让SQL Server决定使用的最佳锁定方法。没有“担心”提交或不提交数据,这大大加快了获取数据的速度。

将此添加到查询顶部

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED - 设置在连接级别,而不是一次性的事情 GO

See this link TRANSACTION ISOLATION LEVEL

接下来,请检查您的唯一ID列是否包含Clustered Indexes。如果它们只有唯一的约束,那么仍然会留下堆而不是表。堆基本上是散乱的混乱。 (你可能知道这些东西,只提一下)接下来,确保你在WHERE ORDER BY GROUP HAVING中使用的所有列都有非聚集索引,并包含经常返回的列;这会占用更多的磁盘空间。如果您使用的是Enterprise Edition或更高版本,请使用压缩索引和表。

我会在表上运行UPDATE STATISTICS WITH FULLSCAN,为SQL Server提供最新,最好的统计信息。重建聚簇索引将顺便为您执行此操作,并且您还可以告知仅更新数据统计信息以帮助加快此过程,因为如果您的表是数百万行,可能需要一段时间。

您正在考虑的最大性能影响是您正在对汇总结果进行分组。 SQL Server将使用工作表进行扫描,排序......一切都在寻求索引,所有这些都是因为没有索引用于帮助你的GROUP BY,HAVING等。

有时候我们别无选择,但有一些技巧,比如创建一个#temporary表(或表对象,是的,你可以在两者上创建索引)并用预先计算的结果填充它,确保这个#临时表可以加入。使用ORDER BY,GROUP BY,HAVING时,除非使用列或多列并使用SUM或标量值用户定义函数之类的聚合,否则它将变慢 - 取决于您定义为慢的:)但是你说你认为它应该更快。

要查看任何SQL Server实例的一些基本设置:

  1. tempdb应该具有与拥有内核相同数量的文件,所有相同的大小和使用MB的所有相同增长率,而不是%。如果你有超过8个核心,我最多只能有8个文件。进行更改后重新启动实例;你确实有,但我推荐它。

    示例:12个核心。

    tempdb.mdf      size= 1024MB   growby= 256MB
    tempdb2.ndf  size= 1024MB   growby= 256MB
    (etc)
    tempdb8.ndf size= 1024MB   growby= 256MB
    
  2. 与您的数据库相同。如果您需要添加更多文件,然后使用建议的大小设置并重建所有聚簇索引,这将在文件中传播数据,因为它将重建数据的物理结构。

  3. 不要让SQL Server占用所有内存!将其限制设置为total_avail_phys_memory减去2GB(保留O / S的内存量很大)

  4. 不要只使用PRIMARY FILE GROUP;将数据和索引分离到自己的文件组中。如果可以,请将索引放在RAID 10驱动器上,将数据放在RAID 5或6上。

  5. 确保您通过维护计划或滚动自己的脚本为SQL Server用户数据库提供所需的维护。

  6. RAID 5上的数据,RAID 10上的日志,RAID 10上的Tempdb - 每个LUN(驱动器号)应该有专用的主轴(驱动器)

  7. 我希望这些建议有用,如果它们对实例的整体性能有任何帮助。