And*_*bka 4 performance sql-server insert sql-server-2014
我正在开发一个具有将表格数据导出到指定数据库表的功能的应用程序。该应用程序使用INSERT
语句将其数据导出到目标数据库。
插入是通过一个批处理INSERT
语句完成的,每个 SQL 语句有 100 行INSERT
(现在我不能使用BULK INSERT
或bcp
)。
我注意到,当源数据中的列数超过某个数字(该数字不是固定的,取决于值的大小、每个中的行数INSERT
等)时,导出时间会不成比例地增加。
例如,导出 50 000 行(500 条INSERT
语句,每条语句 100 行)的随机字符串,每个字符串有 100 个字符,每个INSERT
需要100 行:
3 秒,5 列 6 秒,10 列 56 秒,15 列 77 秒,20 列
请注意 10 列和 15 列之间的导出时间差异。我原以为 15 列的导出时间为 9-10 秒,但实际上要长 5 倍。在测试其他数据集的导出时,我发现了类似的性能下降。
为了确保问题不在我这边,我INSERT
通过sqlcmd.exe
. 我得到了类似的结果。
问题:如何让 SQL Server 像处理小列一样快速处理大量列?或者至少将性能下降的点“移动”到更多的列?
额外细节:
INSERT
查询是在本地 SQL Server Express 2014(64 位)版本 12.0.5000.0 上执行的;INSERT
语句都包含在一个事务中(我尝试COMMIT
在 each 之后调用INSERT
,但结果几乎相同);sqlservr.exe
期间,进程的磁盘写入速度是后两次情况下的 10 倍。表是这样创建的:
CREATE TABLE [Test_Table]
(
[Column 1] VARCHAR(255),
[Column 2] VARCHAR(255),
[Column 3] VARCHAR(255),
[Column 4] VARCHAR(255),
[Column 5] VARCHAR(255)
)
Run Code Online (Sandbox Code Playgroud)
数据看起来像这样(每个单元格实际上包含 100 个字符的长字符串,同一行中的所有字符串都相等):
+------------+------------+------------+------------ --+------------+ | [第1栏] | [第2栏] | [第3栏] | [第4栏] | [第5栏] | +------------+------------+------------+--------- --+------------+ | R6YZ..uWaQ | R6YZ..uWaQ | R6YZ..uWaQ | R6YZ..uWaQ | R6YZ..uWaQ | | DMNW..Kh0a | DMNW..Kh0a | DMNW..Kh0a | DMNW..Kh0a | DMNW..Kh0a | | GKbg..yuap | GKbg..yuap | GKbg..yuap | GKbg..yuap | GKbg..yuap | | pG+f..64bX | pG+f..64bX | pG+f..64bX | pG+f..64bX | pG+f..64bX | | O2Q7..fTNF | O2Q7..fTNF | O2Q7..fTNF | O2Q7..fTNF | O2Q7..fTNF |
以下是重现该问题的两个示例:
http://rextester.com/OZI56670(10列,~0.09 秒)
http://rextester.com/HLAP4972(11列,~0.45 秒)
您发布的 10 列 100 行和 11 列 100 行的再现之间的区别在于,第一个的执行计划使用Simple Parameterization。
10 列的实际执行计划列出了从@1
到 的参数@1000
。
11 * 100
是1100
。但是一千似乎是自动参数化查询可以达到的最大参数数。
您正在为每个插入 10 次。在 10 列的情况下,计划可以编译一次并重新用于其他 9 个插入。在 11 列的情况下,每个插入语句都需要单独编译。
此外,当 SQL Server 需要查看文字值时,编译过程需要更长的时间,因为它花费时间计算组的属性(或者至少曾经是这种情况,我不确定这是否在最近的版本中发生了变化)。