ネストされたループの統計I / Oを設定する


8

以下のクエリを考えてみましょう:

CREATE PROC dbo.GetPage  @orderid  AS INT    = 0, -- anchor sort key
            @pagesize AS BIGINT = 25
 AS
SELECT
TOP (@pagesize) orderid, orderdate, custid, empid
 FROM dbo.Orders WHERE orderid > @orderid ORDER BY orderid;

exec GetPage 25,25

上記のクエリに対してSET STATISTICS IOが返されました:

(25 row(s) affected)
Table 'Orders'. Scan count 1, logical reads 87, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

彼の本の中でイツィクベンガンからの説明は、上記の読み取りについては次のようになります。

クエリプランの実行に関連するI / Oコストは、次のもので構成されます。

  • インデックスのリーフにシークします。3回の読み取り(インデックスには3つのレベルがあります)。
  • 25行の範囲スキャン:0〜1回の読み取り(数百行が1ページに収まります)。
  • ルックアップの最適化に使用されるネストされたループのプリフェッチ:9回の読み取り(トレースフラグ8744でプリフェッチを無効にすることで測定)
  • 25キー検索:75読み取り

クエリプラン

実行計画

今私の質問は、ネストされたループがシークから返された各行に対して1回キールックアップを行うため、シークリードはキールックアップと同じ25 * 3:75である必要がありますか?

クエリプランXML

