【发布时间】:2012-08-09 08:38:22
【问题描述】:
基本问题是插入率随着数据的加载而下降。
- 禁用除 PK 之外的所有索引
- 禁用 FK 约束。
- 使用 LINQ 在插入前按 PK 对数据进行排序
但插入速度仍然在下降。
在加载期间有有限数量的用户。所以不能下PK。
数据按 PK 顺序加载,但该索引仍为碎片。
Int、TinyInt、String 的复合 PK。
在加载重建索引之前,填充因子为 100%。该表有另一个被禁用的索引。
现在表中加载了 20,00 行,PK 索引已经有 4% 的碎片。它继续碎片化并且加载速度恶化。使用 DBCC SHOWCONTIG ('docMVtext', 'PK_docMVtext') 检查碎片
- 已扫描的页面数................................................: 155
- 扫描的范围..........................:26
- 扩展开关..................................................: 25
- 平均每个范围的页数......................:6.0
- 扫描密度 [最佳计数:实际计数].......:76.92% [20:26]
- 逻辑扫描碎片......................:4.52%
- 范围扫描碎片......................:96.15%
- 平均每页可用字节数.....................:54.9
- 平均页面密度(完整)......................:99.32%
Extent Scan Fragmentation 很高,也许我应该提出第二个问题。
我不认为 varchar(600) 值是 PK 的一部分,因为有一个姐妹表 docSVtext 只有在 int tinyint 上有 PK 并且遇到同样的问题。
通过备份还原从另一个数据库创建此数据库。需要相同的配置表但不同的数据表。从数据表中删除数据并运行 shrinkdb TRUNCATEONLY。
使用插入值 ()、()、() 来加载值。
认为值 ()、()、() 可能正在更改顺序,因此将 .NET 更改为每行插入一个,即使按 PK 顺序插入数据,PK 上仍然会出现碎片。
三重检查数据是否按 PK 顺序插入。
在 .NET 应用程序中,我使用 LINQ 在插入之前对数据进行排序。在调试中,我查看了 40 个,它们都已正确排序。
甚至创建了一个具有相同三列的同名镜像表。在该镜像表上使用相同的插入来验证插入顺序。当我在按 iden 排序的镜像表上进行选择时,数据按排序顺序排列。这只是我插入按PK排序的数据的二次测试。
下面是表格定义。 (是的,我知道在第一段中没有 FK 约束,这显示了 FK 约束。当我删除 FK 约束时,对插入速度没有帮助。)
USE [Gabe2a_ENCORE]
GO
/****** Object: Table [dbo].[docMVtext] Script Date: 08/12/2012 20:13:35 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[docMVtext](
[sID] [int] NOT NULL,
[fieldID] [tinyint] NOT NULL,
[value] [varchar](600) NOT NULL,
CONSTRAINT [PK_docMVtext] PRIMARY KEY CLUSTERED
(
[sID] ASC,
[fieldID] ASC,
[value] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = ON, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[docMVtext] WITH CHECK ADD CONSTRAINT [FK_docMVtext_docFieldDef] FOREIGN KEY([fieldID])
REFERENCES [dbo].[docFieldDef] ([ID])
GO
ALTER TABLE [dbo].[docMVtext] CHECK CONSTRAINT [FK_docMVtext_docFieldDef]
GO
ALTER TABLE [dbo].[docMVtext] WITH NOCHECK ADD CONSTRAINT [FK_docMVtext_docSVsys] FOREIGN KEY([sID])
REFERENCES [dbo].[docSVsys] ([sID])
GO
ALTER TABLE [dbo].[docMVtext] CHECK CONSTRAINT [FK_docMVtext_docSVsys]
GO
让我感到困惑的是,在这个初始加载之后,我解析和索引文本以创建一个简单的全文搜索索引。为了加载这些表,我在内存中使用相同的排序策略并按 PK 的顺序插入,在那里我得到 PK 的零碎片。我无法弄清楚在 PK 上获得这种碎片的初始负载有什么不同。
我知道人们不会相信这一点,但主要瓶颈在第一张桌子上。
下面的第一个代码比第二个代码快 10 倍,表中有 300,000 行。第一个在 160 万行时快 30 倍。一开始就为我使用草率的@@identity 服务。
SQLcmd.CommandText = commandText + "; SELECT SCOPE_IDENTITY() ";
sID = int.Parse((SQLcmd.ExecuteScalar().ToString()));
SQLcmd.CommandText = commandText;
rowsRet = SQLcmd.ExecuteNonQuery();
if (rowsRet == 1)
{
commandText = "select @@identity from [docSVsys]";
SQLcmd.CommandText = commandText;
sID = int.Parse(SQLcmd.ExecuteScalar().ToString());
}
【问题讨论】:
-
您是要批量加载数据以初始化表,还是将批量插入作为正常表使用的一部分?
-
这是一个专门的数据加载步骤。使用插入值 (),(),()。该程序一次解析一个文本文件,然后插入与该行关联的行。输入太大,无法将整个输入解析到内存中。我需要输入文件中的一行来作为一个整体成功失败。
标签: tsql indexing sql-server-2008-r2