Bagaimana Anda memeriksa apakah indeks tertentu ada dalam tabel?

288

Sesuatu seperti ini:

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

tetapi untuk indeks.

Lieven Cardoen
sumber
11
Saya berharap INFORMATION_SCHEMA benar-benar memiliki semua informasi skema
Alan Macdonald

Jawaban:

480

Anda dapat melakukannya menggunakan pilihan lurus ke depan seperti ini:

SELECT * 
FROM sys.indexes 
WHERE name='YourIndexName' AND object_id = OBJECT_ID('Schema.YourTableName')
AdaTheDev
sumber
76
Anda juga dapat membungkus pernyataan itu menjadi a IF EXISTS(SELECT * ...) BEGIN ... END.
bounav
26
Patut disebutkan bahwa YourTableNameharus nama lengkap dengan skema
Marek
2
@blasto Jika Anda menggunakan skema non-default, seperti dalam sebagian besar kasus saya, menentukan skema sebagai awalan adalah wajib. Dalam kasus lain, Anda tidak akan mendapatkan hasil dalam permintaan ini
Marek
3
Untuk mengecek tabel temp, dapat menggunakan 'tempdb.sys.indexes' dan 'tempdb .. # TableName'. (ref Bjorn D. Jensen )
crokusek
7
Hanya dengan menambahkan: "Dimulai dengan SQL Server 2016 Anda dapat menggunakan sintaks DROP INDEX IF EXISTS." Dokumentasi MS
heringer
100

Untuk SQL 2008 dan yang lebih baru , metode yang lebih ringkas, dengan cara pengkodean, untuk mendeteksi keberadaan indeks adalah dengan menggunakan INDEXPROPERTYfungsi bawaan:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

Penggunaan paling sederhana adalah dengan IndexIDproperti:

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

Jika indeks ada, yang di atas akan mengembalikan ID-nya; jika tidak, itu akan kembali NULL.

Tuan McGoo
sumber
71

AdaTheDEV, saya menggunakan sintaks Anda dan membuat yang berikut dan mengapa.

Masalah: Proses berjalan sekali seperempat, mengambil satu jam karena indeks yang hilang.

Koreksi: Ubah proses kueri atau Prosedur untuk memeriksa indeks dan membuatnya jika hilang ... Kode yang sama ditempatkan di akhir kueri dan prosedur untuk menghapus indeks karena tidak diperlukan tetapi setiap triwulan. Hanya Menampilkan drop sintaks di sini

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

Namun, sedikit penyimpangan dari pertanyaan awal mungkin berguna bagi orang-orang masa depan yang ingin DROPdan CREATEindeks, yaitu dalam skrip penempatan.

Anda dapat memintas pemeriksaan yang ada hanya dengan menambahkan yang berikut ke pernyataan buat Anda:

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

Baca lebih lanjut di sini: CREATE INDEX (Transact-SQL) - DROP_EXISTING Clause

NB Seperti disebutkan dalam komentar, indeks harus sudah ada agar klausa ini berfungsi tanpa menimbulkan kesalahan.

Chris Pickford
sumber
8
Sebenarnya .. hati-hati! Ini akan gagal jika indeks belum ada! Setidaknya dalam SQL Server 2008.
Andrey Kaipov
1
... dan masih gagal di SQL 2016
Magier
2
Efek lain (mungkin jelas) adalah bahwa ia akan selalu membuat kembali indeks. Ini mungkin bukan yang Anda inginkan. Menjatuhkan dan Membuat indeks di atas meja besar adalah operasi yang mahal - terutama jika indeks yang ada sudah yang Anda inginkan. Pernyataan ini baik untuk penggantian satu langkah. Itu tidak membandingkan indeks yang ada - bukan kekuatan kasar "lakukan ini, bahkan jika ada - jatuhkan ... lakukan saja, cepat selesai!" :-) Ini masih membutuhkan semua pengecekan yang dicari OP. Namun, jika indeks perlu diganti, ia menggabungkan DROP / CREATE.
ripvlan
10

Jika tujuan tersembunyi pertanyaan Anda adalah DROPindeks sebelum membuat INSERTke tabel besar, maka ini berguna satu-liner:

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

Sintaks ini tersedia sejak SQL Server 2016. Dokumentasi untuk IF EXISTS:

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

Jika Anda menggunakan kunci primery, gunakan ini:

ALTER TABLE [TableName] DROP CONSTRAINT IF EXISTS [PK_name] 
Przemyslaw Remin
sumber
7

Tulis fungsi di bawah ini yang memungkinkan saya memeriksa dengan cepat untuk melihat apakah ada indeks; berfungsi seperti 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: Ini hanya mengembalikan OBJECT_ID dari tabel, tetapi itu akan NULL jika indeks tidak ada. Saya kira Anda bisa mengatur ini untuk mengembalikan index_id, tapi itu tidak berguna.

Mark Williams
sumber
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
sumber
-1

Untuk memeriksa Indeks Clustered ada pada tabel tertentu atau tidak:

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
sumber
5
Ini mengembalikan kunci primer dan batasan unik, tetapi tidak satupun dari mereka yang merupakan indeks berkerumun.
Mark Sowul
index_id = 1 tidak benar di mana klausa. Indeks dapat diberi id yang berbeda
Fuzzybear