Tạo chỉ mục không phân biệt không phải duy nhất trong câu lệnh CREATE TABLE với SQL Server


92

Có thể tạo khóa chính hoặc chỉ mục duy nhất trong câu lệnh SQL Server CREATE TABLE. Có thể tạo chỉ mục không phải là duy nhất trong câu lệnh CREATE TABLE không?

CREATE TABLE MyTable(
    a int NOT NULL
    ,b smallint NOT NULL
    ,c smallint NOT NULL
    ,d smallint NOT NULL
    ,e smallint NOT NULL

    -- This creates a primary key
    ,CONSTRAINT PK_MyTable PRIMARY KEY CLUSTERED (a)

    -- This creates a unique nonclustered index on columns b and c
    ,CONSTRAINT IX_MyTable1 UNIQUE (b, c)

    -- Is it possible to create a non-unique index on columns d and e here?
    -- Note: these variations would not work if attempted:
    -- ,CONSTRAINT IX_MyTable2 INDEX (d, e)
    -- ,CONSTRAINT IX_MyTable3 NONCLUSTERED INDEX (d, e)
);
GO

-- The proposed non-unique index should behave identically to
-- an index created after the CREATE TABLE statement. Example:
CREATE NONCLUSTERED INDEX IX_MyTable4 ON MY_TABLE (d, e);
GO

Một lần nữa, mục tiêu là tạo chỉ mục không phải là duy nhất trong câu lệnh CREATE TABLE, không phải sau nó.

Đối với những gì đáng giá, tôi không thấy [SQL Server Books Online entry for CREATE TABLE] hữu ích.

Ngoài ra, [Câu hỏi này] gần giống hệt nhau, nhưng câu trả lời được chấp nhận không áp dụng.

Câu trả lời:


122

Bạn không thể. CREATE / ALTER TABLE chỉ chấp nhận CONSTRAINT được thêm vào, không chấp nhận các chỉ mục. Thực tế là khóa chính và các ràng buộc duy nhất được thực hiện theo chỉ mục là một tác dụng phụ. Để quản lý các chỉ mục, bạn có CREATE / ALTER / DROP INDEX, như bạn đã biết.

Tại sao bạn có một yêu cầu như vậy để thêm các chỉ mục không phải là duy nhất không được phân cụm trong câu lệnh CREATE TABLE?

Lưu ý rằng SQL Server 2014 đã giới thiệu tùy chọn tạo chỉ mục nội tuyến :

CREATE TABLE MyTable(
    a int NOT NULL
    ,b smallint NOT NULL
    ,c smallint NOT NULL
    ,d smallint NOT NULL
    ,e smallint NOT NULL

    -- This creates a primary key
    ,CONSTRAINT PK_MyTable PRIMARY KEY CLUSTERED (a)

    -- This creates a unique nonclustered index on columns b and c
    ,CONSTRAINT IX_MyTable1 UNIQUE (b, c)

    -- This creates a non-clustered index on (d, e)
    ,INDEX IX_MyTable4 NONCLUSTERED (d, e)
);
GO

17
Cảm ơn vì lời giải thích tuyệt vời! Tại sao? Hoàn toàn vì lý do thẩm mỹ. Tôi nghĩ rằng có thể thuận tiện cho bất kỳ ai đọc script nếu tất cả các ràng buộc / chỉ mục được chứa trong cùng một câu lệnh. Cá nhân tôi muốn biết liệu các cột thuộc khóa ngoại cũng có chỉ mục hay không và đây có thể là một phương pháp hay để nhóm thông tin này một cách hợp lý trong cùng một câu lệnh.
Mike

Tôi nhận được Error: (1146) Table 'tablename' doesn't exist, hahahah, mỉa mai
Aminah Nuraini

13

Theo tài liệu T-SQL CREATE TABLE , vào năm 2014, định nghĩa cột hỗ trợ xác định chỉ mục:

<column_definition> ::=  
column_name <data_type>  
    ...
    [ <column_index> ]  

và ngữ pháp được định nghĩa là:

<column_index> ::=   
 INDEX index_name [ CLUSTERED | NONCLUSTERED ]  
    [ WITH ( <index_option> [ ,... n ] ) ]  
    [ ON { partition_scheme_name (column_name )   
         | filegroup_name  
         | default   
         }  
    ]   
    [ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | "NULL" } ]  

Vì vậy, rất nhiều điều bạn có thể làm như một câu lệnh riêng biệt có thể được thực hiện nội tuyến. Tôi nhận thấy includekhông phải là một tùy chọn trong ngữ pháp này vì vậy một số điều không thể thực hiện được.

CREATE TABLE MyTable(
    a int NOT NULL
    ,b smallint NOT NULL index IX_MyTable_b nonclustered
    ,c smallint NOT NULL
    ,d smallint NOT NULL
    ,e smallint NOT NULL
)

Bạn cũng có thể có các chỉ mục nội dòng được định nghĩa là một dòng khác sau các cột, nhưng trong câu lệnh tạo bảng và điều này cho phép nhiều cột trong chỉ mục, nhưng vẫn không có includemệnh đề:

