我编写了一个大约需要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
只需要验证代码是否可以更有效地编写..
答案 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)
用您的ColumnNames Select * from Pledge
替换*。它应该像是
的 Select Instrument_Id from Pledge
强>
排除Cursor的使用。
您是否在Pledge
和Unpledge
表中有唯一记录,如果是,则应使用UNION ALL
。因为它与UNION
在All_Share_Txn
中插入Local Temporary Table
的记录。
创建另一个Local Temporary table
,其中包含基于Instrument_Id列和Instrument_Id
的字段“总数量”信息。现在评估基于Switch案例的条件,并在此表中插入数量信息的记录。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。
创建另一个Local Temporary table
,其中包含基于Instrument_Id列和Instrument_Id
的字段“免费数量”信息。现在评估基于Switch案例的条件,并在此表中插入Free Qty
信息的记录。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。
创建另一个Local Temporary table
,其中包含基于Instrument_Id列和Instrument_Id
的字段'Pledge_Quantity'信息。现在评估基于Switch案例的条件并插入记录
for Pledge_Quantity
此表中的信息。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。
创建另一个Local Temporary table
,其中包含基于Instrument_Id列和Instrument_Id
的字段'Avg_rate'信息。现在评估基于Switch案例的条件并插入记录
for Avg_rate
此表中的信息。请注意,在提取此上下文的信息时,请使用步骤3中创建的本地临时表。
现在,在步骤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实例的一些基本设置:
tempdb应该具有与拥有内核相同数量的文件,所有相同的大小和使用MB的所有相同增长率,而不是%。如果你有超过8个核心,我最多只能有8个文件。进行更改后重新启动实例;你确实有,但我推荐它。
示例:12个核心。
tempdb.mdf size= 1024MB growby= 256MB
tempdb2.ndf size= 1024MB growby= 256MB
(etc)
tempdb8.ndf size= 1024MB growby= 256MB
与您的数据库相同。如果您需要添加更多文件,然后使用建议的大小设置并重建所有聚簇索引,这将在文件中传播数据,因为它将重建数据的物理结构。
不要让SQL Server占用所有内存!将其限制设置为total_avail_phys_memory减去2GB(保留O / S的内存量很大)
不要只使用PRIMARY FILE GROUP;将数据和索引分离到自己的文件组中。如果可以,请将索引放在RAID 10驱动器上,将数据放在RAID 5或6上。
确保您通过维护计划或滚动自己的脚本为SQL Server用户数据库提供所需的维护。
RAID 5上的数据,RAID 10上的日志,RAID 10上的Tempdb - 每个LUN(驱动器号)应该有专用的主轴(驱动器)
我希望这些建议有用,如果它们对实例的整体性能有任何帮助。