Як перевірити, чи існує певний індекс у таблиці?


288

Щось на зразок цього:

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

але для індексів.


11
Я хотів би, щоб INFORMATION_SCHEMA насправді мала всю схему інформації
Алан Макдональд

Відповіді:


480

Ви можете зробити це за допомогою прямого переднього вибору:

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

76
Ви також можете загортати заяву в IF EXISTS(SELECT * ...) BEGIN ... END.
bounav

26
Варто згадати, що YourTableNameмає бути повне ім’я зі схемою
Marek

2
@blasto Якщо ви використовуєте схему, що не використовується за замовчуванням, як у більшості моїх випадків, вказувати схему як префікс обов'язково. В іншому випадку ви не отримаєте жодних результатів у цьому запиті
Marek

3
Щоб перевірити наявність темп-таблиці, можна скористатися 'tempdb.sys.indexes' та 'tempdb .. # TableName'. (ref Bjorn D. Jensen )
crokusek

7
Просто додати: "Починаючи з SQL Server 2016, ви можете використовувати синтаксис DROP INDEX IF EXISTS." MS документація
heringer

100

Для SQL 2008 та новіших версій більш стислий метод кодування для виявлення існування індексу - за допомогою INDEXPROPERTYвбудованої функції:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

Найпростіше використання - це IndexIDвластивість:

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

Якщо індекс існує, вищевказаний поверне свій ідентифікатор; якщо цього не відбудеться, він повернеться NULL.


71

AdaTheDEV, я використав ваш синтаксис і створив наступне і чому.

Проблема: процес проходить один раз на квартал, займаючи годину через відсутність індексу.

Виправлення: Змініть процес запиту чи процедуру, щоб перевірити наявність індексу та створити його, якщо він відсутній ... Той самий код розміщується в кінці запиту та процедури для видалення індексу, оскільки він потрібен, але щоквартально. Тут відображається лише синтаксис краплі

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

Невелике відхилення від початкового питання, однак, може виявитися корисним для майбутніх людей, які приземляються сюди, бажаючі DROPта CREATEіндексувати, тобто в сценарії розгортання.

Ви можете обійти існуючий чек, просто додавши в заяву create таке:

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

Детальніше читайте тут: CREATE INDEX (Transact-SQL) - пункт DROP_EXISTING

Примітка. Як зазначалося в коментарях, індекс повинен вже існувати, щоб ця стаття працювала без помилки.


8
Насправді .. будьте обережні! Це не вдасться, якщо індекс ще не існує! Принаймні, у SQL Server 2008.
Андрій Кайпов

1
... і він все ще не вдається в SQL 2016
Magier

2
Інший (можливо очевидний) ефект полягає в тому, що він завжди буде відновлювати індекс. Це може бути не те, що ви хочете. Видалення та створення індексу на великій таблиці - це дорога операція - особливо, якщо існуючий індекс вже такий, який ви хочете. Це твердження добре для одномоментної заміни. Він не порівнює існуючий індекс - скоріше груба сила "зробіть це, навіть якщо є - скиньте його ... просто зробіть це, виконайте!" :-) Це все ще вимагає всіх перевірок, які ОП шукала. Однак якщо індекс потребує заміни, він об'єднує DROP / CREATE.
ripvlan

10

Якщо прихована мета вашого питання полягає DROPв індексуванні перед тим, як зробити INSERTвелику таблицю, тоді це корисно однолінійним:

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

Цей синтаксис доступний з SQL Server 2016. Документація для IF EXISTS:

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

Якщо ви замість цього використовуєте праймер-ключ, використовуйте це:

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

7

Написав нижче функцію, яка дозволяє мені швидко перевірити, чи існує індекс; працює так само, як 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: Це просто повертає OBJECT_ID таблиці, але це буде NULL, якщо індекс не існує. Я думаю, ви можете встановити це для повернення index_id, але це не дуже корисно.


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

Щоб перевірити існування кластерного індексу на певній таблиці чи ні:

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
Це повертає первинні ключі та унікальні обмеження, але жоден з них не є обов'язково кластерним індексом.
Марк Совул

index_id = 1 неправильно, де пункт. Індексу може бути призначений інший ідентифікатор
Fuzzybear
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.