web-dev-qa-db-ja.com

SQL Server 2008での挿入が遅い

当社のデータベースには、監査証跡表が含まれています。

CREATE TABLE gn_AuditTable(
  gn_ObjectId int NULL,
  gn_Action smallint NULL,
  gn_Time datetime NULL,
  gn_UserId int NULL,
  gn_Login varbinary(16) NULL,
  gn_ExtraObjectId int NULL,
  gn_ExtraInfo int NULL
) ON [PRIMARY]

単純なinsertステートメントを使用して、このテーブルに行を追加します-ストアドプロシージャはありません。

insert into gn_AuditTable (
  gn_ObjectId,gn_Time,gn_UserId,gn_Login,gn_Action,gn_ExtraObjectId,gn_ExtraInfo
) values (
  ?,?,?,?,?,?,?
)

列の値をパラメーターとしてクエリに渡します。トリガーもありません。

問題は、この挿入が非常に遅い場合があることです。場合によっては30秒以上かかり、タイムアウトします。

同じ製品の複数のインストールがあり、すべてではなく一部で問題が発生しています。

監査テーブルは非常に大きくなる可能性があり、最大で数百万行になります。非常に遅い挿入は、大きなテーブル(当然のことながら)を持つデータベースで発生します-しかし、正常に実行される行数が同程度のデータベースが他にもあり、問題が発生しているデータベースでも断続的に発生します。ほとんどの場合、挿入はかなり高速です( 1秒未満)。

テーブルには、6つのクラスター化されていない一意でないインデックスがあります。

  • gn_Login;

  • gn_ObjectId;

  • gn_Actionおよびgn_ExtraInfo;

  • gn_ExtraObjectId;

  • gn_Time;

  • gn_UserId

これらのすべてのインデックスがあると問題が発生する可能性がありますが、繰り返しになりますが、どこにでも同じインデックスがあり、どこか/ときどき問題が発生します。

ユーザーが1人だけのテストデータベースで少なくとも1回は挿入のタイムアウトが発生したため、問題は全体的な負荷ではなく、挿入とテーブル自体に関連しているようです。

以前はgn_ObjectIdにクラスター化インデックスがありましたが、この問題を解決するための試みとしてそれを取り除きました。 gn_ObjectIdはシーケンシャルではないため、クラスター化インデックスには適さないと考え、SQL Serverが挿入時に行を並べ替えるようにしました。おそらくgn_Time-それは常に増加しています-はより良い選択でしょう。

「自然に」一意の列または列の組み合わせがないため、主キーはありません。id列を追加する必要があり、オーバーヘッドのように見えます。

問題を診断するために私たちが何を見ることができるかについて誰かが何か提案がありますか?断続的に非常に時間がかかる可能性があるinsertとは何ですか?

5
MiMo

問題が見つかりました:

  • gn_AuditTableの行を含む、データベースからデータを削除するメンテナンス手順があります。

  • delete gn_AuditTable . .が他のステートメントと一緒にトランザクションに含まれている(悪い)

  • 大量の行が一度に削除される-このような場合、SQL Serverはテーブル全体をロックします-そして、トランザクションが完了するのを待つinsert gn_AuditTableタイムアウト

これは、タイムアウトになったときにロックを確認でき、テーブルロックに気付いたためです。 delete gn_AuditTable . . .をトランザクションの外に移動し、テーブルロックをトリガーしないように、トランザクションをより小さなバッチに分割することができます。

gn_Timeにクラスター化インデックスとインスタントファイル初期化を実装しています。どちらもこの特定の問題とは関係なく有益です-ありがとうございます。

1
MiMo

なぜクラスタ化インデックスがないのですか?なぜ主キーがないのですか?

これはおそらくあなたの問題です:テーブルへのorderがありません(たとえば、IDENTITY列の意味で)これはあなたですヒープに挿入する

見る

更新後に編集します。

一意でないクラスター化インデックスを使用するには、重複するgn_ObjectIdエントリごとに niquifier(DBA.seリンク) が必要です。これは適切なクラスタリングキーではありません。

  • 数値
  • 単調増加
  • 狭い

また、IDENTITYカラムを試していないと思います...?試して、報告してください。

編集2、@ JNKが言うように、書き込みはディスク上でどのように管理されるかにより、この状況ではID列はオーバーヘッドにはなりません。

11
gbn

データベースは十分な大きさですか? INSERTが自動拡張をトリガーしないことを確認しますか?展開で Instant File Initialization が有効になっていない場合、これはまさにデータベースファイルの増加がトリガーされたときに予想される動作です。ファイルの増加と初期化の間、書き込みがランダムにブロックされます。ログファイルの増加が発生している可能性もあります(これは、少なくとも Log Growths パフォーマンスカウンターを確認することで迅速に特定できます)。ただし、ログの増加が発生するには、単純でない復旧モデルと基本的に存在しないバックアップ戦略(つまり、ログの切り捨ては発生しません)。

テーブルの設計に関しては、ほとんどのクエリは時間範囲をカバーするため(たとえば、「過去3日間のすべてのイベントを選択する」)、gn_Timeおそらく一意でないクラスター化キー候補。

6
Remus Rusanu