Come si controlla se esiste un certo indice in una tabella?


288

Qualcosa come questo:

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

ma per gli indici.


11
Vorrei che INFORMATION_SCHEMA avesse effettivamente tutte le informazioni sullo schema
Alan Macdonald,

Risposte:


480

Puoi farlo usando una selezione diretta in questo modo:

SELECT * 
FROM sys.indexes 
WHERE name='YourIndexName' AND object_id = OBJECT_ID('Schema.YourTableName')

76
Puoi anche racchiudere la frase in a IF EXISTS(SELECT * ...) BEGIN ... END.
Bounav,

26
Vale la pena ricordare che YourTableNamedovrebbe essere il nome completo con schema
Marek,

2
@blasto Se si utilizza uno schema non predefinito, come nella maggior parte dei miei casi, è obbligatorio specificare lo schema come prefisso. In altri casi, non otterrai alcun risultato in questa query
Marek,

3
Per verificare una tabella temporanea, è possibile utilizzare "tempdb.sys.indexes" e "tempdb .. # TableName". (ref Bjorn D. Jensen )
crokusek,

7
Solo per aggiungere: "A partire da SQL Server 2016 è possibile utilizzare la sintassi DROP INDEX IF EXISTS." Documentazione MS
Heringer

100

Per SQL 2008 e versioni successive , un metodo più conciso, in termini di codifica, per rilevare l'esistenza dell'indice è l'utilizzo della INDEXPROPERTYfunzione integrata:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

L'uso più semplice è con la IndexIDproprietà:

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

Se l'indice esiste, quanto sopra restituirà il suo ID; in caso contrario, tornerà NULL.


71

AdaTheDEV, ho usato la tua sintassi e ho creato quanto segue e perché.

Problema: il processo viene eseguito una volta al trimestre impiegando un'ora a causa dell'indice mancante.

Correzione: modificare il processo di query o la procedura per verificare l'indice e crearlo se mancante ... Lo stesso codice viene inserito alla fine della query e la procedura per rimuovere l'indice poiché non è necessario ma trimestrale. Mostra solo la sintassi di rilascio qui

-- 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

15

Una leggera deviazione dalla domanda originale può tuttavia rivelarsi utile per le persone che atterrano qui che desiderano DROPe CREATEun indice, ovvero in uno script di distribuzione.

È possibile ignorare il controllo esistente semplicemente aggiungendo quanto segue all'istruzione create:

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

Maggiori informazioni qui: CREATE INDEX (Transact-SQL) - Clausola DROP_EXISTING

NB Come indicato nei commenti, l'indice deve già esistere affinché questa clausola funzioni senza generare un errore.


8
In realtà .. stai attento! Questo fallirà se l'indice non esiste già! Almeno in SQL Server 2008.
Andrey Kaipov,

1
... e fallisce ancora in SQL 2016
Magier,

2
Un altro effetto (forse ovvio) è che ricrea sempre l'indice. Questo potrebbe non essere quello che vuoi. Eliminare e creare un indice su una tabella di grandi dimensioni è un'operazione costosa, specialmente se l'indice esistente è già quello desiderato. Questa affermazione è utile per la sostituzione in un solo passaggio. Non confronta l'indice esistente - piuttosto una forza bruta "fai questo, anche se esistente - lascialo cadere ... fallo, fallo!" :-) Richiede ancora tutto il controllo che OP stava cercando. Tuttavia, se l'indice deve essere sostituito, combina DROP / CREATE.
ripvlan

10

Se lo scopo nascosto della tua domanda è DROPl'indice prima di passare INSERTa una tabella di grandi dimensioni, questo è utile in una riga:

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

Questa sintassi è disponibile da SQL Server 2016. Documentazione per IF EXISTS:

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

Nel caso in cui tu abbia a che fare con una chiave di base, usa questa:

ALTER TABLE [TableName] DROP CONSTRAINT IF EXISTS [PK_name] 

7

Ha scritto la seguente funzione che mi consente di verificare rapidamente se esiste un indice; funziona proprio come 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: restituisce semplicemente OBJECT_ID della tabella, ma sarà NULL se l'indice non esiste. Suppongo che potresti impostarlo per restituire index_id, ma non è molto utile.


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

-1

Per verificare che l'indice cluster sia presente su una tabella particolare o meno:

SELECT * FROM SYS.indexes 
WHERE index_id = 1 AND name IN (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'Table_Name')

5
Ciò restituisce chiavi primarie e vincoli univoci, ma nessuno di questi è necessariamente un indice cluster.
Mark Sowul,

index_id = 1 non è corretto dove clausola.
All'indice
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.