我有一个包含如下定义的调试消息的表:
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 > (@Page*200-200) AND RowNum <= (@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)<(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]>CONVERT_IMPLICIT(bigint,[@Page]*(200)-(200),0) AND [Expr1002]<=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>
答案 0 :(得分:5)
评论太长了。
首先,请勿使用text
,使用varchar(max)
或nvarchar(max)
。它在SQL Server 2016中正式弃用,因此它可能会在将来的版本中消失。
对于分页,请使用OFFSET
/ FETCH
。这是在SQL Server 2012中引入的,因此它有点向后兼容。没有SQL Server 2010.阅读它here。
让我消除表/页/行争用作为性能问题的原因。我最好的猜测是非常广泛的专栏like
。如果message
确实是一堆自由格式文本,那么请使用全文索引。开始的地方是文档。出于某种原因,我的Microsoft文档链接目前还不能正常运行,但应该很容易找到。
如果行宽非常宽,那么select *
可能会出现其他问题。如果您正在进行分页,那么这很可能是用户界面,因此您可能希望将列限制为您真正需要的列 - 如果您不打算显示整个列,甚至可以缩短很长的列