Как проверить, существует ли определенный индекс в таблице?


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». (ссылка Бьорн Д. Йенсен )
Crokusek

7
Просто добавлю: «Начиная с SQL Server 2016, вы можете использовать синтаксис DROP INDEX IF EXISTS». MS документация
Heringer

101

Для 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

NB. Как уже упоминалось в комментариях, индекс должен уже существовать, чтобы это предложение работало без ошибки.


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

1
... и он по- прежнему не в SQL 2016
Magier

2
Другой (возможно, очевидный) эффект заключается в том, что он всегда пересоздает индекс. Это может быть не то, что вы хотите. Удаление и создание индекса для большой таблицы - дорогостоящая операция, особенно если существующий индекс уже тот, который вам нужен. Это утверждение хорошо для одношаговой замены. Он не сравнивает существующий индекс - скорее грубая сила "сделай это, даже если он существует - брось его ... просто сделай это, сделай это!" :-) Это все еще требует всей проверки, которую искал OP. Однако, если индекс нуждается в замене, он объединяет 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

РЕДАКТИРОВАТЬ: Это просто возвращает 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 неверно, где предложение.
Индексу
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.