web-dev-qa-db-ja.com

非常に大きなテーブルでクエリとBCPを高速化する

この質問はこれにいくらか続きます: SQL Serverの巨大なデータとパフォーマンス ですが、独自の質問に値するほど十分に異なります。読みやすくするために、この質問のテキストの一部をここにコピーして貼り付けます。

非常に大量のレコードを収集して保存するSQL Serverバックエンドを使用したアプリケーションを作成しました。ピーク時の平均レコード数は、1日あたり30億から40億(20時間の運用)の平均のどこかにあると計算しました。

私のアプリケーションはデータを受け取り、それを10万件以下のレコードのバッチに分割し、BCP対応のステージングファイルを作成してサーバーに移動し、SQL ServerはBCPを使用してデータを実稼働テーブルに移動します。このソリューションにより、BCPファイルのバックログがほとんどまたはまったくなく、52億行を実稼働テーブルに正常に移動できました。 SQLエージェントジョブとしてBCPを継続的に実行しています。

私のプロダクションテーブルには次のスキーマがあります。

_CREATE TABLE [dbo].[SignalValues](
    [Timestamp] [datetime] NOT NULL,
    [SignalId] [uniqueidentifier] NOT NULL,
    [SignalValue] [nvarchar](4000) NULL,
    [SignalValueId] [uniqueidentifier] NOT NULL
)
_

レコード量が多いため、テーブルは_[Timestamp]_から_2016-01-20 21:00:00.000_まで30分ごとに_2016-06-15 08:00:00.000_に分割されます。 (合計パーティション数約11,000)。

私の問題は2つあります。

  1. なんらかの方法でテーブルをクエリするには何年もかかります。
  2. クエリがテーブルに対して実行されている間、BCP処理は基本的に停止します。それはすべての処理能力がクエリに行き、ファイルのバックログを取得するようなものです。

クエリのパフォーマンスを向上させるにはどうすればよいですか?ユーザーは主に_[Timestamp]_とSignalIdに基づいてクエリを実行します。 _[Timestamp]_で非クラスター化インデックスを作成しましたが、それほど高速化されていないようです。適用するインデックスが多いほど、BCP挿入が遅くなり、ファイルバックログが作成されるようです。インデックスの提案はありますか?

パーティションについての私の仮定は、内部ではそれらが個別のテーブルとして機能するため、_[Timestamp]_に対して_2016-01-25 22:01:00.000_をクエリする場合、クエリに必要な1つのパーティションのみをロックし、他のパーティションはロック解除したままにすることです。私の仮定は間違っていますか?上記の2)に見られる動作では、そのように見えます。 SELECTクエリ中にSQL Serverを強制的にロックしないようにするにはどうすればよいですか(WITH (READPAST)およびWITH (NOLOCK)は役に立ちませんでした)?

このテーブルの行は更新または削除されることはありません。また、アプリケーションが行のタイムスタンプとしてデータセットをアプリケーションに提供する内容によっては、過去のある時点からデータが挿入される可能性があります。残念なことに、私がクレイジーマジックを実行しなければ、パーティションの切り替えの可能性はすべてなくなります。

パーティションごとの平均行数は約7000万です。

前の質問(上記)からのフィードバックに基づいて、サーバーを大幅に強化することができました。以下は、私のサーバーのシステム情報です。

Info

また、フィードバックに基づいてSQL Serverを次のように構成しました。

  • すべてのデータベース関連ファイルは、SANに接続されており、ファイバーチャネルを介してシステムに接続されています)
  • 私のデータベースのデータファイルは、それ自体のドライブだけにあります-4つの回転ディスクのRAID 10アレイ
  • tempdbは6つのファイル(論理プロセッサの数の半分)で構成され、それぞれサイズが512MBで、すべて1つのドライブ上にあります-2つの回転するディスクのRAID 0アレイ
  • すべてのトランザクションログは、独自のドライブ(2つの回転ディスクのRAID 1アレイ)に存在します。

テーブルにクラスター化インデックスがありません。以前にクラスター化された一意のインデックス(PK)を使用していましたが、一意性の制約により、800m行のテーブルで100kレコードの挿入に10分かかりました。私の理解では、クラスター化インデックスは、見出しごとに一意性制約を内部的に作成していました。「重複する値を持つ列にクラスター化インデックスを作成できますか?」このページから:

14のSQL Serverインデックス作成の質問は恥ずかしがり屋でした

しかし、私は完全に間違っている可能性があります。

何か不足している場合はお知らせください。

4
Brandon

