使用SQL Server在CREATE TABLE语句内创建非聚集的非唯一索引


92

可以在SQL Server CREATE TABLE语句中创建主键或唯一索引。是否可以在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

同样,目标是在CREATE TABLE语句中而不是之后创建非唯一索引。

对于它的价值,我没有发现[CREATE TABLE的SQL Server联机丛书条目]会有所帮助。

同样,[此问题]几乎相同,但是接受的答案不适用。

Answers:


122

你不能。CREATE / ALTER TABLE仅接受要添加的约束,而不接受索引。主索引和唯一约束是根据索引实现的,这是一个副作用。众所周知,要管理索引,您需要CREATE / ALTER / DROP INDEX。

为什么要在CREATE TABLE语句中添加非唯一非聚集索引?

请注意,SQL Server 2014引入了内联索引创建选项

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
感谢您的精彩解释!为什么?纯粹出于美学原因。我认为,如果所有约束/索引都包含在同一条语句中,那么对阅读脚本的任何人来说可能会很方便。就个人而言,我想知道属于外键的列是否也具有索引,这可能是在同一条语句中对这些信息进行逻辑分组的好方法。
麦克,

我感到Error: (1146) Table 'tablename' doesn't exist讽刺了,哈哈哈哈
Aminah Nuraini

13

根据T-SQL CREATE TABLE文档,在2014年,列定义支持定义索引:

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

语法定义为:

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

因此,作为单独的语句,您可以做的很多事情都可以内联完成。我注意到include该语法不是一个选项,因此某些事情是不可能的。

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
)

您还可以将内联索引定义为列之后的另一行,但是在create table语句中,这允许索引中有多个列,但仍然没有include子句:

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

}   

例如,在这里我们在列c和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
这非常有效,根据BOL的说法,至少可以追溯到2008年。像OP一样,我发现我经常看到的代码(通常由SSMS生成)使我的眼睛受伤,并且我喜欢表定义对理性的人有意义。谢谢。
韦德·哈特勒

8

这是一个单独的声明。

也不能插入表并从中选择并在同一条语句中建立索引。

BOL条目包含您需要的信息:

集群| NONCLUSTERED
表示为PRIMARY KEY或UNIQUE约束创建了聚集索引或非聚集索引。PRIMARY KEY约束默认为CLUSTERED,UNIQUE约束默认为NONCLUSTERED。

在CREATE TABLE语句中,只能为一个约束指定CLUSTERED。如果为UNIQUE约束指定了CLUSTERED,并且还指定了PRIMARY KEY约束,则PRIMARY KEY默认为NONCLUSTERED。

您可以在PK字段上创建索引,但不能在非pk非唯一约束字段上创建非聚集索引。

NCL索引与表的结构无关,也不是对表内部数据的约束。它是支持表的独立实体,但不是其功能或设计所不可或缺的。

这就是为什么它是一个单独的语句。从设计角度来看,NCL索引与表无关(尽管有查询优化)。


7

如何在表创建脚本中内联创建索引的公认答案对我不起作用。这样做:

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

请记住,外键不会创建索引,因此最好对它们建立索引,因为您很可能会加入它们。


我没有遵循最后一条声明。如果按惯例通过外键查询表,我将同意该声明。而不只是简单地加入它,因此应该对其进行索引。示例:查找所有员工及其公司名称(公司ID X)-然后确保FK上的索引有帮助。查找所有员工及其公司名称(姓氏以A开头);FK上的索引没有帮助。换句话说,我不确定“因为要加入它,所以应该索引它”是不是很好的做法。我想念什么吗?
保罗

2
索引使联接查询更快。
ScubaSteve
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.