Como você verifica se existe um determinado índice em uma tabela?

288

Algo assim:

SELECT
* 
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
WHERE CONSTRAINT_NAME ='FK_TreeNodesBinaryAssets_BinaryAssets'
and TABLE_NAME = 'TreeNodesBinaryAssets'

mas para índices.

Lieven Cardoen
fonte
11
Desejo INFORMATION_SCHEMA realmente tinha todas as informações do esquema
Alan Macdonald

Respostas:

480

Você pode fazer isso usando uma seleção direta como esta:

SELECT * 
FROM sys.indexes 
WHERE name='YourIndexName' AND object_id = OBJECT_ID('Schema.YourTableName')
AdaTheDev
fonte
76
Você também pode agrupar a instrução em a IF EXISTS(SELECT * ...) BEGIN ... END.
bounav
26
Vale a pena mencionar que YourTableNamedeve ser o nome completo com esquema
Marek
2
@ blasto Se você usa um esquema não padrão, como na maioria dos meus casos, a especificação do esquema como prefixo é obrigatória. Em outro caso, você não obterá resultados nesta consulta
Marek
3
Para verificar em uma tabela temporária, use 'tempdb.sys.indexes' e 'tempdb .. # TableName'. (ref Bjorn D. Jensen )
crokusek
7
Apenas para adicionar: "A partir do SQL Server 2016, você pode usar a sintaxe DROP INDEX IF EXISTS." Documentação do MS
heringer 01/09/17
100

Para o SQL 2008 e versões mais recentes , um método mais conciso, em termos de codificação, para detectar a existência de índice é usando a INDEXPROPERTYfunção interna:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

O uso mais simples é com a IndexIDpropriedade:

If IndexProperty(Object_Id('MyTable'), 'MyIndex', 'IndexID') Is Null

Se o índice existir, o acima retornará seu ID; caso contrário, retornará NULL.

Mr McGoo
fonte
71

AdaTheDEV, usei sua sintaxe e criei o seguinte e por quê.

Problema: o processo é executado uma vez por trimestre, levando uma hora devido à falta do índice.

Correção: Altere o processo de consulta ou o Procedimento para verificar o índice e criá-lo se estiver ausente ... O mesmo código é colocado no final da consulta e do procedimento para remover o índice, pois não é necessário, mas trimestralmente. Mostrando apenas soltar sintaxe aqui

-- drop the index 
begin

  IF EXISTS (SELECT *  FROM sys.indexes  WHERE name='Index_Name' 
    AND object_id = OBJECT_ID('[SchmaName].[TableName]'))
  begin
    DROP INDEX [Index_Name] ON [SchmaName].[TableName];
  end

end
Hank Freeman
fonte
15

Um pequeno desvio da pergunta original, no entanto, pode ser útil para futuras pessoas que desembarcarem aqui que desejam DROPeCREATE um índice, ou seja, em um script de implantação.

Você pode ignorar a verificação existente simplesmente adicionando o seguinte à sua instrução create:

CREATE INDEX IX_IndexName
ON dbo.TableName
WITH (DROP_EXISTING = ON);

Leia mais aqui: CREATE INDEX (Transact-SQL) - Cláusula DROP_EXISTING

NB Como mencionado nos comentários, o índice já deve existir para que esta cláusula funcione sem gerar um erro.

Chris Pickford
fonte
8
Na verdade .. tenha cuidado! Isso falhará se o índice ainda não existir! Pelo menos no SQL Server 2008.
Andrey Kaipov 10/17/17
1
... e ele ainda falha no SQL 2016
Magier
2
Outro efeito (talvez óbvio) é que ele sempre recriará o índice. Pode não ser o que você deseja. Descartar e criar um índice em uma tabela grande é uma operação cara - especialmente se o índice existente já for o desejado. Esta declaração é boa para a substituição em uma etapa. Ele não compara o índice existente - e sim uma força bruta "faça isso, mesmo que exista - descarte-o ... apenas faça-o, pronto!" :-) Ainda requer toda a verificação que o OP estava procurando. No entanto, se o índice precisar ser substituído, ele combina DROP / CREATE.
ripvlan
10

Se o objetivo oculto da sua pergunta é DROPo índice antes de criar INSERTuma tabela grande, isso é útil:

DROP INDEX IF EXISTS [IndexName] ON [dbo].[TableName]

Essa sintaxe está disponível desde o SQL Server 2016. Documentação para IF EXISTS :

https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/

Caso você lide com uma chave de primery, use o seguinte:

ALTER TABLE [TableName] DROP CONSTRAINT IF EXISTS [PK_name] 
Przemyslaw Remin
fonte
7

Escreveu a função abaixo que me permite verificar rapidamente se existe um índice; funciona exatamente como OBJECT_ID.

CREATE FUNCTION INDEX_OBJECT_ID (
    @tableName VARCHAR(128),
    @indexName VARCHAR(128)
    )
RETURNS INT
AS
BEGIN
    DECLARE @objectId INT

    SELECT @objectId = i.object_id
    FROM sys.indexes i
    WHERE i.object_id = OBJECT_ID(@tableName)
    AND i.name = @indexName

    RETURN @objectId
END
GO

EDIT: Isso apenas retorna o OBJECT_ID da tabela, mas será NULL se o índice não existir. Suponho que você possa definir isso para retornar index_id, mas isso não é super útil.

Mark Williams
fonte
1
-- Delete index if exists
IF EXISTS(SELECT TOP 1 1 FROM sys.indexes indexes INNER JOIN sys.objects 
objects ON indexes.object_id = objects.object_id WHERE indexes.name 
='Your_Index_Name' AND objects.name = 'Your_Table_Name')
BEGIN
    PRINT 'DROP INDEX [Your_Index_Name] ON [dbo].[Your_Table_Name]'
    DROP INDEX [our_Index_Name] ON [dbo].[Your_Table_Name]
END
GO
Paolo Argentieri
fonte
-1

Para verificar o índice clusterizado existe em uma tabela específica ou não:

SELECT * FROM SYS.indexes 
WHERE index_id = 1 AND name IN (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'Table_Name')
Rajiv Singh
fonte
5
Isso retorna chaves primárias e restrições exclusivas, mas nenhuma delas é necessariamente um índice em cluster.
Mark Sowul
index_id = 1 está incorreto na cláusula where. Pode ser atribuído um ID diferente ao
índice