【问题标题】:Create a nonclustered non-unique index within the CREATE TABLE statement with SQL Server使用 SQL Server 在 CREATE TABLE 语句中创建非聚集非唯一索引
【发布时间】:2011-09-05 19:16:42
【问题描述】:

可以在 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 语句中创建非唯一索引,而不是在它之后。

对于它的价值,我没有发现 [SQL Server Books Online entry for CREATE TABLE] 有帮助。

另外,[This Question] 几乎相同,但接受的答案不适用。

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    从 SQL 2014 开始,这可以通过 inline index creation 完成:

    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 standard non-clustered index on (d, e)
        ,INDEX IX_MyTable4 NONCLUSTERED (d, e)
    );
    GO
    

    在 SQL 2014 之前,CREATE/ALTER TABLE 只接受要添加的约束,而不接受索引。主键和唯一约束是根据索引实现的,这是一个副作用。

    【讨论】:

    • 感谢您的精彩解释!为什么?纯粹是出于审美原因。我认为如果所有约束/索引都包含在同一个语句中,那么阅读脚本的任何人都会很方便。就个人而言,我想知道属于外键的列是否也有索引,这可能是在同一条语句中逻辑分组这些信息的好方法。
    • 我得到了Error: (1146) Table 'tablename' doesn't exist,哈哈哈,讽刺
    【解决方案2】:

    TLDR:

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

    详情

    根据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_indexName 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)
    )
    

    【讨论】:

    • 这很好用,根据 BOL,它至少可以追溯到 2008 年。像 OP 一样,我发现我最常看到的代码(通常由 SSMS 生成)让我的眼球受伤,我只是喜欢我的表格定义对理性的人有意义。谢谢。
    【解决方案3】:

    关于如何创建 Index 内联表创建脚本的公认答案对我不起作用。这样做了:

    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 上的索引没有帮助。换句话说,我不确定“因为你加入它,你应该索引它”是一个好习惯。我错过了什么吗?
    • 索引使连接查询更快。
    【解决方案4】:

    这是一个单独的声明。

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

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

    集群 |非集群
    表明 聚集或非聚集索引是 为 PRIMARY KEY 或 UNIQUE 创建 约束。主键约束 默认为 CLUSTERED 和 UNIQUE 约束默认为 NONCLUSTERED。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-08
      • 1970-01-01
      • 1970-01-01
      • 2012-10-01
      • 2010-10-23
      • 2011-05-29
      相关资源
      最近更新 更多