关于方法论,我相信您在错误的b树;-)吠叫。
我们所知道的:
首先,让我们合并并回顾一下我们对情况的了解:
- 需要执行一些复杂的计算:
- 这需要在该表的每一行上发生。
- 该算法经常更改。
- 该算法... [使用]一些列中的值来操纵其他列
- 当前处理时间为:7小时
- 桌子:
- 应用程序后端:
- 数据库为SQL Server 2014企业版。
每行都有一个存储过程:
我们可以推测的是:
接下来,我们可以一起查看所有这些数据点,以查看是否可以综合其他细节来帮助我们找到一个或多个瓶颈,或者指向一个解决方案,或者至少排除一些可能的解决方案。
评论中的当前思路是,主要问题是SQL Server和Excel之间的数据传输。真的是这样吗?如果对800,000行中的每一行都调用了存储过程,并且每次调用(即每行)花费50毫秒,则总计为40,000秒(而不是ms)。这相当于666分钟(hhmm ;-),或刚刚超过11小时。但是据说整个过程只需要7个小时即可运行。我们已经花了整整4个小时的时间,甚至还增加了时间来进行计算或将结果保存回SQL Server。所以这里不对。
查看存储过程的定义,只有一个输入参数@FileID
;没有任何过滤器@RowID
。因此,我怀疑正在发生以下两种情况之一:
- 实际上,实际上并不是每行都调用此存储过程,而是每行调用一次
@FileID
,这似乎跨越了大约4000行。如果规定的4000行返回的金额相当一致,则在800,000行中只有200个分组。200次执行各耗时50毫秒,这仅相当于这7个小时中的10秒。
- 如果确实对每一行都调用了该存储过程,那么不会第一次
@FileID
传入新的消息花费更长的时间来将新行拉入缓冲池,但是接下来的3999次执行通常会更快,因为缓存了吧?
我认为,专注于此“过滤器”存储过程,或从SQL Server到Excel的任何数据传输都是一个红色的鲱鱼。
目前,我认为表现不佳的最相关指标是:
- 有80万行
- 该操作一次执行一次
- 该数据被保存回SQL服务器,因此“[用途]从一些列的值可以操纵其他栏目 ” [我的EM PHAS是;-)]
我怀疑:
- 尽管在数据检索和计算上还有一些改进的余地,但使这些数据变得更好并不能显着减少处理时间。
- 最大的瓶颈是发布80万条单独的
UPDATE
报表,即80万条单独的交易。
我的建议(基于当前可用信息):
您最大的改进领域是一次(即一次事务)更新多行。您应该更新您的流程,以便按照每个流程FileID
而不是每个流程来工作RowID
。所以:
- 将特定行的所有4000行读
FileID
入数组
- 数组应包含表示要操作的字段的元素
- 遍历数组,按当前方式处理每一行
- 一旦
FileID
计算完数组中的所有行(即针对此行):
- 开始交易
- 每个调用一次更新
RowID
- 如果没有错误,则提交事务
- 如果发生错误,请回滚并适当处理
如果尚未按定义聚集索引(FileID, RowID)
,则应考虑该问题(如@MikaelEriksson在对问题的评论中建议的那样)。它不会帮助这些单例UPDATE,但至少会稍微改善聚合操作,例如您在该“过滤器”存储过程中所做的操作,因为它们都基于FileID
。
您应该考虑将逻辑移至编译语言。我建议创建一个.NET WinForms应用程序甚至控制台应用程序。我更喜欢Console App,因为它很容易通过SQL Agent或Windows Scheduled Tasks进行计划。是否在VB.NET或C#中完成都无关紧要。VB.NET可能更适合您的开发人员,但是仍然会有一些学习过程。
我目前没有任何理由转向SQLCLR。如果算法经常更改,那将很烦人,必须一直重新部署Assembly。重建控制台应用程序并将.exe放置在网络上适当的共享文件夹中,这样您就可以运行相同的程序,并且它恰好始终是最新的,应该非常容易做到。
如果问题是我怀疑的,并且您一次只执行一次UPDATE,我认为将处理完全移到T-SQL中不会有帮助。
如果将处理移至.NET,则可以使用表值参数(UPDATE
TVP ),以便将数组传递到存储过程中,该存储过程将对TVP表变量调用JOIN并因此是单个事务。TVP应该比将4000 INSERT
s分组到一个事务中要快。但是,通过INSERT
1笔交易使用4000 s 以上的TVP带来的收益可能不会像将80万笔单独交易转移到200笔交易(每笔4000行)时看到的那样明显。
TVP选项不适用于VBA端,但是有人想出了一种值得测试的变通方法:
从VBA到SQL Server 2008 R2时,如何提高数据库性能?
如果仅FileID
在WHERE
子句中使用过滤器proc ,并且如果真的每行都调用proc,那么可以通过缓存第一次运行的结果并将其用于该行的其余行来节省一些处理时间FileID
,对?
一旦你获得了处理完成每写到FileID,那么我们就可以开始谈论并行处理。但这在那时可能没有必要:)。假设您要处理3个相当主要的非理想部分:Excel,VBA和800k事务,那么关于SSIS或平行四边形或谁知道什么的任何谈论都是过早的优化/先马后买。 。如果我们可以将这7小时的流程缩短到10分钟或更短的时间,您是否还在考虑其他方法以使其更快?您是否有目标完成时间?请记住,一旦对每个FileID完成处理 因此,如果您使用的是VB.NET控制台应用程序(即命令行.EXE),那么无论是通过SQL Agent CmdExec步骤还是Windows计划任务,都不会阻止您一次运行其中一些FileID :),等等
而且,您始终可以采用“分阶段”方法,并且一次进行一些改进。例如,从每个更新开始,FileID
因此对该组使用一个事务。然后,查看是否可以使TVP正常工作。然后查看有关获取该代码并将其移至VB.NET的知识(TVP在.NET中工作,因此可以很好地移植)。
我们不知道那仍然可以帮助您:
- “筛选器”存储过程是否按RowID或FileID运行?我们甚至拥有该存储过程的完整定义吗?
- 表的完整架构。这个桌子有几宽?有多少个可变长度字段?多少个字段可以为空?如果有任何可为NULL的值,那么有多少包含NULL?
- 该表的索引。它是分区的吗?是否使用ROW或PAGE压缩?
- 此表的MB / GB大小是多少?
- 该表如何处理索引维护?索引有多分散?统计信息如何更新?
- 这个7小时的过程正在进行时,是否还有其他过程写入该表?可能的争论来源。
- 这个7小时的过程正在进行时,是否还有其他过程从该表中读取?可能的争论来源。
更新1:
**关于什么是VBA(应用程序的Visual Basic)以及如何使用它,似乎有些困惑,因此,这只是为了确保我们都在同一个网页上:
更新2:
还有一点要考虑:如何处理连接?VBA代码是在每个操作中打开和关闭连接,还是在过程开始时打开连接并在过程结束时(即7小时后)关闭连接?即使使用连接池(默认情况下应为ADO启用),打开和关闭一次之间的影响仍然会相当大,而不是打开和关闭800,200或1,600,000次。这些值基于至少800,000个UPDATE加上200或800k EXEC(取决于实际执行过滤器存储过程的频率)。
我上面概述的建议自动缓解了连接过多的问题。通过创建一个事务并在该事务中执行所有UPDATE,您将保持该连接打开并为每个重用它UPDATE
。从最初的调用是否保持打开以获取每个指定的4000行的连接FileID
,还是在该“获取”操作之后关闭并为UPDATEs再次打开,连接的影响都较小,因为我们现在谈论的是两者之间的区别在整个过程中总共有200或400个连接。
更新3:
我做了一些快速测试。请记住,这是一个相当小规模的测试,而不是完全相同的操作(纯INSERT与EXEC + UPDATE)。但是,与连接和事务处理方式有关的时间差异仍然很重要,因此可以在此推断信息具有相对相似的影响。
测试参数:
- SQL Server 2012 Developer Edition(64位)SP2
表:
CREATE TABLE dbo.ManyInserts
(
RowID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
InsertTime DATETIME NOT NULL DEFAULT (GETDATE()),
SomeValue BIGINT NULL
);
操作方式:
INSERT INTO dbo.ManyInserts (SomeValue) VALUES ({LoopIndex * 12});
- 每次测试的插入总数:10,000
- 每个测试都会重置:(
TRUNCATE TABLE dbo.ManyInserts;
鉴于此测试的性质,执行FREEPROCCACHE,FREESYSTEMCACHE和DROPCLEANBUFFERS似乎并没有增加太多价值。)
- 恢复模型:简单(可能在日志文件中有1 GB的空闲空间)
- 使用事务的测试仅使用单个连接,而不管有多少事务。
结果:
Test Milliseconds
------- ------------
10k INSERTs across 10k Connections 3968 - 4163
10k INSERTs across 1 Connection 3466 - 3654
10k INSERTs across 1 Transaction 1074 - 1086
10k INSERTs across 10 Transactions 1095 - 1169
如您所见,即使已经在所有操作之间共享了到数据库的ADO连接,使用显式事务(ADO对象应该能够处理)将它们分组为批次也可以确保显着(即,提高2倍以上)减少整体处理时间。