1

我有一个非常大的表(1500 万行,这是一个审计表)。

我需要运行一个查询来检查审计表中是否出现在某个日期之后并满足某些条件(我正在寻找仅在当天发生的审计记录)

当我运行时:

SELECT Field1, Field2 FROM AUDIT_TABLE WHERE AUDIT_DATE >= '8/9/12'

结果很快就回来了(几秒钟,对于 15M 行来说还不错)

当我运行时:

SELECT Field1, Field2 FROM AUDIT_TABLE WHERE AUDIT_DATE >= @DateTime

它需要 11-15 秒并进行全表扫描。

我查询的实际字段是 DATETIME 类型,并且索引也在该字段上。

4

1 回答 1

7

听起来您的计划很糟糕,可能是因为有人在某个时候使用了一个参数,该参数选择了足够多的表,以至于表扫描是该参数值的最有效方式。尝试以这种方式运行一次查询:

SELECT ... FROM AUDIT_TABLE WHERE AUDIT_DATE >= @DateTIme OPTION (RECOMPILE);

然后以这种方式更改您的代码:

SELECT ... FROM dbo.AUDIT_TABLE WHERE AUDIT_DATE >= @DateTime;

使用dbo.前缀至少可以防止具有不同架构的不同用户使用不同版本的计划污染计划缓存。它还将取消将来的查询与存储的错误计划的关联。

如果您要在选择最近的行(小 %)和很多行之间有所不同,我可能会把 OPTION (RECOMPILE) 留在那里。每次在重新编译中支付轻微的 CPU 损失,这比在大多数查询中陷入糟糕的计划要便宜。

我见过的另一个绕过参数嗅探的技巧:

ALTER PROCEDURE dbo.whatever
  @DateTime DATETIME
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @dt DATETIME;
  SET @dt = @DateTime;

  SELECT ... WHERE AUDIT_DATE >= @dt;
END
GO

这是一种肮脏且不直观的技巧,但它使优化器可以更好地了解参数值,并有更好的机会针对该值进行优化。

于 2012-08-09T14:43:47.023 回答