Đặt thống kê I / O cho các vòng lặp lồng nhau


8

Hãy xem xét các truy vấn dưới đây:

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

THIẾT LẬP THỐNG KÊ IO cho truy vấn trên được trả về:

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

Giải thích từ Itzik Ben-Gan trong cuốn sách của mình như thế này cho các bài đọc ở trên:

Các chi phí I / O liên quan đến việc thực hiện kế hoạch truy vấn được thực hiện như sau:

  • Tìm kiếm lá của chỉ mục: 3 lần đọc (chỉ mục có ba cấp độ).
  • Quét phạm vi 25 hàng: 0 đọc1 (hàng trăm hàng vừa trong một trang).
  • Nested Loops prefetch được sử dụng để tối ưu hóa tra cứu: 9 lần đọc (được đo bằng cách vô hiệu hóa tính năng tìm nạp trước với cờ theo dõi 8744)
  • 25 tra cứu chính: 75 lượt đọc

Kế hoạch truy vấn

Kế hoạch thực hiện

Bây giờ câu hỏi của tôi là, vì các vòng lặp lồng nhau thực hiện tra cứu khóa một lần cho mỗi hàng được trả về từ tìm kiếm, nên tìm kiếm đọc là 25 * 3: 75, giống như tra cứu khóa?

Kế hoạch truy vấn 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>

Câu trả lời:


9

Bây giờ câu hỏi của tôi là, vì các vòng lặp lồng nhau thực hiện tra cứu khóa một lần cho mỗi hàng được trả về từ tìm kiếm, nên tìm kiếm đọc là 25 * 3: 75 giống như tra cứu khóa

Nếu câu hỏi là "nên tìm kiếm cũng yêu cầu 75 lần đọc?" thì câu trả lời là không, vì những lý do Itzik đưa ra, và trích dẫn trong câu hỏi:

Tìm kiếm lá của chỉ mục: 3 lần đọc (chỉ mục có ba cấp độ) Quét phạm vi 25 hàng: 0 đọc1 (hàng trăm hàng vừa trong một trang)

Tìm kiếm ban đầu để tìm vị trí bắt đầu của quét phạm vi (trong toán tử Index Seek) mất 3 lần đọc. Từ thời điểm đó, công cụ lưu trữ ghi nhớ vị trí quét hiện tại, do đó, việc tìm nạp hàng Index Seek tiếp theo yêu cầu không hoặc một lần đọc. Không đọc nếu hàng tiếp theo nằm trên cùng một trang; một đọc nếu nó ở trang tiếp theo.

Sự khác biệt trong hành vi là một nguồn gây nhầm lẫn phổ biến và một trong những lý do khiến tôi không thích đọc logic như một thước đo hiệu suất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.