< table_index > ::=   
{  
    {  
      INDEX index_name [ CLUSTERED | NONCLUSTERED ]   
         (column_name [ ASC | DESC ] [ ,... n ] )   
    | INDEX index_name CLUSTERED COLUMNSTORE  
    | INDEX index_name [ NONCLUSTERED ] COLUMNSTORE (column_name [ ,... n ] )  
    }  
    [ WITH ( <index_option> [ ,... n ] ) ]   
    [ ON { partition_scheme_name (column_name )   
         | filegroup_name  
         | default   
         }  
    ]   
    [ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | "NULL" } ]  

}   

Ví dụ ở đây, chúng tôi thêm một chỉ mục trên cả hai cột c và d:

CREATE TABLE MyTable(
    a int NOT NULL
    ,b smallint NOT NULL index IX_MyTable_b nonclustered
    ,c smallint NOT NULL
    ,d smallint NOT NULL
    ,e smallint NOT NULL

    ,index IX_MyTable_c_d nonclustered (c,d)
)

1
Điều này hoạt động tuyệt vời, và theo BOL ít nhất nó đã trở lại năm 2008. Giống như OP, tôi thấy mã mà tôi chủ yếu nhìn thấy (thường được tạo bởi SSMS) khiến nhãn cầu của tôi bị tổn thương và tôi chỉ thích các định nghĩa trên bảng của mình có ý nghĩa đối với một con người lý trí. Cảm ơn.
Wade Hatler

8

Đó là một tuyên bố riêng biệt.

Cũng không thể chèn vào một bảng và chọn từ nó và xây dựng một chỉ mục trong cùng một câu lệnh.

Mục nhập BOL chứa thông tin bạn cần:

ĐÃ ĐIỀU CHỈNH | KHÔNG CHỈNH SỬA
Cho biết rằng một chỉ mục được phân nhóm hoặc không phân biệt được tạo cho khóa CHÍNH hoặc Ràng buộc DUY NHẤT. Các ràng buộc CHÍNH CHÍNH mặc định là ĐÃ ĐIỀU CHỈNH và các ràng buộc DUY NHẤT mặc định là KHÔNG ĐƯỢC ĐIỀU CHỈNH.

Trong câu lệnh CREATE TABLE, CLUSTERED chỉ có thể được chỉ định cho một ràng buộc. Nếu CLUSTERED được chỉ định cho một ràng buộc UNIQUE và một ràng buộc PRIMARY KEY cũng được chỉ định, PRIMARY KEY sẽ mặc định là NONCLUSTERED.

Bạn có thể tạo chỉ mục trên trường PK, nhưng không phải chỉ mục không phân cụm trên trường ràng buộc không phải pk không phải là duy nhất.

Chỉ mục NCL không liên quan đến cấu trúc của bảng và không phải là một ràng buộc đối với dữ liệu bên trong bảng. Đó là một thực thể riêng biệt hỗ trợ bảng nhưng không phải là không thể thiếu với chức năng hoặc thiết kế của nó.

Đó là lý do tại sao nó là một tuyên bố riêng biệt. Chỉ mục NCL không liên quan đến bảng từ quan điểm thiết kế (mặc dù tối ưu hóa truy vấn).


7

Câu trả lời được chấp nhận về cách tạo Chỉ mục nội tuyến một tập lệnh tạo Bảng không phù hợp với tôi. Điều này đã làm:

CREATE TABLE [dbo].[TableToBeCreated]
(
    [Id] BIGINT IDENTITY(1, 1) NOT NULL PRIMARY KEY
    ,[ForeignKeyId] BIGINT NOT NULL
    ,CONSTRAINT [FK_TableToBeCreated_ForeignKeyId_OtherTable_Id] FOREIGN KEY ([ForeignKeyId]) REFERENCES [dbo].[OtherTable]([Id])
    ,INDEX [IX_TableToBeCreated_ForeignKeyId] NONCLUSTERED ([ForeignKeyId])
)

Hãy nhớ rằng, Khóa ngoại không tạo Chỉ mục, vì vậy, bạn nên lập chỉ mục vì bạn sẽ có nhiều khả năng tham gia vào chúng hơn.


Tôi không tuân theo tuyên bố cuối cùng đó. Tôi sẽ đồng ý với tuyên bố đó nếu thông thường truy vấn bảng của bạn bằng khóa ngoại; nhưng không chỉ đơn giản là bạn tham gia vào nó, do đó nó sẽ được lập chỉ mục. Ví dụ: Tìm tất cả nhân viên và tên công ty của họ trong id công ty X - sau đó chắc chắn rằng một chỉ mục trên FK sẽ giúp ích. Tìm tất cả nhân viên và tên công ty của họ có họ bắt đầu bằng A; chỉ mục trên FK không giúp được gì. Nói cách khác, tôi không chắc rằng "bởi vì bạn tham gia vào nó, bạn nên lập chỉ mục nó" là một phương pháp hay. Tui bỏ lỡ điều gì vậy?
Paul

2
Chỉ mục làm cho các truy vấn tham gia nhanh hơn.
ScubaSteve 13:16
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.