基本问题是加载数据时插入率会下降。
但插入速度仍在下降。
在加载期间,用户数量有限。所以不能取下PK。
数据按PK的顺序加载,但该索引仍然存在碎片。
Int,TinyInt,String的复合PK。
在加载重建索引之前,填充因子为100%。该表有另一个被禁用的索引。
现在有20,00行加载到表中,PK索引已经有4%的碎片。它继续碎片和加载速度恶化。使用DBCC SHOWCONTIG('docMVtext','PK_docMVtext')检查碎片
范围扫描碎片很高,也许我应该打开第二个问题。
我认为它不是作为PK的一部分的varchar(600)值,因为有一个姐妹表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());
}
答案 0 :(得分:1)
由于这是一个用于初始化的批量插入,我建议删除表中的所有索引。通过这样做,您可以尽快将数据导入服务器。之后,在数据加载完成后应用PK和非聚簇索引。 Sql server将能够同时处理所有数据的重新排列,而不是每次达到给定页面的填充因子。