Buat indeks non-unik yang tidak terkluster dalam pernyataan CREATE TABLE dengan SQL Server

95

Dimungkinkan untuk membuat kunci utama atau indeks unik dalam pernyataan SQL Server CREATE TABLE. Apakah mungkin untuk membuat indeks non-unik dalam pernyataan CREATE TABLE?

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

Sekali lagi, tujuannya adalah untuk membuat indeks non-unik dalam pernyataan CREATE TABLE, bukan setelahnya.

Untuk apa nilainya, saya tidak menemukan [entri SQL Server Books Online untuk CREATE TABLE] untuk membantu.

Selain itu, [Pertanyaan Ini] hampir sama, tetapi jawaban yang diterima tidak berlaku.

Mike
sumber

Jawaban:

126

Kamu tidak bisa. CREATE / ALTER TABLE hanya menerima CONSTRAINT yang akan ditambahkan, bukan indeks. Fakta bahwa kunci utama dan batasan unik diimplementasikan dalam indeks adalah efek samping. Untuk mengelola indeks, Anda memiliki CREATE / ALTER / DROP INDEX, seperti yang Anda ketahui.

Mengapa Anda memiliki persyaratan untuk menambahkan indeks non-unik-non-cluster di pernyataan CREATE TABLE?

Perhatikan bahwa SQL Server 2014 memperkenalkan opsi buat indeks sebaris :

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
Remus Rusanu
sumber
17
Terima kasih atas penjelasan yang bagus! Mengapa? Murni untuk alasan estetika. Saya pikir akan lebih mudah bagi siapa saja yang membaca skrip jika semua batasan / indeks terkandung dalam pernyataan yang sama. Secara pribadi, saya ingin tahu apakah kolom milik foreign key juga memiliki indeks, dan ini mungkin metode yang bagus untuk mengelompokkan informasi ini secara logis dalam pernyataan yang sama.
Mike
I got Error: (1146) Table 'tablename' doesn't exist, hahahah, ironic
Aminah Nuraini
13

Sesuai dokumentasi T-SQL CREATE TABLE , pada tahun 2014 definisi kolom mendukung pendefinisian indeks:

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

dan tata bahasa didefinisikan sebagai:

<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" } ]  

Jadi banyak hal yang dapat Anda lakukan sebagai pernyataan terpisah dapat dilakukan secara inline. Saya perhatikan includetidak ada opsi dalam tata bahasa ini sehingga beberapa hal tidak memungkinkan.

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
)

Anda juga dapat menetapkan indeks sebaris sebagai baris lain setelah kolom, tetapi dalam pernyataan buat tabel, dan ini memungkinkan beberapa kolom dalam indeks, tetapi tetap tidak ada includeklausa:

< 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" } ]  

}   

Misalnya di sini kami menambahkan indeks pada kedua kolom c dan 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)
)
AaronLS
sumber
1
Ini bekerja dengan baik, dan menurut BOL setidaknya kembali ke tahun 2008. Seperti OP, saya menemukan kode yang paling sering saya lihat (biasanya dihasilkan oleh SSMS) membuat bola mata saya sakit, dan saya hanya menyukai definisi tabel saya agar masuk akal bagi manusia yang rasional. Terima kasih.
Wade Hatler
8

Ini pernyataan terpisah.

Ini juga tidak mungkin untuk menyisipkan ke dalam tabel dan memilih darinya dan membangun indeks dalam pernyataan yang sama juga.

Entri BOL berisi informasi yang Anda butuhkan:

CLUSTERED | NONCLUSTERED
Menunjukkan bahwa clustered atau nonclustered index dibuat untuk PRIMARY KEY atau UNIQUE kendala. Batasan PRIMARY KEY default ke CLUSTERED, dan batasan UNIQUE default ke NONCLUSTERED.

Dalam pernyataan CREATE TABLE, CLUSTERED hanya dapat ditentukan untuk satu batasan. Jika CLUSTERED ditentukan untuk batasan UNIQUE dan batasan PRIMARY KEY juga ditentukan, PRIMARY KEY defaultnya adalah NONCLUSTERED.

Anda dapat membuat indeks pada bidang PK, tapi bukan indeks non-cluster pada bidang non-pk non-unique-constrained.

Indeks NCL tidak relevan dengan struktur tabel, dan bukan merupakan kendala pada data di dalam tabel. Ini adalah entitas terpisah yang mendukung tabel tetapi tidak integral dengan fungsionalitas atau desainnya.

Itulah mengapa ini adalah pernyataan terpisah. Indeks NCL tidak relevan dengan tabel dari perspektif desain (meskipun demikian pengoptimalan kueri).

JNK
sumber
7

Jawaban yang diterima tentang cara membuat Indeks sebaris skrip pembuatan Tabel tidak berfungsi untuk saya. Ini dilakukan:

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

Ingat, Kunci Asing tidak membuat Indeks, jadi praktik yang baik untuk mengindeksnya karena Anda kemungkinan besar akan bergabung dengannya.

ScubaSteve
sumber
Saya tidak mengikuti pernyataan terakhir itu. Saya setuju dengan pernyataan itu jika itu adalah praktik biasa untuk menanyakan tabel Anda dengan kunci asing; tetapi tidak hanya Anda bergabung di dalamnya karena itu harus diindeks. Contoh: Temukan semua karyawan dan nama perusahaan mereka dari perusahaan id X - maka pastikan indeks di FK membantu. Temukan semua karyawan dan nama perusahaan mereka dengan nama belakang dimulai dengan A; indeks di FK tidak membantu. Dengan kata lain, saya tidak yakin bahwa "karena Anda bergabung, Anda harus mengindeksnya" adalah praktik yang baik. Apakah saya melewatkan sesuatu?
Paul
2
Indeks membuat kueri gabungan lebih cepat.
ScubaSteve