我有一个非常大的表(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类型,索引也在该字段上。
答案 0 :(得分: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
这是一种肮脏且不直观的技巧,但它可以让优化器更好地了解参数值,并更好地优化该值。