Làm thế nào để bạn kiểm tra nếu một chỉ mục nhất định tồn tại trong một bảng?


288

Một cái gì đó như thế này:

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

nhưng đối với chỉ số.


11
Tôi muốn THÔNG TIN_SCHema thực sự có tất cả thông tin lược đồ
Alan Macdonald

Câu trả lời:


480

Bạn có thể làm điều đó bằng cách sử dụng một chuyển tiếp thẳng như thế này:

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

76
Bạn cũng có thể gói câu lệnh thành a IF EXISTS(SELECT * ...) BEGIN ... END.
bounav

26
Điều đáng nói YourTableNamelà tên đầy đủ với lược đồ
Marek

2
@blasto Nếu bạn sử dụng lược đồ không mặc định, như trong hầu hết các trường hợp của tôi, việc chỉ định lược đồ làm tiền tố là bắt buộc. Trong trường hợp khác, bạn sẽ không nhận được bất kỳ kết quả nào trong truy vấn này
Marek

3
Để kiểm tra bảng tạm thời, có thể sử dụng 'tempdb.sys.indexes' và 'tempdb .. # TableName'. (ref Bjorn D. Jensen )
crokusek

7
Chỉ cần thêm: "Bắt đầu với SQL Server 2016, bạn có thể sử dụng cú pháp DROP INDEX IF EXISTS." Tài liệu MS
heringer

100

Đối với SQL 2008 và mới hơn , một phương pháp ngắn gọn hơn, mã hóa khôn ngoan, để phát hiện sự tồn tại của chỉ mục là sử dụng hàm INDEXPROPERTYdựng sẵn:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

Cách sử dụng đơn giản nhất là với thuộc IndexIDtính:

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

Nếu chỉ mục tồn tại, ở trên sẽ trả về ID của nó; nếu không, nó sẽ quay trở lại NULL.


71

AdaTheDEV, tôi đã sử dụng cú pháp của bạn và tạo ra sau đây và tại sao.

Vấn đề: Quá trình chạy một lần một phần tư mất một giờ do thiếu chỉ số.

Khắc phục: Thay đổi quy trình truy vấn hoặc Quy trình để kiểm tra chỉ mục và tạo chỉ mục nếu thiếu ... Cùng một mã được đặt ở cuối truy vấn và thủ tục để xóa chỉ mục vì không cần thiết nhưng hàng quý. Chỉ hiển thị cú pháp thả ở đây

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

Tuy nhiên, một sai lệch nhỏ so với câu hỏi ban đầu có thể chứng minh hữu ích cho những người tương lai đến đây muốn DROPCREATEmột chỉ mục, tức là trong một kịch bản triển khai.

Bạn có thể bỏ qua kiểm tra tồn tại chỉ bằng cách thêm phần sau vào câu lệnh tạo của bạn:

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

Đọc thêm tại đây: CREATE INDEX (Transact-SQL) - Điều khoản DROP_EXISTING

NB Như đã đề cập trong các ý kiến, chỉ mục phải tồn tại để mệnh đề này hoạt động mà không gây ra lỗi.


8
Thật ra .. hãy cẩn thận! Điều này sẽ thất bại nếu chỉ mục không tồn tại! Ít nhất là trong SQL Server 2008
Andrey Kaipov

1
... và nó vẫn thất bại trong SQL 2016
Magier

2
Một hiệu ứng khác (có thể rõ ràng) là nó sẽ luôn tạo lại chỉ mục. Đây có thể không phải là những gì bạn muốn. Thả và tạo một chỉ mục trên một bảng lớn là một hoạt động đắt tiền - đặc biệt nếu chỉ mục hiện có đã là chỉ số bạn muốn. Tuyên bố này là tốt cho thay thế một bước. Nó không so sánh chỉ số hiện tại - thay vào đó là một lực lượng vũ phu "làm điều này, ngay cả khi có sẵn - bỏ nó ... chỉ cần làm điều đó, hoàn thành!" :-) Nó vẫn yêu cầu tất cả các kiểm tra mà OP đang tìm kiếm. Tuy nhiên, nếu chỉ số cần thay thế, nó sẽ kết hợp DROP / CREATE.
ripvlan

10

Nếu mục đích ẩn của câu hỏi của bạn là DROPchỉ mục trước khi thực hiện INSERTmột bảng lớn, thì đây là một mục đích hữu ích:

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

Cú pháp này có sẵn kể từ SQL Server 2016. Tài liệu cho IF EXISTS:

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

Trong trường hợp bạn xử lý một khóa mồi thay thế, sau đó sử dụng:

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

7

Đã viết hàm dưới đây cho phép tôi nhanh chóng kiểm tra xem liệu chỉ mục có tồn tại không; hoạt động giống như OBarget_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: Điều này chỉ trả về OBarget_ID của bảng, nhưng nó sẽ là NULL nếu chỉ mục không tồn tại. Tôi cho rằng bạn có thể thiết lập điều này để trả về index_id, nhưng điều đó không hữu ích lắm.


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

Để kiểm tra Clustered Index có tồn tại trên bảng cụ thể hay không:

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
Điều này trả về các khóa chính và các ràng buộc duy nhất, nhưng không có khóa nào trong số đó nhất thiết phải là một chỉ mục được nhóm.
Mark Sowul

index_id = 1 không đúng trong mệnh đề. Chỉ mục có thể được chỉ định một id khác
Fuzzybear
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.