Создайте некластеризованный неуникальный индекс в инструкции CREATE TABLE с SQL Server.


95

Можно создать первичный ключ или уникальный индекс в инструкции 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 для CREATE TABLE] .

Кроме того, [Этот вопрос] почти идентичен, но принятый ответ неприменим.

Ответы:


126

Вы не можете. 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, хахахах, иронично
Амина Нураини

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 можно указать только для одного ограничения. Если для ограничения 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])
)

Помните, что внешние ключи не создают индексы, поэтому рекомендуется индексировать их, так как вы, скорее всего, присоединитесь к ним.


Я не слежу за последним утверждением. Я бы согласился с этим утверждением, если бы обычно запрашивали вашу таблицу по внешнему ключу; но не просто то, что вы присоединяетесь к нему, поэтому он должен быть проиндексирован. Пример: Найдите всех сотрудников и их название компании с идентификатором X - тогда убедитесь, что индекс на FK поможет. Найдите всех сотрудников и их название компании с фамилией, начинающейся с A; указатель на FK не помогает. Другими словами, я не уверен, что «поскольку вы присоединились к нему, вы должны его проиндексировать» - это хорошая практика. Я что-то упускаю?
Пол

2
Индексы ускоряют запросы на соединение.
ScubaSteve,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.