【问题标题】:Why do I get high fragmentation when using SqlBulkCopy to move large amounts data between databases?为什么使用 SqlBulkCopy 在数据库之间移动大量数据时会出现高碎片?
【发布时间】:2016-05-17 15:48:27
【问题描述】:

使用代码

Using bcp As New SqlBulkCopy(destConnection)
     bcp.DestinationTableName = "myOutputTable"
     bcp.BatchSize = 10000

     bcp.WriteToServer(reader)
End Using

其中 reader 本质上是一个 IDataReader,它读取包含 200k 行左右的表。

输入表是这样的

CREATE TABLE [dbo].[MyTable](
    [TagIndex] [SMALLINT] NOT NULL,
    [TimeStamp] [DATETIME] NOT NULL,
    [RawQuality] [SMALLINT] NOT NULL,
    [ValQuality] [SMALLINT] NOT NULL,
    [Sigma] [REAL] NULL,
    [Corrected] [REAL] NULL,
    [Raw] [REAL] NULL,
    [Delta] [REAL] NULL,
    [Mean] [REAL] NULL,
    [ScadaTimestamp] [DATETIME] NOT NULL
) ON [PRIMARY

并按时间戳排序。

输出表结构相同,索引如下(流程开始时为空)。

CREATE CLUSTERED INDEX [MyOutputTable_Index] ON [dbo].[MyOutputTable]
(
    [TimeStamp] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

人为地限制一次将少量(ish)数据运行到输出表(大约

但是如果我在更大的块中运行,比如 45k,(或者让进程运行整个 200k),碎片会变成 99%+。

准确地说,如果我在 39,773 中运行,我得到

FileId  PageId  Row Level   ChildFileId ChildPageId TimeStamp (key)
1       18937   0   1       1           18906       2015-10-22 01:37:32.497
1       18937   1   1       1           18686       2015-10-22 01:38:12.497
1       18937   2   1       1           18907       2015-10-22 01:38:47.497
1       18937   3   1       1           18687       2015-10-22 01:39:27.497
1       18937   4   1       1           18908       2015-10-22 01:40:02.497
1       18937   5   1       1           18688       2015-10-22 01:40:42.497
1       18937   6   1       1           18909       2015-10-22 01:41:17.497
1       18937   7   1       1           18689       2015-10-22 01:41:57.497
1       18937   8   1       1           18910       2015-10-22 01:42:32.497

查看 ChildPageId 列,我们可以看到数字不是连续的。

例如,18906 之后是 18686,然后是 18907,以 18686 开头的系列与以 18906 开头的系列交错,导致超过 99% 的碎片。

那么,问题是在更大的数据块中运行时,是什么导致索引这样构建?

【问题讨论】:

    标签: sql sql-server indexing sqlbulkcopy


    【解决方案1】:

    如果没有更多数据,这很难说,但我敢打赌,您的时间戳是聚集索引会导致这种情况。在发送到输出表之前尝试按此字段对数据进行排序。

    【讨论】:

    • 您还可以将其批量加载到临时表中并在那里排序,然后再将其插入实际表中。
    【解决方案2】:

    对于任何对此问题的结果感兴趣的人。

    我发现碎片是由表中重复数量不定引起的。

    为了解释,作为 NON-UNIQUE 中的索引是可能的,并且确实是时间戳重复的情况。但是,如果这些组的大小都相同,例如,每个时间戳有 7 行始终贯穿文件,那么完成时碎片将小于 1%。但是,如果表的可变性更大,那么碎片会迅速增加。例如,如果有数据块,其中每个时间戳有 7 行,那么一些有 6 行,一些有 5 行等碎片将超过 99%,我们看到这种交错(如问题中所述)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-04
      • 2023-04-07
      • 2016-11-29
      相关资源
      最近更新 更多