sql >> データベース >  >> RDS >> Sqlserver

大きなテーブルでのSQLServerクエリのパフォーマンスを向上させる

    簡単な答え:いいえ。クラスター化インデックスのフィルファクターが50%の238列のテーブルに対するアドホッククエリを支援することはできません。

    詳細な回答:

    このトピックに関する他の回答で述べたように、インデックスのデザインは芸術と科学の両方であり、ハードで高速なルールがあったとしてもごくわずかであると考える要素がたくさんあります。考慮する必要があります:DML操作とSELECT、ディスクサブシステム、テーブル上の他のインデックス/トリガーの量、テーブル内のデータの分散、SARGable WHERE条件を使用したクエリ、および私が正しく覚えていない他のいくつかのこと今。

    テーブル自体、そのインデックス、トリガーなどを理解しないと、このトピックに関する質問に役立つことはできないと言えます。これで、テーブル定義を投稿できました(まだインデックスを待っていますが、テーブル定義だけがポイントしています問題の99%)私はいくつかの提案を提供することができます。

    まず、テーブルの定義が正確である場合(238列、50%フィルファクター)、ここでの残りの回答/アドバイスはほとんど無視できます;-)。ここでは政治的ではないことを残念に思いますが、真剣に、それは詳細を知らずに野生のガチョウの追跡です。そして、テーブル定義が表示されたので、テストクエリ(更新#1)が非常に高速に実行された場合でも、単純なクエリに時間がかかる理由がかなり明確になりました。

    ここでの(そして多くのパフォーマンスの悪い状況での)主な問題は、悪いデータモデリングです。 999のインデックスを持つことが禁止されていないのと同じように、238の列も禁止されていませんが、一般的にはあまり賢明ではありません。

    推奨事項:

    1. まず、このテーブルは実際に改造する必要があります。これがデータウェアハウステーブルである場合は多分ですが、そうでない場合は、これらのフィールドを実際にはいくつかのテーブルに分割する必要があります。これらのテーブルはすべて同じPKを持つことができます。マスターレコードテーブルがあり、子テーブルは一般的に関連付けられた属性に基づく依存情報であり、これらのテーブルのPKはマスターテーブルのPKと同じであるため、マスターテーブルへのFKも同じです。マスターテーブルとすべての子テーブルの間には1対1の関係があります。
    2. ANSI_PADDING OFFの使用 時間の経過とともにさまざまな列が追加されたために、テーブル内で一貫性がないことは言うまでもありません。今すぐ修正できるかどうかはわかりませんが、理想的には常に ANSI_PADDING ONを使用します。 、または少なくともすべての ALTER TABLEで同じ設定にする ステートメント。
    3. テーブルとインデックスの2つの追加ファイルグループを作成することを検討してください。自分のものをPRIMARYに入れないのが最善です これは、SQLSERVERがオブジェクトに関するすべてのデータとメタデータを格納する場所です。 [Tables] でテーブルとクラスター化インデックス(テーブルのデータ)を作成します および[Indexes]のすべての非クラスター化インデックス
    4. フィルファクターを50%から増やします。この低い数値は、インデックススペースがデータスペースよりも大きい理由である可能性があります。インデックスの再構築を行うと、データに使用される最大4k(合計8kページサイズのうち)でデータページが再作成されるため、テーブルが広範囲に分散されます。
    5. ほとんどまたはすべてのクエリのWHEREに「ER101_ORG_CODE」が含まれている場合 条件を確認してから、それをクラスター化インデックスの先頭の列に移動することを検討してください。 「ER101_ORD_NBR」よりも頻繁に使用されると仮定します。 「ER101_ORD_NBR」がより頻繁に使用される場合は、それを保持します。フィールド名が「OrganizationCode」と「OrderNumber」を意味すると仮定すると、「OrgCode」は複数の「OrderNumbers」を含む可能性のあるより適切なグループ化であるように思われます。
    6. マイナーポイントですが、「ER101_ORG_CODE」が常に2文字の場合は、 CHAR(2)を使用してください。 VARCHAR(2)の代わりに 可変幅のサイズを追跡し、数百万を超える行を合計する行ヘッダーに1バイトを保存するためです。
    7. ここで他の人が言及しているように、 SELECT *を使用します パフォーマンスが低下します。 SQL Serverがすべての列を返す必要があるため、他のインデックスに関係なくクラスター化インデックススキャンを実行する可能性が高いだけでなく、SQLServerがテーブル定義に移動して* すべての列名に。 少し SELECTで238列すべての名前を指定する方が速い リストしますが、それはスキャンの問題には役立ちません。しかし、とにかく、238列すべてを同時に必要とすることはありますか?

    頑張ってください!

    更新
    「アドホッククエリの大きなテーブルのパフォーマンスを向上させる方法」という質問を完全にするために、この特定のケースでは役に立たないものの、誰かがSQLServer2012を使用している場合は注意が必要です。 (またはその時点で新しい)テーブルが更新されていない場合は、列ストアインデックスを使用するオプションがあります。この新機能の詳細については、http://msdn.microsoft.com/en-us/library/gg492088.aspxを参照してください(これらはSQL Server 2014以降で更新可能になっていると思います)。

    アップデート2
    その他の考慮事項は次のとおりです。

    • クラスター化インデックスの圧縮を有効にします。このオプションはSQLServer2008で利用可能になりましたが、EnterpriseEditionのみの機能として利用可能になりました。ただし、SQLServer2016の時点でSP1 、データ圧縮はすべてのエディションで利用可能になりました!行とページの圧縮の詳細については、データ圧縮のMSDNページを参照してください。
    • データ圧縮を使用できない場合、または特定のテーブルにあまりメリットがない場合は、固定長タイプ( INT )の列がある場合 、 BIGINT TINYINT SMALLINT CHAR NCHAR BINARY DATETIME SMALLDATETIME MONEY など)、行の50%以上が NULL 、次に SPARSEを有効にすることを検討してください SQL Server 2008で利用可能になったオプション。詳細については、MSDNページの「スパース列の使用」を参照してください。


    1. SQL ServerのFORMAT()でサポートされている標準の日付/時刻形式の文字列

    2. Oracle-XMLTYPE:値を更新する方法

    3. PLSQLプロシージャを使用してOracleのCSVファイルにデータをエクスポートする方法

    4. MySQLの区切り文字