SQL Server 中的插入速度真的很慢
Posted
技术标签:
【中文标题】SQL Server 中的插入速度真的很慢【英文标题】:Insert rate really slow in SQL Server 【发布时间】:2017-04-28 21:32:15 【问题描述】:在向表中插入 200 万行时,我需要帮助。我插入的表有 40 亿行,我插入的表有 200 万行。插入速率约为每分钟 190 行。
DECLARE @BatchSize INT = 5000
WHILE 1 = 1
BEGIN
INSERT INTO [dbo].[a] ([a].[col1], [a].[col2], [a].[adate], [a].[importdate])
SELECT TOP(@BatchSize)
b.col1,
b.col2,
b.adate,
b.importdate
FROM
b
WHERE
NOT EXISTS (SELECT 1
FROM dbo.[a]
WHERE [a].col1 = b.col1
AND [a].col2 = b.col2
AND [a].adate = b.adate)
--AND [sent].aDate > getdate()-10)
IF @@ROWCOUNT < @BatchSize BREAK
END;
在上面的查询中,在表a中,col1和col2和col3是主键(Non-clustered)。我想从表 b 中插入表 a 中的每条记录...
表 a 有 3 个索引,一个是 col1.col2,第二个是 col1,col2,col3,第三个是 col1 ......
任何人都可以提供任何关于使其更快的想法吗?
我在 SQL Server 2008 R2 上有 128 Gb RAM。
谢谢
【问题讨论】:
我想你想要的是 MERGE() 两百万行,我会一批插入。 桌上有触发器吗?如果主键是 col1+col2+col3 你不能插入 dups 所以你不需要 not exists 子句。继续选择要插入的前 5000 行。我不明白 M. Ali 的建议。这将创建一个非常大的交易。 一个包含大量行和插入(以及删除/更新)的非聚集表最终会产生“无数”前向指针(非常低效的索引),这可能是问题所在。 嗨@benjamin 我试过不存在,它给了我重复键无法插入的错误......有什么想法可以克服吗? 【参考方案1】:由于您希望将B
中的所有行都插入A
,因此不需要使用exists
。问题变成跟踪先前批次中已经传输的行之一。以下示例生成一个行号并使用它来将行分组为批次。如果行号是按现有索引排序的,那么select
侧应该不需要排序传递。
-- Sample data.
declare @A as Table ( Col1 Int, Col2 Int );
declare @B as Table ( Col1 Int, Col2 Int );
insert into @B ( Col1, Col2 ) values
( 1, 1 ), ( 1, 2 ), ( 1, 3 ), ( 1, 4 ), ( 1, 5 ),
( 2, 1 ), ( 2, 2 ), ( 2, 3 ), ( 2, 4 ), ( 2, 5 );
-- Rows to transfer in each batch.
declare @BatchSize as Int = 5;
-- First row to transfer in the current batch.
declare @BatchMark as Int = 1;
-- Count of rows processed.
declare @RowsProcessed as Int = 1;
-- Process the batches.
while @RowsProcessed > 0
begin
insert into @A ( Col1, Col2 )
select Col1, Col2
from ( select Col1, Col2, Row_Number() over ( order by Col1, Col2 ) as RN from @B ) as PH
where @BatchMark <= RN and RN < @BatchMark + @BatchSize;
select @RowsProcessed = @@RowCount, @BatchMark += @BatchSize;
select * from @A; -- Show progress.
end;
替代方案包括向B
表添加一个标志列以标记已处理的行,使用B
表中的现有id
跟踪已处理的最大值,使用附加表跟踪索引值已处理的行,从B
中删除已处理的行,...。
output
子句可能对某些替代方案有用。
在传输数据之前使用合适的填充因子重建索引可能会有所帮助。见here。这取决于您的问题中没有的索引值的知识。
【讨论】:
嘿@habo 非常感谢您的回答,我试图获取索引的静态信息,但作为一个拥有 40 亿行的在线系统,每次我尝试检查 frag 之类的东西时索引。超时失败。还有一件事 。我可以删除 PK 并插入唯一记录并重新构建 PK .... 是个好选择吗? This 文章提供了一些有关重组和重建索引的附加信息。无论你做什么,都会有一个可观的价格。是否有一个开发数据库,其中包含您可以测试的最新数据副本?了解一下重建会造成的打击,以及它是否能让您更快地插入?确定合适的填充因子?以上是关于SQL Server 中的插入速度真的很慢的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server - 有啥方法可以加快插入 TVF 中的表变量的速度?