0

我编写了一个脚本,执行大约需要 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

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

4

3 回答 3

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
.......
于 2012-05-15T14:08:49.273 回答
2
  1. 将 * 替换为您的 ColumnNames Select * from Pledge。它应该像
    Select Instrument_Id from Pledge

  2. 排除光标的使用。

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

  4. 插入All_Share_Txnin的记录Local Temporary Table

  5. 创建另一个Local Temporary table将基于 Instrument_Id 列和 具有“总数量”信息的字段Instrument_Id。现在评估基于 Switch case 的条件并在此表中插入 Quantity Information 的记录。请注意,当您为此上下文提取信息时,请使用在步骤 3 中创建的本地临时表。

  6. 创建另一个Local Temporary table将根据 Instrument_Id 列和Instrument_Id. Free Qty现在评估基于 Switch 案例的条件并在此表中插入信息记录。请注意,当您为此上下文提取信息时,请使用在步骤 3 中创建的本地临时表。

  7. Local Temporary table根据 Instrument_Id 列和.创建另一个将具有字段“Pledge_Quantity”信息的字段Instrument_IdPledge_Quantity现在评估基于 Switch 案例的条件并在此表中插入信息记录。请注意,当您为此上下文提取信息时,请使用在步骤 3 中创建的本地临时表。

  8. Local Temporary table根据 Instrument_Id 列和.创建另一个具有“Avg_rate”信息的字段Instrument_IdAvg_rate现在评估基于 Switch 案例的条件并在此表中插入信息记录。请注意,当您为此上下文提取信息时,请使用在步骤 3 中创建的本地临时表。

  9. 现在,借助在步骤 3、4、5、6、7 中创建的表之间的连接。您可以立即获得结果集。

于 2012-05-15T18:43:04.550 回答
0

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

将此添加到查询的顶部

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

请参阅此链接 事务隔离级别

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

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

您受到的最大性能影响是您对汇总结果进行分组这一事实。SQL Server 将扫描、使用工作表、排序……一切都在寻找索引,这一切都是因为没有索引可用于帮助您的 GROUP BY、HAVING 等。

有时我们在这件事上别无选择,但是有一些技巧,比如创建一个#temporary 表(或表对象,是的,你可以在两者上创建索引)并用预先计算的结果填充它,确保这个#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. 不要只使用主文件组;将您的数据和索引分开到它们自己的文件组中。如果可以,将索引放在 RAID 10 驱动器上,将数据放在 RAID 5 或 6 上。

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

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

我希望这些建议是有帮助的,如果它们对实例的整体性能有帮助的话。

于 2012-07-06T04:53:37.013 回答