SQL Server 何时决定使用新索引?

DFo*_*k42 3 performance sql-server execution-plan sql-server-2008-r2 index-tuning

我一直在运行公司购买的某些软件的服务器上进行一些维护,因此我无法真正更改查询的编写方式。我使用了一些工具来确定服务器上一些缺失的索引。但是,使用我的工具,我没有看到哪些查询指示了这些。但是,我确实会监视正在写入和读取的索引量。

所以,我的问题是,在添加已确定为缺失的新索引时,SQL Server 何时注意到新索引并确定它们是否真的有助于查询?是在创建索引后立即再次运行查询,还是更复杂?

Tho*_*ger 8

SQL Server 什么时候注意到新索引并确定它们是否真的有助于查询?

立即地。 由于架构更改,创建索引会导致重新编译

这是一个例子。首先在测试数据库中设置对象:

use TestDatabase;
go

if exists (select 1 from sys.tables where object_id = object_id('dbo.TestTable1'))
    drop table dbo.TestTable1;
create table dbo.TestTable1
(
    Id int identity(1, 1) not null
);
go

insert into dbo.TestTable1
default values;
go 1000

if exists (select 1 from sys.procedures where object_id = object_id('dbo.GetIdFromTestTable1'))
    drop proc dbo.GetIdFromTestTable1;
go
create proc dbo.GetIdFromTestTable1
    @Id int
as
    select Id
    from dbo.TestTable1
    where Id = @Id;
go
Run Code Online (Sandbox Code Playgroud)

如您所料,运行此存储过程将导致表扫描:

exec dbo.GetIdFromTestTable1 500;
go
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

现在让我们创建一个索引,我们知道这个查询可以从中受益:

create unique index IX_TestTable1_Id
on dbo.TestTable1 (Id);
go
Run Code Online (Sandbox Code Playgroud)

重新执行存储过程,看看执行后的计划:

exec dbo.GetIdFromTestTable1 500;
go
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

我们可以看到我们的表扫描变成了索引查找。这表明生成了一个新计划。

为什么?

我们可以使用 XEvents 会话跟踪此行为:

if exists (select 1 from sys.server_event_sessions where name = N'RecompileTracing')
    drop event session RecompileTracing
    on server;
go
create event session RecompileTracing
on server
add event sqlserver.sql_statement_recompile
(
    set
        collect_statement = 1,
        collect_object_name = 1
)
add target package0.event_file
(
    set
        filename = N'RecompileTracing.xel'
);
go

alter event session RecompileTracing
on server
state = start;
go

/*
alter event session RecompileTracing
on server
state = stop;
go

drop event session RecompileTracing
on server;
go
*/
Run Code Online (Sandbox Code Playgroud)

我们从上面的插图/repro 中得到的输出是我们sql_statement_recompile在语句上有一个select Id from dbo.TestTable1 where Id = @Id;(用删除的空格/制表符/换行符浓缩),并且recompile_causeSchema changed