2

我正在尝试查看一个简单的 select Top (n) 的查询计划。每次我更改 n(我获取的记录数)时,查询计划都会更改,其中 Select Top 10 会特别导致性能问题,小于 10 或大于 10 时查询运行顺利。

查询由实体框架 (4.2) 生成,如果它有所作为。

查询是:

 exec sp_executesql N'SELECT TOP (10) 
[Project1].[Id] AS [Id], 
[Project1].[DateReceived] AS [DateReceived], 
[Project1].[Status] AS [Status], 
[Project1].[Subject] AS [Subject], 
[Project1].[Description] AS [Description], 
[Project1].[Path] AS [Path], 
[Project1].[C1] AS [C1], 
[Project1].[C2] AS [C2], 
[Project1].[C3] AS [C3],
.
.
.
.
.
.
.

WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[DateReceived] DESC',N'@p__linq__0 int,@p__linq__1 int,@p__linq__2 datetime2(7),@p__linq__3 datetime2(7),@p__linq__4 nvarchar(4000),@p__linq__5 nvarchar(4000),@p__linq__6 nvarchar(4000),@p__linq__7 nvarchar(4000)',@p__linq__0=-1,@p__linq__1=-1,@p__linq__2='2013-03-15 00:00:00',@p__linq__3='2013-04-15 23:59:55',@p__linq__4=N'ALL',@p__linq__5=N'ALL',@p__linq__6=N'',@p__linq__7=N'%%'

为什么 TOP 10 会导致性能问题?

我还不能分享图片,这里是链接:

http://imageshack.us/photo/my-images/407/top10a.png/

http://imageshack.us/photo/my-images/580/top20x.png/

4

1 回答 1

0

正如@JanDrozen 所说,它很可能是统计问题。当数据大小超过某个阈值时,生成的执行计划不再是最佳计划,但统计数据不允许它获得正确的估计行数。优化器并不总是生成最佳执行计划。这是一项令人印象深刻的编程成就壮举,通常可以从我们的谷壳中获得金子,但它确实只能利用手头的数据做到最好。它使用 carnality 统计数据,并将使用估计的结果集大小来确定它认为最好的计划。

在不尝试首先更新统计信息的情况下判断它是否是统计信息问题的一种方法是启用实际的执行计划,并查看属性。

检查:

  • 在数据进入管道的地方,估计的行数接近实际的行数。
  • 执行计划的属性表明优化器达到了最佳计划。在属性中,它将告诉您为什么选择该计划。有时,如果统计数据已经过时,优化器永远不会找到最佳计划,而只能使用它可以找到的最佳计划。

此查询是更新示例 Adventureworks 数据库中的统计信息的示例。

USE AdventureWorks2012;
GO
UPDATE STATISTICS Production.Product(Products)
    WITH FULLSCAN, NORECOMPUTE;
GO

有一个存储过程sp_updatestats [ [ @resample = ] 'resample'] ,但我从来没有用它得到很好的结果,我永远不能强迫它通过全面扫描进行更新,根据我的经验,这是获得良好统计数据的最佳方式。

如果您需要对大量表执行此操作,这是我之前使用过的脚本,用于使用动态 sql 重新生成统计信息。

DECLARE @sql nvarchar(MAX);
SELECT @sql = (SELECT 'UPDATE STATISTICS ' +
                  quotename(s.name) + '.' + quotename(o.name) +
                  ' WITH FULLSCAN; ' AS [text()]
           FROM   sys.objects o
           JOIN   sys.schemas s ON o.schema_id = s.schema_id
           WHERE  o.type = 'U'
           FOR XML PATH(''), TYPE).value('.', 'nvarchar(MAX)');
PRINT @sql
EXEC (@sql)

是一篇关于统计的好文章,并对它们是什么、它们做什么以及如何看待它们进行了很好的细分。

于 2013-05-15T00:51:43.870 回答