0

我有一个针对一个非常大的表运行的查询,我需要对其进行计数。

如果我使用文字,查询会在几秒钟内运行,但是当我将值作为变量放入时(我需要这样做),查询需要永远并且可能会进行全表扫描。

我已经阅读了很多关于此的内容,并且我理解它最有可能与参数嗅探有关,我不能假装我理解它,我只想知道如何修复它,否则,我将不得不使用生成的查询字符串在 c# 中调用它。

此查询将在几秒钟内运行..

  SELECT Count(Id) FROM  dbo.BeaconScan WHERE State = 'Archived' AND  LastSeen < '29 February 2020';

这需要永远

DECLARE @Date DATE = '31 March 2020'
DECLARE @Status NVARCHAR(256) = 'Archived'
SELECT Count(Id) FROM  dbo.BeaconScan WHERE State = @Status AND  LastSeen < @Date;
4

4 回答 4

1

您应该检查您actual plans的问题以确保问题出在参数嗅探中。只有实际计划向您显示实际行数与预期 + 计划构建的参数。

如果您希望您的查询每次都使用您的实际参数,您可以recompile在查询级别添加选项:

SELECT Count(Id) FROM  dbo.BeaconScan WHERE State = @Status AND  LastSeen < @Date
option(recompile);
于 2020-11-06T11:45:40.283 回答
1

With a literal date, the optimizer can determine if a SEEK will out perform a SCAN. If the table has many years of data, but the query only asks for data after 29 Feb 2020, the optimizer can determine that it needs a small data set and will SEEK. The query will run relatively quickly.

The optimizer views a variable date as unknown. Therefore, the optimizer must build a plan that accounts for dates like 1 Jan 2001 or 12 Dec 2012. Large datasets do better with SCAN (index scan or table scan). Given the unknown value, the optimizer will often select SCAN. The query will run much longer because it is reading every row and not using the indexes.

To avoid the unknown, you can use the OPTIMIZE FOR query hint. But, depending on your use case, that may be no different than just using a literal.

Parameter sniffing usually refers to stored procedures. To avoid, assign procedure parameter to a variable within the first line or two of the procedure. Not necessary to know the full explanation for parameter sniffing in order to avoid it.

于 2020-11-08T10:25:58.447 回答
1

SQL Server 基于行数估计和启发式优化查询。这些估计值可能因文字、局部变量或参数而异。

使用文字或参数(在应用程序代码中声明并随命令传递的参数),SQL Server 根据提供的实际值和统计直方图(如果列上存在索引或统计信息)估计计数。当统计数据是最新的时,这通常会导致准确的估计和最佳计划。

使用局部变量(T-SQLDECLARE语句)或OPTIMIZE FOR UNKNOWN查询提示,SQL Server 根据值的总体平均密度估计计数,而忽略实际值和直方图。这通常会导致一个折衷计划,总体上可能足够好,但对于某些值可能不是最优的。向带有局部变量的查询添加OPTION (RECOMPILE)查询提示将改为使用实际的局部变量值进行优化,并产生与指定文字相同的计划。

请注意,没有RECOMPILE提示的参数化查询计划将被缓存和重用。重用计划时会忽略当前参数值,因此重用的查询计划对于当前参数值可能不是最佳的。这是另一种OPTION (RECOMPILE)可能提高性能的情况。

OPTION (RECOMPILE)考虑到查询执行频率,明智地使用提示。对于频繁执行的查询(例如每秒多次),编译开销可能超过运行时节省。

于 2020-11-06T12:21:34.453 回答
1

如果您使用存储过程,要消除参数嗅探,请执行以下操作:

DECLARE @DateLocal DATE = @Date
DECLARE @StatusLocal NVARCHAR(256) = @Status

SELECT Count(Id) FROM dbo.BeaconScan WHERE State = @StatusLocal AND LastSeen < @DateLocal
于 2020-11-06T10:20:30.080 回答