Створіть некластерований не-унікальний індекс в операторі CREATE TABLE за допомогою SQL Server


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, а не після нього.

Для чого це варте, я не знайшов [Інтернет-запис книг SQL Server для СТВОРЕННЯ ТАБЛИЦІ] корисним.

Крім того, [Це запитання] майже ідентичне, але прийнята відповідь не застосовується.

Відповіді:


122

Ви не можете. СТВОРИТИ / ЗМІНИТЬ ТАБЛИЦЮ приймають лише обмеження, які потрібно додати, а не індекси. Той факт, що первинний ключ та унікальні обмеження реалізовані в термінах індексу, є побічним ефектом. Для управління індексами у вас є 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
)

Ви також можете мати вбудовані індекси, визначені як інший рядок після стовпців, але всередині оператора створення таблиці, і це дозволяє декілька стовпців в індексі, але все ще немає 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 можна вказати лише для одного обмеження. Якщо CLUSTERED вказано для UNIQUE обмеження, а також вказано обмеження PRIMARY KEY, то PRIMARY KEY за замовчуванням має значення NONCLUSTERED.

Ви можете створити індекс у полі 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])
)

Пам’ятайте, Іноземні ключі не створюють індекси, тому корисно їх індексувати, оскільки ви, швидше за все, приєднаєтесь до них.


Я не стежу за цим останнім твердженням. Я погодився б із цим твердженням, якщо це звичайна практика запитувати таблицю за зовнішнім ключем; але не просто тим, що ви приєднуєтесь до цього, тому його слід проіндексувати. Приклад: Знайдіть усіх співробітників та назву їх компанії з ідентифікатором компанії X - тоді впевнений, що індекс на FK допомагає. Знайдіть усіх співробітників та назву їх компанії з прізвищем, що починається з A; індекс на ФК не допомагає. Іншими словами, я не впевнений, що "оскільки ви приєднуєтесь до цього, ви повинні його проіндексувати" - це хороша практика. Мені чогось не вистачає?
Пол

2
Індекси пришвидшують запити на приєднання.
ScubaSteve
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.