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

SQL Serverの内部:問題のあるオペレーターPt。 I –スキャン

    SQL Serverは約30年以上前から存在しており、私はSQLServerをほぼ同じくらい長い間使用してきました。 Kalenは、SQL Server内部のパート1:問題のあるオペレーターでスキャンについて説明しています。

    私はこの素晴らしい製品の何年にもわたって(そして何十年にもわたって!)そしてバージョンの多くの変化を見てきました。これらの投稿では、SQL Serverの機能や側面のいくつかを、時には歴史的な視点とともにどのように見ているかを紹介します。

    SQL Serverクエリの調整は、SQLServer診断のパフォーマンスと最適化を向上させるために実行できる最善の方法の1つです。しかし、チューニングは大きなトピックです!可能な限り最良の方法で調整する方法を正確に知るには、データとワークロードについての完全な知識だけでなく、SQLServerが実際に計画の実行を選択する方法についての知識が必要です。では、SQL Server Internalsの専門家でない場合は、どうすればよいでしょうか。あなたができることの一つは、専門家である人々と専門家によって書かれたツールに頼ることです。 Quest Spotlight Cloud Tuning Packのようなツールは、クエリのパフォーマンスを向上させるための道を始めるためのいくつかの優れた提案を提供します。もちろん、外部ツールがデータとすべてのワークロードのすべての詳細を認識しているわけではないため、実装することを決定した提案を徹底的にテストすることを常にお勧めします。

    問題のある演算子に関するこれらの投稿では、SQLServerのインデックス構造に関する基本的な知識があることを前提としています。役立つ情報は次のとおりです。

    • クラスター化されたインデックスのないテーブルはヒープと呼ばれ、順序はありません。最初の行も最後の行もありません。ヒープは、特定の順序ではない行の集まりです。
    • クラスター化インデックスのリーフレベルは、テーブル自体です。 (これはテーブルのコピーではなく、テーブルです。)インデックスの行は、クラスター化インデックスキーとして定義された列によって論理的に順序付けられます。
    • 非クラスター化インデックスのリーフレベルには、テーブル内のすべての行のインデックス行が含まれます。行には非クラスター化キー列が含まれ、キーが指定された順序で論理的に順序付けられます。キー列に加えて、非クラスター化インデックス行には、テーブル内の参照された行を指す「ブックマーク」が含まれています。ブックマークは、次の2つの形式のいずれかになります。
      1. テーブルにクラスター化されたインデックスがある場合、ブックマークはクラスター化されたインデックスキーです。 (クラスター化されたインデックスキーが非クラスター化されたインデックスキーの一部である場合、複製されません。)
      2. テーブルがヒープの場合、ブックマークは行ID、つまりRIDであり、行の物理的な場所を指定します。場所は通常、 FileNum:PageNum:RowNumとして指定されます 。

    SQL Server独自のツールは、オプティマイザーが特定のクエリに使用することを決定したクエリ実行プランを表示するための複数の方法を提供します。 Quest Spotlight Tuning Packを追加すると、計画に関するさらに多くの情報を入手できます。

    次のコードは、 AdventureWorksに2つのテーブルのコピーを作成します データベース(私は AdventureWorks2016を使用しています 、ただし、別のバージョンを使用することもできます。

    USE AdventureWorks2016;

    GO

    DROP TABLE IF EXISTS SalesHeader;

    GO

    SELECT *

    INTO SalesHeader

    FROM Sales.SalesOrderHeader;

    GO

    DROP TABLE IF EXISTS SalesDetail;

    GO

    SELECT * INTO SalesDetail

    FROM Sales.SalesOrderDetail;

    GO

    次に、[実際の実行プランを含める]をオンにした後、2つのテーブルを結合するクエリを実行します

    SELECT h.SalesOrderID, OrderDate, ProductID, UnitPrice, OrderQty

    FROM SalesHeader h JOIN SalesDetail d

    ON h.SalesOrderID = d.SalesOrderID

    WHERE SalesOrderDetailID < 100;

    GO

    Quest Spotlight Tuning Packはクエリの問題を報告するため、[分析の表示]をクリックして、[実行プラン]オプションを選択できます。次のように表示されます。

    テーブルスキャンについて

    まず、手足に出て、いつも悪いプランオペレーターはいないと言いたいです!オプティマイザーがそれをクエリプランに追加するのはなぜですか?データやインデックス構造に改善の余地があることを示している可能性がありますが、それ自体は悪くありません。

    上記の例では、Tuning Packがテーブルスキャンにスポットライトを当てているようで、問題がある可能性があることを示しています。しかし、テーブルスキャンに問題があるとは限りません。さらに悪い状況は、テーブル内のすべての行にアクセスするクエリに対して非クラスター化インデックスシークを使用することです。この特定のクエリでは、 SalesDetail の数行のみに関心があるため、スキャンは適切ではない可能性があることに同意します。 テーブル(121,317行のうち99行、または10分の1パーセント未満)

    したがって、インデックスを作成するための分析ペインの提案を見ることができます。 SalesDetailの提案 テーブルは、 SalesOrderIDに非クラスター化インデックスを作成するためのものです。 column(JOIN句の列)およびクエリによって返されるテーブル内の1つおきの列をINCLUDEします。 SalesHeaderの提案 テーブルは、 SalesOrderDetailIdの非クラスター化インデックスです。 WHERE句の列であるcolumn、およびINCLUDE OrderDate 列。このテーブルから返される他の唯一の列です。

    クエリが少し異なる場合はどうなりますか?特定の列リストの代わりにSELECT*を使用してこのクエリを実行した場合はどうなりますか。試してみて、推奨事項を確認すると、単一のキー列以外のテーブルのすべての列にINCLUDEを使用することをお勧めします。このようなインデックスを使用すると、この特定のクエリの実行速度が少し速くなる可能性がありますが、他のクエリ、特にUPDATEクエリの速度が低下する可能性があります。インデックスのリーフレベルにはテーブル内のすべての列が含まれるため、このインデックスは基本的にテーブルの単なるコピーです。テーブル内のすべての列を含むインデックスを提案するこのような推奨事項が表示された場合は、やみくもに作成するのではなく、少し前に戻ることを強くお勧めします。

    SQL Server診断のクエリ調整には、インデックスの管理だけでなく、クエリ自体の管理も含まれます。この特定のクエリの場合、実際には、クエリを書き直して、テーブル内のすべての行を返すためにSELECT*を使用しない方がよい場合があります。最初の例のように、列の小さなサブセットのみを返すだけで十分な場合があり、その後ははるかに狭いインデックスで十分です。

    これらのインデックスのいずれかが実際に作成するのに適したインデックスでしょうか?狭い方のインデックスは全体的に小さくなり、データの更新による影響が少なくなります。すべての列のインデックスは、テーブル自体とは異なる順序で並べ替えられた、テーブルの2番目のコピーのようなものです。テーブルの「2番目のコピー」を別の順序で配置すると便利な場合がありますが、データ変更操作には多くのオーバーヘッドが発生します。代表的なワークロードを持つテストシステムで推奨事項を試すことを確実に知る唯一の方法。あなただけがあなたのデータとあなたのクエリを知っているので、それを試してみてください!

    インデックススキャンについて

    上で述べたように、テーブルスキャンは必ずしも悪いことではありません。しかし、インデックススキャンはどうですか?クラスター化インデックスリーフレベルはテーブル自体であるため、クラスター化インデックススキャンはテーブルスキャンと同じです。テーブルスキャンが不良の場合、クラスター化インデックススキャンも同様に不良です。しかし、それは必ずしも悪いことではありません。繰り返しになりますが、システムでテストする必要があります。

    Quest Spotlight TuningPackが示すSQLServerエンジンの推奨事項では、クラスター化インデックスを提案することはありません。これは、テーブルのすべての列を含む非クラスター化を示唆している可能性があります(前述のとおり)。これは、テーブルの単なる複製です。クラスタ化されたインデックスに最適な列を見つけること自体が大きなトピックなので、ここでは取り上げません。

    シークとは何ですか?プランでのシーク操作とは、SQL Serverがインデックスツリー内の順序付けられたデータを使用して、行、行のセット、または行の範囲内の開始点や停止点を検索することを意味します。一般に、非クラスター化インデックスシークを使用することは、テーブルからごくわずかな割合の行を返す場合に完全に合理的な操作です。ただし、シークは、テーブルから大量の行を返すクエリには適していません。ロットはいくつですか?簡単な答えはありませんが、クエリが行の数パーセントを超える場合は、インデックスの提案を徹底的にテストする必要があります。テーブルスキャンまたはクラスター化インデックススキャンの方が、インデックスシークよりも優れている場合があります。 (そのような例の1つについては、こちらのブログ投稿を参照してください)。

    Quest Spotlight Tuning Packなどのツール SQL Server診断のチューニングの旅を始めるための優れた提案を提供できますが、SQLServerインデックスとSQLServerオプティマイザーがどのように機能するかを理解すればするほど、クエリとデータ、そしておそらくあなた自身の提案を思い付くかもしれません。

    このシリーズの次の投稿では、クエリプランに表示される可能性のある他の問題のある演算子について説明しますので、しばらくしてからもう一度確認してください。


    1. SQLite内部結合

    2. SQLServerインデックス使用統計

    3. 次のSELECT式で列エイリアスを使用できないのはなぜですか?

    4. SQLでビューを作成する方法