基本的な問題は、データがロードされるにつれて挿入率が低下することです。
- PK 以外のすべてのインデックスを無効にしました
- FK 制約を無効にしました。
- 挿入する前に、LINQ を使用して PK でデータを並べ替えました
しかし、挿入速度は依然として低下しています。
ロード中はユーザー数が制限されます。だからPKを倒すことはできません。
データは PK の順序でロードされますが、そのインデックスはまだフラグメント化されています。
Int、TinyInt、String の複合 PK。
読み込みが 100% のフィル ファクターでインデックスを再構築する前。テーブルには、無効になっている別のインデックスが 1 つあります。
現在、20,00 行がテーブルにロードされているため、PK インデックスには既に 4% の断片化があります。断片化し続け、読み込み速度が低下します。DBCC SHOWCONTIG ('docMVtext', 'PK_docMVtext') で断片化をチェックします。
- スキャンされたページ.................................................................155
- スキャンされたエクステント................................................................................. 26
- エクステント スイッチ.................................................................: 25
- 平均 エクステントあたりのページ................................................: 6.0
- スキャン濃度 [ベストカウント:実際のカウント].......: 76.92% [20:26]
- 論理スキャンの断片化 ................................: 4.52%
- エクステント スキャン フラグメンテーション ................................: 96.15%
- 平均 1 ページあたりの空きバイト数.................................................: 54.9
- 平均 ページ密度 (フル).................................................: 99.32%
Extent Scan Fragmentation が高いので、2 つ目の質問をする必要があるかもしれません。
int tinyint にのみ PK があり、同じ問題に苦しんでいる姉妹テーブル docSVtext があるため、PK の一部としての varchar(600) 値ではないと思います。
バックアップ復元を介して別のデータベースからこのデータベースを作成しました。同じ構成テーブルが必要でしたが、同じデータ テーブルは必要ありませんでした。データ テーブルからデータを削除し、shrinkdb TRUNCATEONLY を実行しました。
挿入値 ()、()、() を使用して値をロードします。
おそらく値 ()、()、() が順序を変更していると考えたため、.NET を行ごとに 1 つの挿入に変更し、PK の順序で挿入されたデータでも PK で断片化が発生しました。
データが PK の順序で挿入されていることを 3 回確認します。
.NET アプリでは、挿入前に LINQ を使用してデータを並べ替えています。デバッグで 40 を確認したところ、すべて適切にソートされていました。
IDEN を使用してミラー テーブルを作成し、同じ 3 つの列を作成しました。そのミラー テーブルで同じ挿入を使用して、挿入順序を検証しました。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 でこの断片化を取得するための初期ロードの違いがわかりません。
信じられないかもしれませんが、主要なボトルネックは最初のテーブルにありました。
以下の最初のコードは、テーブルに 300,000 行ある 2 番目のコードよりも 10 倍高速です。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());
}