Jak sprawdzić, czy w tabeli istnieje określony indeks?

288

Coś takiego:

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

ale dla indeksów.

Lieven Cardoen
źródło
11
Chciałbym, aby INFORMACJE_SCHEMA faktycznie posiadał wszystkie informacje o schemacie
Alan Macdonald

Odpowiedzi:

480

Możesz to zrobić za pomocą prostego wyboru, takiego jak to:

SELECT * 
FROM sys.indexes 
WHERE name='YourIndexName' AND object_id = OBJECT_ID('Schema.YourTableName')
AdaTheDev
źródło
76
Możesz także zawinąć instrukcję w IF EXISTS(SELECT * ...) BEGIN ... END.
bounav
26
Warto wspomnieć, że YourTableNamepowinno to być pełne imię i nazwisko ze schematem
Marek
2
@blasto Jeśli używasz schematu innego niż domyślny, jak w większości moich przypadków, podanie schematu jako prefiksu jest obowiązkowe. W innym przypadku nie otrzymasz żadnych wyników w tym zapytaniu
Marek
3
Aby sprawdzić w tabeli tymczasowej, można użyć plików „tempdb.sys.indexes” i „tempdb .. # TableName”. (zob. Bjorn D. Jensen )
crokusek
7
Wystarczy dodać: „Począwszy od SQL Server 2016 możesz używać składni DROP INDEX IF IFISTIST.” Dokumentacja stwardnienia rozsianego
heringer
100

W SQL 2008 i nowszych bardziej zwięzłą, kodową metodą wykrywania istnienia indeksu jest użycie INDEXPROPERTYwbudowanej funkcji:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

Najprostszym zastosowaniem jest IndexIDwłaściwość:

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

Jeśli indeks istnieje, powyższe zwróci jego identyfikator; jeśli nie, wróci NULL.

Pan McGoo
źródło
71

AdaTheDEV, użyłem twojej składni i stworzyłem następujące i dlaczego.

Problem: Proces przebiega raz na kwadrans i zajmuje godzinę z powodu braku indeksu.

Korekta: Zmień proces zapytania lub Procedurę, aby sprawdzić indeks i utwórz go, jeśli go brakuje ... Na końcu zapytania i procedury usuwany jest ten sam kod, aby usunąć indeks, ponieważ nie jest on potrzebny, ale co kwartał. Pokazuje tutaj tylko składnię

-- 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
źródło
15

Nieznaczne odchylenie od pierwotnego pytania jednak mogą okazać się przydatne dla przyszłych osób lądujących tu chcących DROPi CREATEindeksu, czyli w skrypcie wdrażania.

Możesz pominąć istniejący czek, po prostu dodając następujące elementy do instrukcji create:

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

Przeczytaj więcej tutaj: UTWÓRZ INDEKS (Transact-SQL) - DROP_EXISTING Klauzula

Uwaga: Jak wspomniano w komentarzach, indeks musi już istnieć, aby ta klauzula działała bez zgłaszania błędu.

Chris Pickford
źródło
8
Właściwie .. bądź ostrożny! To się nie powiedzie, jeśli indeks już nie istnieje! Przynajmniej w SQL Server 2008.
Andrey Kaipov
1
... i nadal nie działa w SQL 2016
Magier
2
Innym (być może oczywistym) efektem jest to, że zawsze będzie ponownie tworzyć indeks. To może nie być to, czego chcesz. Upuszczanie i tworzenie indeksu na dużej tabeli jest kosztowną operacją - szczególnie jeśli istniejący indeks jest już tym, którego potrzebujesz. To oświadczenie jest dobre w przypadku zamiany w jednym kroku. Nie porównuje istniejącego indeksu - raczej brutalną siłę „zrób to, nawet jeśli istnieje - upuść go ... po prostu zrób to, gotowe!” :-) Nadal wymaga to sprawdzenia, którego szukał OP. Jeśli jednak indeks wymaga wymiany, łączy DROP / CREATE.
ripvlan
10

Jeśli ukrytym celem twojego pytania jest DROPindeksowanie przed INSERTprzejściem do dużego stołu, to jest to przydatne w jednym wierszu:

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

Ta składnia jest dostępna od SQL Server 2016. Dokumentacja dla IF EXISTS:

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

Jeśli zamiast tego masz do czynienia z kluczem podstawowym, użyj tego:

ALTER TABLE [TableName] DROP CONSTRAINT IF EXISTS [PK_name] 
Przemysław Remin
źródło
7

Napisałem poniższą funkcję, która pozwala mi szybko sprawdzić, czy indeks istnieje; działa podobnie jak 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

EDYCJA: Zwraca tylko OBJECT_ID tabeli, ale będzie wynosić NULL, jeśli indeks nie istnieje. Przypuszczam, że możesz ustawić to tak, aby zwracało index_id, ale to nie jest bardzo przydatne.

Mark Williams
źródło
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
źródło
-1

Aby sprawdzić Indeks klastrowy istnieje na konkretnej tabeli, czy nie:

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
źródło
5
Zwraca klucze podstawowe i unikalne ograniczenia, ale żaden z nich niekoniecznie jest indeksem klastrowym.
Mark Sowul
index_id = 1 jest niepoprawny gdzie klauzula. Indeks może mieć przypisany inny identyfikator
Fuzzybear