SQL Server の実行プランを少しだけ詳しく説明したみた
SQL Server Management Studio の知っておいたほうが良い機能について挙げてみる - その3 - で使用していた SQL を検証がしやすいよう下記のように変更したいと思います。( NESTED LOOPS をわざと発生するようにしています。)
USE AdventureWorks2012
SET STATISTICS PROFILE ON SELECT * FROM [Production].[Product] a INNER JOIN [Production].[ProductInventory] b ON a.ProductID = b.ProductID OPTION(LOOP JOIN)
まずは、実行プランの見方です。前回の記事で、実行プランは下から評価していくと記載していました。上からの評価が正しいです。(スイマセン。) 上図実行プランの詳細な見方を説明したいと思います。まず重要なのは、下記2つカラムです。
- Rows
StmtText を実行した時に処理結果として、算出された行数です。 - Executes
StmtText を実行した回数です。回数は上位の StmtText の結果により変化します。
上図の 3 行目の StmtText は下記の通りです。PK_Product_ProductID に対してClusterd Index Scan を 1 回行っています。
|--Clustered Index Scan(
OBJECT:([AdventureWorks2012].[Production].[Product].[PK_Product_ProductID] AS [a]))
上図の4行目は、3行目のスキャン操作で得た 個々の ProductID をキーに、504 回の Clustered Index Seek を行っています。
|--Clustered Index Seek(
OBJECT:([AdventureWorks2012].[Production].[ProductInventory].[PK_ProductInventory_ProductID_LocationID] AS [b]),
SEEK:([b].[ProductID]=[AdventureWorks2012].[Production].[Product].[ProductID] as [a].[ProductID]) ORDERED FORWARD)
Nested Loop は、外部テーブル ( 上図の実行プランでは、『 Product 』) から一行づつ取り出し、内部テーブル (上図の実行プランでは、『 ProductInventory 』) の行から一致する行を探します。Nested Loop をC# で表現すると下記のような感じです。( なぜ、ロジックにするのか? なんとなく分かり易いと思ったからです.... )
ProductionProductCollection ppc = ....; //外部テーブル
ProductionProductInventoryCollection ppic = .....; //内部テーブル
//今回の例では、この foreach 文が504回ループします。
//Clustered Index Scanに該当します。
foreach ( var ppc_record in ppc ) {
//下記の処理が、Clustered Index Seekに該当します。
foreach ( var ppic_record in ppic ) {
if ( ppic_record.ProductID == ppc_record.ProductID ) {
//同一のProductID であればレコードを生成して返す。みたいな感じでしょうか。
}
} }
Nested Loop は、上記のような考えです。HASH, MERGE も説明しようかと思いましたが、 土日仕事だったので....今日はここまでにします。実行プランを読み解けるようになれば、自然と高速な SQL が書けるようになります。( 思います、多分)