テーブルに特定のインデックスが存在するかどうかをどのように確認しますか?


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 2013

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

インデックスが存在する場合、上記はそのIDを返します。そうでない場合は、戻りNULLます。


71

AdaTheDEV、私はあなたの構文を使用して、以下とその理由を作成しました。

問題:インデックスが欠落しているため、プロセスは四半期に1回実行され、1時間かかります。

修正:クエリプロセスまたはプロシージャを変更してインデックスをチェックし、欠落している場合は作成する...同じコードがクエリの最後に配置され、インデックスは削除されます。ここにドロップ構文のみを表示

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

元の質問から若干のずれは、しかし、将来のここに着陸したい人のために有用であることを証明し得るDROPCREATE展開スクリプトのインデックス、すなわち。

createステートメントに以下を追加するだけで、存在チェックをバイパスできます。

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

詳細はこちら:CREATE INDEX(Transact-SQL)-DROP_EXISTING句

注意コメントで述べたように、この句がエラーをスローせずに機能するには、インデックスがすでに存在している必要があります。


8
実際に..注意してください!インデックスが存在しない場合、これは失敗します!少なくともSQL Server 2008では
Andrey Kaipov

1
...そしてそれでもSQL 2016で失敗する
Magier

2
別の(おそらく明白な)効果は、常にインデックスを再作成することです。これはあなたが望むものではないかもしれません。大きなテーブルでのインデックスの削除と作成はコストのかかる操作です。特に、既存のインデックスが既に必要な場合はそうです。このステートメントは、1ステップの交換に適しています。それは既存のインデックスを比較しません-むしろ、力ずくで「既存のものであってもこれを実行してください-ドロップしてください...実行してください!」:-)それでも、OPが探していたすべてのチェックが必要です。ただし、インデックスを置き換える必要がある場合は、DROP / CREATEを組み合わせます。
ripvlan 2017年

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
これは主キーと一意の制約を返しますが、これらは必ずしもクラスター化インデックスではありません。
Mark Sowul 2013

index_id = 1は、where句が正しくありません。インデックスには別のIDを割り当てることができます
Fuzzybear
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.