Database
 sql >> Base de Dados >  >> RDS >> Database

Índices ausentes no MS SQL ou otimização em pouco tempo


Ao executar uma consulta, o otimizador do SQL Server tenta encontrar o melhor plano de consulta com base nos índices existentes e nas estatísticas mais recentes disponíveis por um tempo razoável, é claro, se esse plano ainda não estiver armazenado no cache do servidor. Se não, a consulta é executada de acordo com este plano e o plano é armazenado no cache do servidor. Se o plano já foi construído para esta consulta, a consulta é executada de acordo com o plano existente.

Estamos interessados ​​na seguinte questão:

Durante a compilação de um plano de consulta, ao classificar possíveis índices, se o servidor não encontrar o melhor índice, o índice ausente é marcado no plano de consulta e o servidor mantém estatísticas sobre tais índices:quantas vezes o servidor usaria esse índice e quanto custaria essa consulta.



Neste artigo, vamos analisar esses índices ausentes – como lidar com eles.

Vamos considerar isso em um exemplo particular. Crie algumas tabelas em nosso banco de dados em um servidor local e de teste:

[expandir título =”Código”]
if object_id ('orders_detail') is not null drop table orders_detail;

if object_id('orders') is not null drop table orders;

go

create table orders

(

id int identity primary key,

dt datetime,

seller nvarchar(50)

)

create table orders_detail

(

id int identity primary key,

order_id int foreign key references orders(id),

product nvarchar(30),

qty int,

price money,

cost as qty * price

)

go

with cte as

(

select 1 id union all

select id+1 from cte where id < 20000

)

insert orders

select

dt,

seller

from

(

select

dateadd(day,abs(convert(int,convert(binary(4),newid()))%365),'2016-01-01') dt,

abs(convert(int,convert(binary(4),newid()))%5)+1 seller_id

from cte

) c

left join

(

values
(1,'John'),

(2,'Mike'),

(3,'Ann'),

(4,'Alice'),

(5,'George')
) t (id,seller) on t.id = c.seller_id

option(maxrecursion 0)

 

insert orders_detail

select

order_id,

product,

qty,

price

from

(

select

o.id as order_id,

abs(convert(int,convert(binary(4),newid()))%5)+1 product_id,

abs(convert(int,convert(binary(4),newid()))%20)+1 qty

from orders o cross join

(

select top(abs(convert(int,convert(binary(4),newid()))%5)+1) *

from

(

values (1),(2),(3),(4),(5),(6),(7),(8)

) n(num)

) n

) c

left join

(

values
(1,'Sugar', 50),

(2,'Milk', 80),

(3,'Bread', 20),

(4,'Pasta', 40),

(5,'Beer', 100)

) t (id,product, price) on t.id = c.product_id

go

[/expandir]

A estrutura é simples e consiste em duas tabelas. A primeira tabela é chamada de pedidos com campos como identificador, data de venda e vendedor. A segunda são os detalhes do pedido, onde algumas mercadorias são especificadas com preço e quantidade.

Veja uma consulta simples e seu plano:
select count(*) from orders o join orders_detail d on o.id = d.order_id

where d.cost > 1800

go



Podemos ver uma dica verde sobre o índice ausente na exibição gráfica do plano de consulta. Se você clicar com o botão direito do mouse e selecionar “Missing Index Details ..”, haverá o texto do índice sugerido. A única coisa a fazer é remover os comentários no texto e dar um nome ao índice. O script está pronto para ser executado.

Não construiremos o índice que recebemos da dica fornecida pelo SSMS. Em vez disso, veremos se esse índice será recomendado por visualizações dinâmicas vinculadas a índices ausentes. As vistas são as seguintes:
select * from sys.dm_db_missing_index_group_stats

select * from sys.dm_db_missing_index_details

select * from sys.dm_db_missing_index_groups



Como podemos ver, existem algumas estatísticas sobre índices ausentes na primeira visualização:
  1. Quantas vezes uma pesquisa seria realizada se o índice sugerido existisse?
  2. Quantas vezes uma verificação seria executada se o índice sugerido existisse?
  3. Última data e hora em que usamos o índice
  4. O custo real atual do plano de consulta sem o índice sugerido.

A segunda visão é o corpo do índice:
  1. Banco de dados
  2. Objeto/tabela
  3. Colunas classificadas
  4. Colunas adicionadas para aumentar a cobertura do índice

A terceira vista é a combinação da primeira e da segunda vista.

Assim, não é difícil obter um script que gere um script para criar índices ausentes dessas visualizações dinâmicas. O roteiro é o seguinte:

[expandir título=”Código”]
with igs as

(

select *

from sys.dm_db_missing_index_group_stats

)

, igd as

(

select *,

isnull(equality_columns,'')+','+isnull(inequality_columns,'') as ix_col

from sys.dm_db_missing_index_details

)

select --top(10)

'use ['+db_name(igd.database_id)+'];

create index ['+'ix_'+replace(convert(varchar(10),getdate(),120),'-','')+'_'+convert(varchar,igs.group_handle)+'] on '+

igd.[statement]+'('+

case

when left(ix_col,1)=',' then stuff(ix_col,1,1,'')

when right(ix_col,1)=',' then reverse(stuff(reverse(ix_col),1,1,''))

else ix_col

end

+') '+isnull('include('+igd.included_columns+')','')+' with(online=on, maxdop=0)

go

' command

,igs.user_seeks

,igs.user_scans

,igs.avg_total_user_cost

from igs

join sys.dm_db_missing_index_groups link on link.index_group_handle = igs.group_handle

join igd on link.index_handle = igd.index_handle

where igd.database_id = db_id()

order by igs.avg_total_user_cost * igs.user_seeks desc

[/expandir]

Para eficiência do índice, os índices ausentes são gerados. A solução perfeita é quando esse conjunto de resultados não retorna nada. Em nosso exemplo, o conjunto de resultados retornará pelo menos um índice:



Quando não há tempo e você não tem vontade de lidar com os bugs do cliente, executei a consulta, copiei a primeira coluna e executei no servidor. Depois disso, tudo funcionou bem.

Eu recomendo tratar as informações sobre esses índices de forma consciente. Por exemplo, se o sistema recomendar os seguintes índices:
create index ix_01 on tbl1 (a,b) include (c)

create index ix_02 on tbl1 (a,b) include (d)

create index ix_03 on tbl1 (a)

E esses índices são usados ​​para a pesquisa, é bastante óbvio que é mais lógico substituir esses índices por um que cubra todos os três sugeridos:
create index ix_1 on tbl1 (a,b) include (c,d)

Assim, fazemos uma revisão dos índices ausentes antes de implantá-los no servidor de produção. Embora…. Novamente, por exemplo, implantei os índices perdidos no servidor TFS, aumentando assim o desempenho geral. Levou um tempo mínimo para realizar essa otimização. No entanto, ao mudar do TFS 2015 para o TFS 2017, enfrentei o problema de não haver atualização devido a esses novos índices. No entanto, eles podem ser facilmente encontrados pela máscara
select * from sys.indexes where name like 'ix[_]2017%'



Ferramenta útil:


dbForge Index Manager – suplemento SSMS útil para analisar o status de índices SQL e corrigir problemas com fragmentação de índice.