(长话短说 - 我认为奇怪的执行计划注释列表中的#3 就是问题所在)。
我目前遇到了一个过去表现良好的存储过程的一些非常糟糕的性能 - 这是在性能测试的背景下,我们恢复数据库,然后在系统上加载。我无法弄清楚我们系统的这部分发生了什么变化。根据封锁报告,没有实质性的封锁(我们将阈值设置为1秒一段时间来检查这一点)。
通过捕获执行计划,我们发现过程中的单个查询是罪魁祸首。查询很简单
INSERT INTO #table (<columnset>)
SELECT <columnset>
FROM table
WHERE <binary type column> > @binaryArgumentPassedIntoProc
对于源表:WHERE子句中的时间戳列已建立索引。所选列之一是 PK,其类型为 varchar。正在选择另外 3 列(总共 5 列)。临时表没有索引/键或约束。
此表上的架构没有更改,但有一点异常(exception) - 源表上的其中一列现在将 TrimTrailingBlanks 设置为 yes。此列不在所选择的列集中。我无法想象这很重要,但我想把它说出来。
当我恢复时间点时,我无法复制缓慢的情况。在生产执行期间(即在性能测试环境中运行缓慢时),查询有时需要 30 秒以上。在时间点备份中,查询时间不到 1 秒。
通过比较从生产执行和时间点执行中捕获的执行计划数据,我发现了一些令人困惑的部分。请注意,查询(在这两种情况下)都会将 180 行插入到临时表中。
- 时间点备份执行中的 EstimatedRow 计数为 176.683。生产执行中为2。对于选择和插入来说都是如此
- select 的生产执行中的 TableCardinality 为 2,而在时间点执行中为 1578。这表明生产中的统计数据很糟糕,这并不奇怪,尽管我不确定当系统负载如此重时如何实时处理这个问题(执行期间表中实际上有 1578 行)。话虽如此,在过去性能良好的情况下这并不是问题。
- 执行计划中记录的插入临时表的实际行数在生产执行中列为 3222。在执行时间点中,实际行数列出为 180。
关于(3) - 我对实际行数的理解是,它是迭代器在执行查询时调用GetNext()的次数。我认为,通过简单的选择(主要是没有联接),实际行数值最多将等于该点表中的行数 (1578)。
最后,通过捕获物理和逻辑磁盘的性能计数器,它不会出现明显的磁盘排队现象,也不会有磁盘排队和缓慢执行之间的相关性。
有人对我如何进一步解决此问题有任何建议吗?
我们在 Windows Server 2008 R2 SP1 计算机上运行 SQL Server 2008 R2。该机器有 16 个核心和 128 GB RAM(其中 64 个专用于 SQL Server)。
更新:我在恢复后和测试前用数据播种表,然后更新统计信息并重新编译过程。实际和预期的行数以及表基数反射(reflect)了实际值,但我们仍然看到执行时间很长。
以下是此最新测试中的错误查询之一的 XML 显示计划配置文件统计跟踪事件输出:
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.1" Build="10.50.2500.0"><BatchSequence><Batch><Statements><StmtSimple><QueryPlan DegreeOfParallelism="1" CachedPlanSize="24" CompileTime="4" CompileCPU="4" CompileMemory="192"><RelOp NodeId="0" PhysicalOp="Table Insert" LogicalOp="Insert" EstimateRows="170" EstimateIO="0.010254" EstimateCPU="0.00017" AvgRowSize="9" EstimatedTotalSubtreeCost="0.0154085" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList/><RunTimeInformation><RunTimeCountersPerThread Thread="0" ActualRows="69" ActualEndOfScans="1" ActualExecutions="1"/></RunTimeInformation><Update DMLRequestSort="0"><Object Database="[tempdb]" Schema="[dbo]" Table="[#sourceTable]"/><SetPredicate><ScalarOperator ScalarString="[#destinationTable].[record_Identifier] = RaiseIfNullInsert([Expr1008]),[#destinationTable].[modifiedTS] = [Expr1009],[#destinationTable].[Last_Update] = [DBName].[dbo].[sourceTable].[last_update],[#destinationTable].[LastValueUpdate] = [DBName].[dbo].[sourceTable].[LastValueUpdate],[#destinationTable].[OtherValue_lastUpdate] = [DBName].[dbo].[sourceTable].[OtherValue_lastUpdate]"><ScalarExpressionList><ScalarOperator><MultipleAssign><Assign><ColumnReference Table="[#destinationTable]" Column="record_Identifier"/><ScalarOperator><Intrinsic FunctionName="RaiseIfNullInsert"><ScalarOperator><Identifier><ColumnReference Column="Expr1008"/></Identifier></ScalarOperator></Intrinsic></ScalarOperator></Assign><Assign><ColumnReference Table="[#destinationTable]" Column="modifiedTS"/><ScalarOperator><Identifier><ColumnReference Column="Expr1009"/></Identifier></ScalarOperator></Assign><Assign><ColumnReference Table="[#destinationTable]" Column="Last_Update"/><ScalarOperator><Identifier><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="last_update"/></Identifier></ScalarOperator></Assign><Assign><ColumnReference Table="[#destinationTable]" Column="LastValueUpdate"/><ScalarOperator><Identifier><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="LastValueUpdate"/></Identifier></ScalarOperator></Assign><Assign><ColumnReference Table="[#destinationTable]" Column="OtherValue_lastUpdate"/><ScalarOperator><Identifier><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="OtherValue_lastUpdate"/></Identifier></ScalarOperator></Assign></MultipleAssign></ScalarOperator></ScalarExpressionList></ScalarOperator></SetPredicate><RelOp NodeId="1" PhysicalOp="Compute Scalar" LogicalOp="Compute Scalar" EstimateRows="170" EstimateIO="0" EstimateCPU="1.7e-005" AvgRowSize="50" EstimatedTotalSubtreeCost="0.00498448" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="last_update"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="LastValueUpdate"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="OtherValue_lastUpdate"/><ColumnReference Column="Expr1008"/><ColumnReference Column="Expr1009"/></OutputList><ComputeScalar><DefinedValues><DefinedValue><ColumnReference Column="Expr1008"/><ScalarOperator ScalarString="CONVERT_IMPLICIT(varchar(15),[DBName].[dbo].[sourceTable].[record_identifier],0)"><Convert DataType="varchar" Length="15" Style="0" Implicit="1"><ScalarOperator><Identifier><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="record_identifier"/></Identifier></ScalarOperator></Convert></ScalarOperator></DefinedValue><DefinedValue><ColumnReference Column="Expr1009"/><ScalarOperator ScalarString="CONVERT_IMPLICIT(binary(8),[DBName].[dbo].[sourceTable].[ModifiedTS],0)"><Convert DataType="binary" Length="8" Style="0" Implicit="1"><ScalarOperator><Identifier><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="ModifiedTS"/></Identifier></ScalarOperator></Convert></ScalarOperator></DefinedValue></DefinedValues><RelOp NodeId="2" PhysicalOp="Top" LogicalOp="Top" EstimateRows="170" EstimateIO="0" EstimateCPU="1.7e-005" AvgRowSize="58" EstimatedTotalSubtreeCost="0.00496748" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="record_identifier"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="last_update"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="LastValueUpdate"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="ModifiedTS"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="OtherValue_lastUpdate"/></OutputList><RunTimeInformation><RunTimeCountersPerThread Thread="0" ActualRows="69" ActualEndOfScans="1" ActualExecutions="1"/></RunTimeInformation><Top RowCount="1" IsPercent="0" WithTies="0"><TopExpression><ScalarOperator ScalarString="(0)"><Const ConstValue="(0)"/></ScalarOperator></TopExpression><RelOp NodeId="3" PhysicalOp="Clustered Index Seek" LogicalOp="Clustered Index Seek" EstimateRows="170" EstimateIO="0.00460648" EstimateCPU="0.000344" AvgRowSize="58" EstimatedTotalSubtreeCost="0.00495048" TableCardinality="1402" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="record_identifier"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="last_update"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="LastValueUpdate"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="ModifiedTS"/><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="OtherValue_lastUpdate"/></OutputList><RunTimeInformation><RunTimeCountersPerThread Thread="0" ActualRows="69" ActualEndOfScans="1" ActualExecutions="1"/></RunTimeInformation><IndexScan Ordered="1" ScanDirection="FORWARD" ForcedIndex="0" ForceSeek="0" ForceScan="0" NoExpandHint="0"><DefinedValues><DefinedValue><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="record_identifier"/></DefinedValue><DefinedValue><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="last_update"/></DefinedValue><DefinedValue><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="LastValueUpdate"/></DefinedValue><DefinedValue><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="ModifiedTS"/></DefinedValue><DefinedValue><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="OtherValue_lastUpdate"/></DefinedValue></DefinedValues><Object Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Index="[idx_sourceTable_modifiedts]" IndexKind="Clustered"/><SeekPredicates><SeekPredicateNew><SeekKeys><StartRange ScanType="GT"><RangeColumns><ColumnReference Database="[DBName]" Schema="[dbo]" Table="[sourceTable]" Column="ModifiedTS"/></RangeColumns><RangeExpressions><ScalarOperator ScalarString="CONVERT_IMPLICIT(timestamp,[@modifiedts],0)"><Identifier><ColumnReference Column="ConstExpr1010"><ScalarOperator><Convert DataType="timestamp" Style="0" Implicit="1"><ScalarOperator><Identifier><ColumnReference Column="@modifiedts"/></Identifier></ScalarOperator></Convert></ScalarOperator></ColumnReference></Identifier></ScalarOperator></RangeExpressions></StartRange></SeekKeys></SeekPredicateNew></SeekPredicates></IndexScan></RelOp></Top></RelOp></ComputeScalar></RelOp></Update></RelOp><ParameterList><ColumnReference Column="@modifiedts" ParameterCompiledValue="0x00000000008EB813" ParameterRuntimeValue="0x0000000000914056"/></ParameterList></QueryPlan></StmtSimple></Statements></Batch></BatchSequence></ShowPlanXML>
最佳答案
问题已解决。错误的实际行计数是由于错误的统计信息造成的,而阻塞是由于针对表运行的大量非常小的排队锁定查询造成的。它们都太小,即使在 1 秒阈值下也不会导致生成阻塞报告,但足以在 10 秒以上的范围内导致阻塞。 我选择了 READUNCOMMITTED 并更改了应用程序代码来处理此问题。
关于sql-server - SQL Server 执行计划实际行数对于简单选择来说太大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28205591/