使用变量的过滤器查询未使用索引

时间:2018-10-25 06:14:40

标签: sql-server

在索引字段中使用以下查询中的变量进行比较的过滤器未使用索引:

not using index

下面是使用与常量比较的查询,该比较使用索引: enter image description here

相关索引:

enter image description here

请解释为什么第一个查询不使用索引,以及如何使用索引进行查询?

谢谢!

1 个答案:

答案 0 :(得分:0)

这是一个ad-hoc查询。引擎只会忽略您的变量,并建立一个执行计划,无论变量的值如何,该计划都可用于每个查询。例如,让我们生成一些数据:

DROP TABLE IF EXISTS [dbo].[DataSource];

CREATE TABLE [dbo].[DataSource]
(
    [ID] INT IDENTITY(1000, 1) PRIMARY KEY
   ,[DateTimeCreated] DATETIME2
   ,[SampleText] NVARCHAR(4000)
);

CREATE INDEX IX_DateTimeCreated ON [dbo].[DataSource] ([DateTimeCreated]);


INSERT INTO [dbo].[DataSource] ([DateTimeCreated], [SampleText])
SELECT SYSDATETIME()
      ,LEFT(REPLICATE([number], 3500), 3500)
FROM [master]..[spt_values]; 

UPDATE [dbo].[DataSource]
SET [DateTimeCreated] = '2018-01-01'
WHERE [ID] < 1051;

GO

,并将50条记录设置为日期2018-01-01。现在,清除缓冲区和缓存(不要在生产SQL实例上执行)并分别运行以下查询:

DBCC DROPCLEANBUFFERS;
DBCC FREEPROCCACHE;

GO

DECLARE @filter DATETIME2 = '2018-01-01'

SELECT *
FROM [dbo].[DataSource] 
WHERE [DateTimeCreated] = @filter;

GO

SELECT *
FROM [dbo].[DataSource] 
WHERE [DateTimeCreated] = '2018-01-01';

您将看到引擎为每个查询建立单独的执行计划,并且您可以像示例中一样执行计划(变量值将被忽略):

SELECT cacheobjtype, objtype, text,usecounts
FROM sys.dm_exec_cached_plans   
CROSS APPLY sys.dm_exec_sql_text(plan_handle)   
WHERE [objtype] = 'Adhoc'
    AND [text] LIKE '%2018-01-01%'  
    AND [text] NOT LIKE '%dm_exec_cached_plans%'
ORDER BY usecounts DESC;  

enter image description here

enter image description here

如果您要强制引擎根据变量值构建计划,则可以使用recompile选项或WITH INDEX提示:

DECLARE @filter DATETIME2 = '2018-01-01'

SELECT *
FROM [dbo].[DataSource] 
WHERE [DateTimeCreated] = @filter
OPTION (RECOMPILE);

GO

DECLARE @filter DATETIME2 = '2018-01-01'

SELECT *
FROM [dbo].[DataSource] WITH (INDEX = IX_DateTimeCreated)
WHERE [DateTimeCreated] = @filter;

GO 

enter image description here

在某些情况下,我需要提供索引提示,但通常情况下最好具有正确的索引,进行常规索引维护并编写易于引擎理解和优化而又不易于理解的T-SQL语句担心他的工作方式。

在您的情况下,该语句非常简单,因此我认为这只是忽略默认值以加快即席查询的一些默认行为。您可以将语句包装在存储过程中,然后再次查看缓存计划和执行计划。