4

3,000 万行のデータベースがあります。PK クラスター化インデックスは、生成されたコードGUIDです。

表は次のとおりです。

CREATE TABLE [dbo].[events](
    [imageEventGUID] [uniqueidentifier] NOT NULL,
    [imageSHAID] [nvarchar](256) NOT NULL,
    [queryGUID] [uniqueidentifier] NOT NULL,
    [eventType] [int] NOT NULL,
    [eventValue] [nvarchar](2050) NULL,
    [dateOfEvent] [datetime] NOT NULL,
 CONSTRAINT [PK_store_image_event] PRIMARY KEY CLUSTERED 
(
    [imageEventGUID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

簡単に言えば、画像検索エンジンです。

  • imageEventGUIDはコード固有の識別子です。
  • imageSHAID画像 URL の SHA256 です。
  • queryGUIDコードで生成された FK です (簡潔にするために create ステートメントから除外されます)。
  • eventTypeイベントの種類に割り当てられた番号です
  • eventValue通常、画像の URI です。たとえば、" http://mywebpage.com/images/image123456789.jpg "です。

かなり標準的なコードを使用して、定期的に via SqlBulkCopy(from a ) をこのテーブルに挿入します。DataTable

using (SqlBulkCopy bulk = new SqlBulkCopy(storeConn, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls, null))
{
    bulk.DestinationTableName = "[dbo].[events]";
    bulk.WriteToServer(myeventsDataTable);
}

通常、1 回の一括挿入で 5k から 10k 行を挿入しようとしています。この一括コピーの挿入結果がひどいです。私はこの DB を SSD (SATA 1 のみが接続されている) で実行していましたが、非常に高速でした (500 ミリ秒未満)。SSD の空き容量がなくなったので、DB を 1TB 7200 キャッシュ回転ディスクに交換しました。完了時間が 120 秒 (120000 MS) を超えているためです。一括挿入が実行されているとき、約 1MB/秒のディスク アクティビティが見られ、CPU 使用率が低いことがわかります。

このテーブルには、PK 以外のインデックスはありません。

あなたへの私の質問は次のとおりです。

これを引き起こす原因となる、私が間違っていることは明らかですか?

「あなたの回転するディスクは、このサイズのDBには十分な速度ではありません」という単なるケースですか?

このデータの挿入で正確に何が起こっているのでしょうか? クラスター化されたインデックスであるため、挿入時にディスク上のデータ ページを再配置しますか? 本質的に順序付けされていない GUID を挿入しようとしているため、この「ランダムな挿入の性質」により、読み取り/書き込みヘッダーがディスク上の別のページに頻繁に移動する可能性がありますか?

御時間ありがとうございます。

4

4 に答える 4

6

私の推測では、主な問題はクラスター化インデックスの選択です。クラスター化インデックスは、テーブル内の物理的な順序またはレコードを決定します。PK は Guid であるため (順次ではなくランダムに生成されると想定しています)、データベースは各行を適切な場所に挿入する必要があります。これは、2 つの既存のレコードの間にある可能性が高く、ページの分割や断片化などを引き起こす可能性があります。

SSD と磁気ドライブのほうが高速である理由については、私は専門家ではありませんが、データの編成方法により、SSD の方が断片化プロセスが高速である可能性があります。I/O スループットは高速になりますが、それほど大きくはありません。

GUID の代わりに数値の自動インクリメント主キーを使用できる場合は、一括挿入がはるかに高速になります。GUID 列に一意のインデックスを作成して、クエリを高速化することもできます。

于 2013-08-08T15:24:37.537 に答える
1

GUIDクラスター化された主キー自体はひどく悪い設計上の選択であるため、説明については、Kim Tripp のブログ投稿GUIDs as PRIMARY KEYs および/または clustering keyを参照してください。ランダム (クライアント側で生成)GUIDを使用すると、非常に高い (多くの場合 99% 以上) 断片化が発生し、大量の行を一括挿入する過程で、非常にコストのかかる操作である大量のページ分割が発生します。

それを変更できない場合は、少なくとも、ひどい断片化値を持つクラスター化インデックスが毎晩再構築されていることを確認できます。余裕があれば、さらに頻繁に再構築されます。

また、GUID列を (クラスター化されていない) 主キーとして保持し、新しいINT IDENTITY列を導入してクラスター化キーとして使用することもできます。それだけでも、非常にランダムな GUID がクラスター化インデックスで引き起こす途方もない断片化を排除することで、すでにかなりの効果があると確信しています。

于 2013-08-08T15:52:49.080 に答える