<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.4" Build="13.0.900.73" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="3" StatementEstRows="25" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="130" StatementSubTreeCost="0.0887816" StatementText=" CREATE PROC dbo.GetPage  @orderid  AS INT    = 0, -- anchor sort key &#xD;&#xA;  @pagesize AS BIGINT = 25 &#xD;&#xA;  AS&#xD;&#xA;SELECT TOP (@pagesize) orderid, orderdate, custid, empid FROM dbo.Orders WHERE orderid &gt; @orderid ORDER BY orderid" StatementType="SELECT" QueryHash="0x48DC1D1D4649B914" QueryPlanHash="0x8FDC055F05E0E93C" RetrievedFromCache="true" SecurityPolicyApplied="false">
          <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
          <QueryPlan CachedPlanSize="32" CompileTime="2" CompileCPU="2" CompileMemory="208">
            <MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0" />
            <OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="52428" EstimatedPagesCached="13107" EstimatedAvailableDegreeOfParallelism="2" />
            <RelOp AvgRowSize="29" EstimateCPU="2.5E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="25" LogicalOp="Top" NodeId="0" Parallel="false" PhysicalOp="Top" EstimatedTotalSubtreeCost="0.0887816">
              <OutputList>
                <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderid" />
                <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="custid" />
                <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="empid" />
                <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderdate" />
              </OutputList>
              <Top RowCount="false" IsPercent="false" WithTies="false">
                <TopExpression>
                  <ScalarOperator ScalarString="[@pagesize]">
                    <Identifier>
                      <ColumnReference Column="@pagesize" />
                    </Identifier>
                  </ScalarOperator>
                </TopExpression>
                <RelOp AvgRowSize="29" EstimateCPU="4.1799" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="25" LogicalOp="Inner Join" NodeId="1" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0887791">
                  <OutputList>
                    <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderid" />
                    <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="custid" />
                    <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="empid" />
                    <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderdate" />
                  </OutputList>
                  <NestedLoops Optimized="false" WithOrderedPrefetch="true">
                    <OuterReferences>
                      <ColumnReference Column="Uniq1001" />
                      <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderdate" />
                      <ColumnReference Column="Expr1003" />
                    </OuterReferences>
                    <RelOp AvgRowSize="18" EstimateCPU="1.10013" EstimateIO="1.92683" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="25" LogicalOp="Index Seek" NodeId="3" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.00335567" TableCardinality="1000000">
                      <OutputList>
                        <ColumnReference Column="Uniq1001" />
                        <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderid" />
                        <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderdate" />
                      </OutputList>
                      <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false" Storage="RowStore">
                        <DefinedValues>
                          <DefinedValue>
                            <ColumnReference Column="Uniq1001" />
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderid" />
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderdate" />
                          </DefinedValue>
                        </DefinedValues>
                        <Object Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Index="[PK_Orders]" IndexKind="NonClustered" Storage="RowStore" />
                        <SeekPredicates>
                          <SeekPredicateNew>
                            <SeekKeys>
                              <StartRange ScanType="GT">
                                <RangeColumns>
                                  <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderid" />
                                </RangeColumns>
                                <RangeExpressions>
                                  <ScalarOperator ScalarString="[@orderid]">
                                    <Identifier>
                                      <ColumnReference Column="@orderid" />
                                    </Identifier>
                                  </ScalarOperator>
                                </RangeExpressions>
                              </StartRange>
                            </SeekKeys>
                          </SeekPredicateNew>
                        </SeekPredicates>
                      </IndexScan>
                    </RelOp>
                    <RelOp AvgRowSize="22" EstimateCPU="0.0001581" EstimateIO="0.003125" EstimateRebinds="25" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Clustered Index Seek" NodeId="5" Parallel="false" PhysicalOp="Clustered Index Seek" EstimatedTotalSubtreeCost="0.0853189" TableCardinality="1000000">
                      <OutputList>
                        <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="custid" />
                        <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="empid" />
                      </OutputList>
                      <IndexScan Lookup="true" Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false" Storage="RowStore">
                        <DefinedValues>
                          <DefinedValue>
                            <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="custid" />
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="empid" />
                          </DefinedValue>
                        </DefinedValues>
                        <Object Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Index="[idx_cl_od]" TableReferenceId="-1" IndexKind="Clustered" Storage="RowStore" />
                        <SeekPredicates>
                          <SeekPredicateNew>
                            <SeekKeys>
                              <Prefix ScanType="EQ">
                                <RangeColumns>
                                  <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderdate" />
                                  <ColumnReference Column="Uniq1001" />
                                </RangeColumns>
                                <RangeExpressions>
                                  <ScalarOperator ScalarString="[PerformanceV3].[dbo].[Orders].[orderdate]">
                                    <Identifier>
                                      <ColumnReference Database="[PerformanceV3]" Schema="[dbo]" Table="[Orders]" Column="orderdate" />
                                    </Identifier>
                                  </ScalarOperator>
                                  <ScalarOperator ScalarString="[Uniq1001]">
                                    <Identifier>
                                      <ColumnReference Column="Uniq1001" />
                                    </Identifier>
                                  </ScalarOperator>
                                </RangeExpressions>
                              </Prefix>
                            </SeekKeys>
                          </SeekPredicateNew>
                        </SeekPredicates>
                      </IndexScan>
                    </RelOp>
                  </NestedLoops>
                </RelOp>
              </Top>
            </RelOp>
            <ParameterList>
              <ColumnReference Column="@pagesize" ParameterCompiledValue="(25)" />
              <ColumnReference Column="@orderid" ParameterCompiledValue="(25)" />
            </ParameterList>
          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>

回答:


9

今私の質問は、ネストされたループがシークから返された各行に対して一度キー検索を行うため、シーク読み取りはキー検索と同じ25 * 3:75である必要があります

質問が「シークにも75回の読み取りが必要か?」次に、答えは「いいえ」です。これは、イツィクが与えた理由のため、質問で引用されています。

インデックスのリーフにシークする:3回の読み取り(インデックスには3つのレベルがあります)25行の範囲スキャン:0〜1回の読み取り(ページに収まる数百行)

(インデックスシークオペレーターでの)範囲スキャンの開始位置を見つけるための最初のシークには、3回の読み取りが必要です。その時点以降、ストレージエンジンはスキャンの現在の位置を記憶しているため、次のインデックスシーク行をフェッチするには、0回または1回の読み取りが必要です。次の行が同じページにある場合、ゼロは読み取られます。次のページにある場合は、1つお読みください。

動作の違いは一般的な混乱の原因であり、論理メトリック読み取りをパフォーマンスメトリックとして嫌う理由の1つです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.