使用RowNumber进行SELECT需要很长时间才能执行

时间:2016-12-08 14:37:56

标签: sql sql-server

我有一个包含如下定义的调试消息的表:

id  INT NOT NULL IDENTITY
message TEXT NOT NULL
date    DATETIME NOT NULL

对此,我运行以下查询:

SELECT * FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) AS RowNum, * 
    FROM debug WHERE message LIKE @Filter
) AS tbl 
WHERE RowNum > (@Page*200-200) 
AND RowNum <= (@Page * 200)
ORDER BY ID DESC

这给了我一页200个结果;但是表中有220k条目(并且正在计数!),过滤和行编号需要相当长的时间(> 30秒)。

我有什么办法可以加快获取该结果页面的过程吗?

编辑:所以我已按照戈登的建议切换到VARCHAR(MAX);但这并没有加快速度。生成的查询执行计划如下(我尝试将图形重新绘制为ASCII-Art):

                                       Sequence Project                        Clustered Index Scan
    SELECT <- Sort <- Filter <- Top <- (Compute Scalar) <- Segment <- Filter <- [debug].[PK_debug]
Cost: 0%       26%      0%       0%           0%             0%         2%           71%

或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.2" Build="12.0.2569.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="4" StatementEstRows="16.4317" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="120" StatementSubTreeCost="0.0438369" StatementText="SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) AS RowNum, * FROM debug WHERE message LIKE @Filter) AS tbl WHERE RowNum &gt; (@Page*200-200) AND RowNum &lt;= (@Page * 200) ORDER BY ID DESC" StatementType="SELECT" QueryHash="0x535D30B424597DBB" QueryPlanHash="0x17ABB516DFF1A1A7" RetrievedFromCache="true">
          <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
          <QueryPlan DegreeOfParallelism="0" NonParallelPlanReason="EstimatedDOPIsOne" MemoryGrant="1024" CachedPlanSize="32" CompileTime="4" CompileCPU="4" CompileMemory="248">
            <MemoryGrantInfo SerialRequiredMemory="512" SerialDesiredMemory="672" RequiredMemory="512" DesiredMemory="672" RequestedMemory="1024" GrantWaitTime="0" GrantedMemory="1024" MaxUsedMemory="56" />
            <OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="256000" EstimatedPagesCached="16000" EstimatedAvailableDegreeOfParallelism="1" />
            <RelOp AvgRowSize="4055" EstimateCPU="0.000207573" EstimateIO="0.0112613" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="16.4317" LogicalOp="Sort" NodeId="0" Parallel="false" PhysicalOp="Sort" EstimatedTotalSubtreeCost="0.0438369">
              <OutputList>
                <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                <ColumnReference Column="Expr1002" />
              </OutputList>
              <MemoryFractions Input="1" Output="1" />
              <RunTimeInformation>
                <RunTimeCountersPerThread Thread="0" ActualRebinds="1" ActualRewinds="0" ActualRows="147" ActualEndOfScans="1" ActualExecutions="1" />
              </RunTimeInformation>
              <Sort Distinct="false">
                <OrderBy>
                  <OrderByColumn Ascending="false">
                    <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                  </OrderByColumn>
                </OrderBy>
                <RelOp AvgRowSize="4055" EstimateCPU="8.8E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="16.4317" LogicalOp="Filter" NodeId="1" Parallel="false" PhysicalOp="Filter" EstimatedTotalSubtreeCost="0.0323681">
                  <OutputList>
                    <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                    <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                    <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                    <ColumnReference Column="Expr1002" />
                  </OutputList>
                  <RunTimeInformation>
                    <RunTimeCountersPerThread Thread="0" ActualRows="147" ActualEndOfScans="1" ActualExecutions="1" />
                  </RunTimeInformation>
                  <Filter StartupExpression="false">
                    <RelOp AvgRowSize="4055" EstimateCPU="1E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="100" LogicalOp="Top" NodeId="2" Parallel="false" PhysicalOp="Top" EstimatedTotalSubtreeCost="0.0322801">
                      <OutputList>
                        <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                        <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                        <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                        <ColumnReference Column="Expr1002" />
                      </OutputList>
                      <RunTimeInformation>
                        <RunTimeCountersPerThread Thread="0" ActualRows="147" ActualEndOfScans="1" ActualExecutions="1" />
                      </RunTimeInformation>
                      <Top RowCount="false" IsPercent="false" WithTies="false">
                        <TopExpression>
                          <ScalarOperator ScalarString="CASE WHEN CONVERT_IMPLICIT(bigint,[@Page]*(200),0) IS NULL OR CONVERT_IMPLICIT(bigint,[@Page]*(200),0)&lt;(0) THEN (0) ELSE CONVERT_IMPLICIT(bigint,[@Page]*(200),0) END">
                            <IF>
                              <Condition>
                                <ScalarOperator>
                                  <Logical Operation="OR">
                                    <ScalarOperator>
                                      <Compare CompareOp="IS">
                                        <ScalarOperator>
                                          <Identifier>
                                            <ColumnReference Column="ConstExpr1007">
                                              <ScalarOperator>
                                                <Convert DataType="bigint" Style="0" Implicit="true">
                                                  <ScalarOperator>
                                                    <Arithmetic Operation="MULT">
                                                      <ScalarOperator>
                                                        <Identifier>
                                                          <ColumnReference Column="@Page" />
                                                        </Identifier>
                                                      </ScalarOperator>
                                                      <ScalarOperator>
                                                        <Const ConstValue="(200)" />
                                                      </ScalarOperator>
                                                    </Arithmetic>
                                                  </ScalarOperator>
                                                </Convert>
                                              </ScalarOperator>
                                            </ColumnReference>
                                          </Identifier>
                                        </ScalarOperator>
                                        <ScalarOperator>
                                          <Const ConstValue="NULL" />
                                        </ScalarOperator>
                                      </Compare>
                                    </ScalarOperator>
                                    <ScalarOperator>
                                      <Compare CompareOp="LT">
                                        <ScalarOperator>
                                          <Identifier>
                                            <ColumnReference Column="ConstExpr1007">
                                              <ScalarOperator>
                                                <Convert DataType="bigint" Style="0" Implicit="true">
                                                  <ScalarOperator>
                                                    <Arithmetic Operation="MULT">
                                                      <ScalarOperator>
                                                        <Identifier>
                                                          <ColumnReference Column="@Page" />
                                                        </Identifier>
                                                      </ScalarOperator>
                                                      <ScalarOperator>
                                                        <Const ConstValue="(200)" />
                                                      </ScalarOperator>
                                                    </Arithmetic>
                                                  </ScalarOperator>
                                                </Convert>
                                              </ScalarOperator>
                                            </ColumnReference>
                                          </Identifier>
                                        </ScalarOperator>
                                        <ScalarOperator>
                                          <Const ConstValue="(0)" />
                                        </ScalarOperator>
                                      </Compare>
                                    </ScalarOperator>
                                  </Logical>
                                </ScalarOperator>
                              </Condition>
                              <Then>
                                <ScalarOperator>
                                  <Const ConstValue="(0)" />
                                </ScalarOperator>
                              </Then>
                              <Else>
                                <ScalarOperator>
                                  <Identifier>
                                    <ColumnReference Column="ConstExpr1007">
                                      <ScalarOperator>
                                        <Convert DataType="bigint" Style="0" Implicit="true">
                                          <ScalarOperator>
                                            <Arithmetic Operation="MULT">
                                              <ScalarOperator>
                                                <Identifier>
                                                  <ColumnReference Column="@Page" />
                                                </Identifier>
                                              </ScalarOperator>
                                              <ScalarOperator>
                                                <Const ConstValue="(200)" />
                                              </ScalarOperator>
                                            </Arithmetic>
                                          </ScalarOperator>
                                        </Convert>
                                      </ScalarOperator>
                                    </ColumnReference>
                                  </Identifier>
                                </ScalarOperator>
                              </Else>
                            </IF>
                          </ScalarOperator>
                        </TopExpression>
                        <RelOp AvgRowSize="4055" EstimateCPU="0.00284444" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="100" LogicalOp="Compute Scalar" NodeId="3" Parallel="false" PhysicalOp="Sequence Project" EstimatedTotalSubtreeCost="0.0322701">
                          <OutputList>
                            <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                            <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                            <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                            <ColumnReference Column="Expr1002" />
                          </OutputList>
                          <RunTimeInformation>
                            <RunTimeCountersPerThread Thread="0" ActualRows="147" ActualEndOfScans="1" ActualExecutions="1" />
                          </RunTimeInformation>
                          <SequenceProject>
                            <DefinedValues>
                              <DefinedValue>
                                <ColumnReference Column="Expr1002" />
                                <ScalarOperator ScalarString="row_number">
                                  <Sequence FunctionName="row_number" />
                                </ScalarOperator>
                              </DefinedValue>
                            </DefinedValues>
                            <RelOp AvgRowSize="4055" EstimateCPU="0.00071111" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="100" LogicalOp="Segment" NodeId="4" Parallel="false" PhysicalOp="Segment" EstimatedTotalSubtreeCost="0.0322621">
                              <OutputList>
                                <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                                <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                                <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                                <ColumnReference Column="Segment1008" />
                              </OutputList>
                              <RunTimeInformation>
                                <RunTimeCountersPerThread Thread="0" ActualRows="147" ActualEndOfScans="1" ActualExecutions="1" />
                              </RunTimeInformation>
                              <Segment>
                                <GroupBy />
                                <SegmentColumn>
                                  <ColumnReference Column="Segment1008" />
                                </SegmentColumn>
                                <RelOp AvgRowSize="4047" EstimateCPU="0.347654" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="100" LogicalOp="Filter" NodeId="5" Parallel="false" PhysicalOp="Filter" EstimatedTotalSubtreeCost="0.0322601">
                                  <OutputList>
                                    <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                                    <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                                    <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                                  </OutputList>
                                  <RunTimeInformation>
                                    <RunTimeCountersPerThread Thread="0" ActualRows="147" ActualEndOfScans="1" ActualExecutions="1" />
                                  </RunTimeInformation>
                                  <Filter StartupExpression="false">
                                    <RelOp AvgRowSize="4047" EstimateCPU="0.434724" EstimateIO="9.53275" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1111.11" LogicalOp="Clustered Index Scan" NodeId="6" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.0312823" TableCardinality="395061">
                                      <OutputList>
                                        <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                                        <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                                        <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                                      </OutputList>
                                      <RunTimeInformation>
                                        <RunTimeCountersPerThread Thread="0" ActualRows="395061" ActualEndOfScans="1" ActualExecutions="1" />
                                      </RunTimeInformation>
                                      <IndexScan Ordered="true" ScanDirection="BACKWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false" Storage="RowStore">
                                        <DefinedValues>
                                          <DefinedValue>
                                            <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="id" />
                                          </DefinedValue>
                                          <DefinedValue>
                                            <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                                          </DefinedValue>
                                          <DefinedValue>
                                            <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="date" />
                                          </DefinedValue>
                                        </DefinedValues>
                                        <Object Database="[timeflex]" Schema="[dbo]" Table="[debug]" Index="[PK_debug]" IndexKind="Clustered" Storage="RowStore" />
                                      </IndexScan>
                                    </RelOp>
                                    <Predicate>
                                      <ScalarOperator ScalarString="[timeflex].[dbo].[debug].[message] like [@Filter]">
                                        <Intrinsic FunctionName="like">
                                          <ScalarOperator>
                                            <Identifier>
                                              <ColumnReference Database="[timeflex]" Schema="[dbo]" Table="[debug]" Column="message" />
                                            </Identifier>
                                          </ScalarOperator>
                                          <ScalarOperator>
                                            <Identifier>
                                              <ColumnReference Column="@Filter" />
                                            </Identifier>
                                          </ScalarOperator>
                                        </Intrinsic>
                                      </ScalarOperator>
                                    </Predicate>
                                  </Filter>
                                </RelOp>
                              </Segment>
                            </RelOp>
                          </SequenceProject>
                        </RelOp>
                      </Top>
                    </RelOp>
                    <Predicate>
                      <ScalarOperator ScalarString="[Expr1002]&gt;CONVERT_IMPLICIT(bigint,[@Page]*(200)-(200),0) AND [Expr1002]&lt;=CONVERT_IMPLICIT(bigint,[@Page]*(200),0)">
                        <Logical Operation="AND">
                          <ScalarOperator>
                            <Compare CompareOp="GT">
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Column="Expr1002" />
                                </Identifier>
                              </ScalarOperator>
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Column="ConstExpr1006">
                                    <ScalarOperator>
                                      <Convert DataType="bigint" Style="0" Implicit="true">
                                        <ScalarOperator>
                                          <Arithmetic Operation="SUB">
                                            <ScalarOperator>
                                              <Arithmetic Operation="MULT">
                                                <ScalarOperator>
                                                  <Identifier>
                                                    <ColumnReference Column="@Page" />
                                                  </Identifier>
                                                </ScalarOperator>
                                                <ScalarOperator>
                                                  <Const ConstValue="(200)" />
                                                </ScalarOperator>
                                              </Arithmetic>
                                            </ScalarOperator>
                                            <ScalarOperator>
                                              <Const ConstValue="(200)" />
                                            </ScalarOperator>
                                          </Arithmetic>
                                        </ScalarOperator>
                                      </Convert>
                                    </ScalarOperator>
                                  </ColumnReference>
                                </Identifier>
                              </ScalarOperator>
                            </Compare>
                          </ScalarOperator>
                          <ScalarOperator>
                            <Compare CompareOp="LE">
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Column="Expr1002" />
                                </Identifier>
                              </ScalarOperator>
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Column="ConstExpr1007">
                                    <ScalarOperator>
                                      <Convert DataType="bigint" Style="0" Implicit="true">
                                        <ScalarOperator>
                                          <Arithmetic Operation="MULT">
                                            <ScalarOperator>
                                              <Identifier>
                                                <ColumnReference Column="@Page" />
                                              </Identifier>
                                            </ScalarOperator>
                                            <ScalarOperator>
                                              <Const ConstValue="(200)" />
                                            </ScalarOperator>
                                          </Arithmetic>
                                        </ScalarOperator>
                                      </Convert>
                                    </ScalarOperator>
                                  </ColumnReference>
                                </Identifier>
                              </ScalarOperator>
                            </Compare>
                          </ScalarOperator>
                        </Logical>
                      </ScalarOperator>
                    </Predicate>
                  </Filter>
                </RelOp>
              </Sort>
            </RelOp>
            <ParameterList>
              <ColumnReference Column="@Page" ParameterRuntimeValue="(1)" />
              <ColumnReference Column="@Filter" ParameterRuntimeValue="'%ZUser888%'" />
            </ParameterList>
          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>

1 个答案:

答案 0 :(得分:5)

评论太长了。

首先,请勿使用text,使用varchar(max)nvarchar(max)。它在SQL Server 2016中正式弃用,因此它可能会在将来的版本中消失。

对于分页,请使用OFFSET / FETCH。这是在SQL Server 2012中引入的,因此它有点向后兼容。没有SQL Server 2010.阅读它here

让我消除表/页/行争用作为性能问题的原因。我最好的猜测是非常广泛的专栏like。如果message确实是一堆自由格式文本,那么请使用全文索引。开始的地方是文档。出于某种原因,我的Microsoft文档链接目前还不能正常运行,但应该很容易找到。

如果行宽非常宽,那么select *可能会出现其他问题。如果您正在进行分页,那么这很可能是用户界面,因此您可能希望将列限制为您真正需要的列 - 如果您不打算显示整个列,甚至可以缩短很长的列