基本问题是插入率随着数据的加载而下降。
- 禁用所有索引,但 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 的镜像表。在该镜像表上使用相同的插入来验证插入顺序。当我在按 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());
}