“ピボットベースのクエリの実行時間をスケーリングおよび改善する方法に関するアドバイス10億行のテーブルで、1日に100万を増やす
-
05-07-2019 - |
質問
当社は、テキストファイルを解析する内部プロジェクトを開発しています。 これらのテキストファイルは、通常の表現を使用して抽出されたメタデータで構成されます。 10台のコンピューターが24時間年中無休でテキストファイルを解析し、抽出されたメタデータをハイエンドのIntel Xeon SQL Server 2005データベースに送信しています。
簡略化されたデータベーススキーマは次のようになります。
Items | Id | Name | |----|--------| | 1 | Sample |
Items_Attributes | ItemId | AttributeId | |--------|-------------| | 1 | 1 | | 1 | 2 |
Attributes | Id | AttributeTypeId | Value | |----|-----------------|-------| | 1 | 1 | 500mB | | 2 | 2 | 1.0.0 |
AttributeTypes | Id | Name | |----|---------| | 1 | Size | | 2 | Version |
内部には個別のメタデータを持つ多くの個別のテキストファイルタイプがあります。すべてのテキストファイルには Item
があり、抽出されたすべてのメタデータ値には Attribute
。
があります
Items_Attributes
を使用すると、重複する Attribute
値を回避でき、データベースサイズがx ^ 10増加することを回避できます。
この特定のスキーマにより、新しい正規表現を動的に追加し、新しい内部ファイルの構造に関係なく、新しい処理済みファイルから新しいメタデータを取得できます。
さらに、これにより、ユーザーの条件に基づいてデータをフィルタリングし、動的レポートを取得できます。 Attribute
でフィルタリングし、結果セットをピボットします( http://msdn.microsoft.com/en-us/library/ms177410.aspx )。したがって、この例の疑似SQLクエリ
SELECT FROM Items WHERE Size = @A AND Version = @B
このようなピボットテーブルを返します
| ItemName | Size | Version |
|----------|-------|---------|
| Sample | 500mB | 1.0.0 |
アプリケーションは数か月間実行されており、使用できなくなった時点でパフォーマンスが大幅に低下しました。レポートの所要時間は2秒以内で、Items_Attributes
テーブルは週に平均10,000,000行増加します。
すべてが適切にインデックス付けされ、クエリ実行プランの分析と最適化に多大な時間を費やしました。
では、レポートの実行時間を短縮するために、これをどのようにスケーリングしますか?
次の解決策がありました:
- ハードウェアを追加購入し、SQL Serverクラスターをセットアップします。 (適切な「クラスタリング」戦略に関するアドバイスが必要です)
- HBaseのようなキー/値データベースを使用します(問題が解決するかどうかはわかりません)
- RDBMSではなくODBMSを使用します(db4oを検討しています)
- ソフトウェアをクラウドに移行します(経験はゼロです)
- 実行時に統計的にレポートを生成します。 (私たちは本当にしたくない)
- 一般的なレポートの静的インデックス付きビュー(パフォーマンスはほぼ同じです)
- スキーマの非正規化(レポートの一部には、1回のクエリで最大50個のテーブルが含まれます)
解決
おそらく、Entity-Attribute-Valueデータベースモデルの落とし穴に関するSQL Server CATチームによるこのホワイトペーパーが役立ちます。 http://sqlcat.com/whitepapers/archive/2008/09/03/best-practices- for-semantic-data-modeling-for-performance-and-scalability.aspx
他のヒント
正確なテーブルメタデータ(インデックス作成の詳細とともに)、正確なクエリテキスト、および実行計画の投稿から始めます。
現在のテーブルレイアウトで、次のようなクエリ:
SELECT FROM Items WHERE Size = @A AND Version = @B
(Size、Version)
で複合インデックスを使用してもメリットはありません。そのようなインデックスを作成することは不可能だからです。
attributes
の自己結合を含むため、インデックス付きビューを作成することさえできません。
おそらく次のようにテーブルを非正規化するのが最良の決定でしょう。
id name size version
(size、version)
このようなスキーマを長時間使用しました。彼らは決してうまくいきません。 最良の方法は、必要なデータを次の形式で保存することです。
| ItemName |サイズ|バージョン| | ---------- | ------- | --------- | |サンプル| 500mB | 1.0.0 |
それから、ピボットする必要はありません。ところで、元のEAVスキーマを「正規化」と呼ばないでください。 -正規化されていません。
OLTPトランザクション用に最適化されたデータベースでOLAPクエリを発行するように思えます。詳細がわからない場合は、別の「データウェアハウス」を構築することをお勧めします。実行しているクエリの種類に最適化されています。それには、データの集約(可能であれば)、非正規化、および1日ほど前のデータベースも含まれます。毎日または任意の間隔でデータを増分更新します。
正確なDDLとインデックスを投稿してください。ID列にインデックスがある場合、クエリはスキャンになります
このようなものの代わりに
SELECT FROM Items WHERE Size = @A AND Version = @B
これを行う必要があります
SELECT FROM Items WHERE ID = 1
つまり、テキスト値を取得し、インデックスを作成するIDを見つけて、クエリとして使用して結果を返す必要があります
おそらく、データを配信するためのパーティション関数を調べることもお勧めです
クラスタリングはパフォーマンスではなく可用性のために行われます.1つのノードが死んだ場合(アクティブクラスター)、他のノード(パッシブクラスター)がアクティブになります....もちろんアクティブなアクティブクラスタリングもありますが、それは別の話です
短期的な修正として、水平分割。最大のテーブルは Items_Attributes
であると想定しています。このテーブルを水平方向にパーティション分割し、各パーティションを個別のディスクコントローラ上の個別のファイルグループに配置できます。
これは、すべての ItemId
を一度にレポートしようとしていないことを前提としています。
1つのクエリで50個のテーブルに言及します。 SQLサーバーは単一のモノリシッククエリで最大256のテーブルをサポートしますが、このアプローチを採用すると、オプティマイザーが効率的なプランを作成する可能性が低くなります。
現在のスキーマに夢中になっている場合は、レポートクエリを一連の手順に分割して、結果を一時(#)テーブルに具体化することを検討してください。 このアプローチにより、クエリの最も選択的な部分を分離して実行でき、私の経験では、パフォーマンスが大幅に向上します。一般に、クエリのメンテナンス性も高くなります。
また(これは少し長めのショットですが)、どのSQLサーバーのバージョンを使用しているのかはわかりません。しかし、SQL 2005を使用している場合、レポートに含まれるテーブルの数とデータの量を考えると、SQLサーバーが少なくともSP2にパッチされていることを確認する価値があります。
数億の行カウントを持つテーブルを使用してETLプロジェクトに取り組みましたが、SQL 2005 RTM / SP1のクエリオプティマイザーは、5つ以上のテーブルを結合するクエリの効率的な計画を一貫して作成できないことがわかりましたテーブルはこの規模でした。この問題はSP2で解決されました。