Atur statistik I / O untuk loop bersarang


8

Pertimbangkan permintaan di bawah ini:

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 STATISTIK IO untuk permintaan di atas dikembalikan:

(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.

Penjelasan dari Itzik Ben-Gan dalam bukunya seperti ini untuk bacaan di atas:

Biaya I / O yang terlibat dalam pelaksanaan rencana kueri dibuat sebagai berikut:

  • Mencari ke daun indeks: 3 berbunyi (indeks memiliki tiga level).
  • Pemindaian rentang 25 baris: 0–1 berbunyi (ratusan baris masuk dalam satu halaman).
  • Preferensi Nested Loops digunakan untuk mengoptimalkan pencarian: 9 kali dibaca (diukur dengan menonaktifkan prefetch dengan jejak flag 8744)
  • 25 pencarian kunci: 75 kali dibaca

Rencana kueri

Rencana eksekusi

Sekarang pertanyaan saya adalah, karena loop bersarang melakukan pencarian kunci sekali untuk setiap baris yang dikembalikan dari pencarian, apakah pencarian harus berbunyi 25 * 3: 75, sama dengan pencarian kunci?

XML rencana kueri

<?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>

Jawaban:


9

Sekarang pertanyaan saya adalah, karena loop bersarang melakukan pencarian kunci sekali untuk setiap baris yang dikembalikan dari pencarian, harus mencari bacaan menjadi 25 * 3: 75 sama dengan pencarian kunci

Jika pertanyaannya adalah "haruskah pencarian juga membutuhkan 75 bacaan?" maka jawabannya tidak, karena alasan yang diberikan Itzik, dan dikutip dalam pertanyaan:

Mencari ke daun indeks: 3 kali dibaca (indeks memiliki tiga level) Pemindaian rentang 25 baris: 0–1 berbunyi (ratusan baris sesuai dalam satu halaman)

Upaya awal untuk menemukan posisi awal pemindaian jangkauan (di operator Index Seek) membutuhkan 3 kali pembacaan. Sejak saat itu, mesin penyimpanan mengingat posisi pemindaian saat ini, sehingga mengambil baris Indeks Pencarian berikutnya memerlukan nol atau satu bacaan. Nol membaca jika baris berikutnya ada di halaman yang sama; satu baca jika ada di halaman berikutnya.

Perbedaan perilaku adalah sumber kebingungan yang umum, dan salah satu alasan mengapa saya tidak suka membaca logis sebagai metrik kinerja.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.