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ステートメント内で一意でないインデックスを作成することが目標です。

それだけの価値があるので、[CREATE TABLEのSQL Server Books Onlineエントリ]役に立たないと思いました。

また、[この質問]はほぼ同じですが、受け入れられた回答は適用されません。

回答:


122

できません。CREATE / ALTER TABLEは、追加されるCONSTRAINTのみを受け入れ、インデックスは受け入れません。主キーと一意の制約がインデックスの観点から実装されているという事実は、副作用です。インデックスを管理するには、ご存知のとおり、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、ははは、皮肉なことに
アミナ・ヌライニ

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エントリには、必要な情報が含まれています。

クラスター| クラスター化されていない
PRIMARY KEYまたはUNIQUE制約に対してクラスター化または非クラスター化インデックスが作成されることを示します。PRIMARY KEY制約のデフォルトはCLUSTEREDで、UNIQUE制約のデフォルトはNONCLUSTEREDです。

CREATE TABLEステートメントでは、CLUSTEREDを指定できる制約は1つだけです。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 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.