これは長いショットですが、SQL 2014 Enterpriseを実行しているので、このテーブルでクラスター化列ストアインデックスを使用してテストし、パフォーマンスが向上するかどうかを確認します。

特に、選択と一括挿入のみにテーブルを使用していることを考慮してください-更新と削除はありません。

回転するディスクから少し負荷を取り、CPU /メモリの方に移動するという追加の利点があります。

1
Lawrage

データ入力(1秒あたり+ 50k行を受け入れる)の両方で任意のEAV時系列をクエリするアドホッククエリの両方で優れているものを見つけるのは難しいでしょう(timestmapsignal_idsignal_value)。クラスター化列ストアを試してみます。クラスター化列ストアはtimestampセグメントの削除 を利用し、クラスター化列ストアは一括挿入の同時実行特性も優れています。 SQL Serverクラスター化列ストアタプルムーバー を読んで、直接圧縮されたセグメントを作成するのに十分な高BCPレートを達成してください。そうでない場合は、ステージング、ステージングでのbcp + rebuild、およびパーティション切り替えはである必要があります

あなたが持っているレイアウトでは、timestampにクラスター化インデックスを付ける方がはるかに好ましいでしょう。今のところ、あなたの最善の希望は パーティションの削除 を活用することです。これが誤作動する可能性のある方法はたくさんあります( なぜパーティション消去が機能しないのですか? )。それが機能しても、同時実行性の問題が発生します。特に、ユーザークエリはほとんどの場合recentデータに関係するため、これによりBCP挿入がブロックされます。

私のBPCがテーブルXロックにエスカレートしないことを確認します。 データロードパフォーマンスガイド は必須の読みですが、列ストアに関してはホワイトペーパーが時代遅れであるため、現在の構造にのみ適用されることに注意してください。 「パーティションテーブルの一括読み込み」の章に特に注意してください。

より粗いパーティション分割の細分性、おそらく1日あたり1つのパーティションを検討します。パーティションが多すぎると、実行時にかなりのコストがかかります。

そして、パフォーマンスの問題と同様に、 メジャー です。

根本的に異なるアプローチを検討することに恥ずかしがらないでしょう。 Cassandra たとえば、データを非常に高い速度で入力でき、「問題のあるハードウェアを増やす」スケールアウトソリューションの利点があります。クエリ可能性はCassandraの強みではありませんが、そのエコシステムを購入すると、Spark + Hive + ORC/Parquetがあり、これらはデータを非常に高速にクエリできます。

1
Remus Rusanu
  • なんらかの方法でテーブルをクエリするには何年もかかります。

  • クエリがテーブルに対して実行されている間、BCP処理は基本的に停止します。それはすべての処理能力がクエリに行き、ファイルのバックログを取得するようです。

  • クエリのパフォーマンスを向上させるにはどうすればよいですか?

  • このテーブルの行は更新または削除されることはありません。また、過去のある時点からデータが挿入された可能性もあります

最初に、クラスター化インデックスのいくつかの組み合わせを試してください-一意ではないクラスター化インデックスです。

2番目に、膨大な量のデータを処理することになります。nvarcharが絶対に必要でなく、必要もない場合は、varcharに変更して、多くのスペースと時間を節約してください。

3番目に、メインテーブルのデータが更新も削除もされず、ファイルの内容全体を一度に取得するかどうかを気にしない場合(チャンクが示すように)、すべてのクエリをREADに移動することを検討してください。 UNCOMMITTED/WITH(nolock)、とにかく更新ステートメントがないため。

4番目に、各BCPファイルのロードが新しいステージングテーブルを作成し、埋めることを検討してください。 BCPをメインテーブルから離してください。これらを後で別の物理ディスクのセットに分散して、複数のBCP操作を並行して実行することもできます。 BCPが完了した後のsp_renameによって、またはいくつかの制御/ログテーブル(ファイルUyiからテーブルX102で開始、終了したテーブルX102、X102に移動)のいずれかによって、これらのステージングテーブルに「準備完了」信号を入れる必要があります。メイン、X102ドロップなど)。

ETA:5番目に、利用可能なリソースがあるようです-RAMは素晴らしいものでした。tempdbがメインテーブルとは別のディスク上にあり、ステージングテーブルがその上にあることを確認してください。独自の独立したディスクも所有しています。おそらく、tempdbとそれらのBCPステージングテーブルの両方にいくつかのソリッドステートディスクを配置して、費用を制限する必要があります。予算があれば、もちろんすべてのソリッドステートです。少なくともtempdbの場合は、 SAN SSDではなくローカルSSDを使用できます-同じ費用で高速であり、ほとんどの場合tempdbを複製する必要はありません。

0