Creare un indice non univoco non cluster all'interno dell'istruzione CREATE TABLE con SQL Server


94

È possibile creare una chiave primaria o un indice univoco all'interno di un'istruzione CREATE TABLE di SQL Server. È possibile creare un indice non univoco all'interno di un'istruzione 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

Anche in questo caso, l'obiettivo è creare l'indice non univoco all'interno dell'istruzione CREATE TABLE, non dopo di essa.

Per quello che vale, non ho trovato utile la [voce della documentazione in linea di SQL Server relativa a CREATE TABLE] .

Inoltre, [Questa domanda] è quasi identica, ma la risposta accettata non si applica.

Risposte:


124

Non puoi. CREATE / ALTER TABLE accetta solo vincoli da aggiungere, non indici. Il fatto che la chiave primaria e i vincoli univoci siano implementati in termini di indice è un effetto collaterale. Per gestire gli indici, hai CREATE / ALTER / DROP INDEX, come ben sai.

Perché hai un tale requisito da aggiungere indici non univoci non cluster nell'istruzione CREATE TABLE?

Si noti che SQL Server 2014 ha introdotto l' opzione di creazione dell'indice inline :

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
Grazie per l'ottima spiegazione! Perché? Per motivi puramente estetici. Ho pensato che potesse essere conveniente per chiunque leggesse lo script se tutti i vincoli / indici fossero contenuti nella stessa istruzione. Personalmente, mi piace sapere se le colonne appartenenti a una chiave esterna hanno anche un indice, e questo potrebbe essere stato un bel metodo per raggruppare logicamente queste informazioni nella stessa istruzione.
Mike

Ho Error: (1146) Table 'tablename' doesn't exist, hahahah, ironico
Aminah Nuraini

13

Secondo la documentazione di T-SQL CREATE TABLE , nel 2014 la definizione di colonna supporta la definizione di un indice:

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

e la grammatica è definita come:

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

Quindi molto di quello che puoi fare come dichiarazione separata può essere fatto in linea. Ho notato che includenon è un'opzione in questa grammatica, quindi alcune cose non sono possibili.

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
)

Puoi anche avere indici in linea definiti come un'altra riga dopo le colonne, ma all'interno dell'istruzione create table, e questo consente più colonne nell'indice, ma ancora nessuna includeclausola:

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

}   

Ad esempio qui aggiungiamo un indice su entrambe le colonne ced:

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
Funziona alla grande e, secondo BOL, risale almeno al 2008. Come l'OP, trovo che il codice che vedo di più (solitamente generato da SSMS) mi fa male gli occhi, e mi piace che le mie definizioni di tabella abbiano senso per un essere umano razionale. Grazie.
Wade Hatler

8

È una dichiarazione separata.

Inoltre, non è possibile inserire in una tabella e selezionare da essa e creare un indice nella stessa istruzione.

La voce BOL contiene le informazioni necessarie:

Cluster | NONCLUSTER
Indica che viene creato un indice cluster o non cluster per il vincolo PRIMARY KEY o UNIQUE. L'impostazione predefinita dei vincoli PRIMARY KEY è CLUSTER e dei vincoli UNIQUE è NONCLUSTER.

In un'istruzione CREATE TABLE, CLUSTER può essere specificato per un solo vincolo. Se viene specificato CLUSTER per un vincolo UNIQUE e viene specificato anche un vincolo PRIMARY KEY, il valore predefinito di PRIMARY KEY è NONCLUSTER.

È possibile creare un indice su un campo PK, ma non un indice non cluster su un campo non vincolato non univoco senza pacchetto.

Un indice NCL non è rilevante per la struttura della tabella e non è un vincolo sui dati all'interno della tabella. È un'entità separata che supporta la tabella ma non è parte integrante della sua funzionalità o design.

Ecco perché è una dichiarazione separata. L'indice NCL è irrilevante per la tabella dal punto di vista del design (nonostante l'ottimizzazione delle query).


7

La risposta accettata su come creare un indice in linea uno script per la creazione di una tabella non ha funzionato per me. Questo ha fatto:

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

Ricorda, le chiavi esterne non creano indici, quindi è buona norma indicizzarle poiché molto probabilmente ti unirai a loro.


Non sto seguendo l'ultima affermazione. Sarei d'accordo con questa affermazione se fosse pratica normale interrogare la tua tabella con la chiave esterna; ma non semplicemente che ci si unisce, quindi dovrebbe essere indicizzato. Esempio: trova tutti i dipendenti e il nome della società dell'ID società X, quindi assicurati che un indice sull'FK aiuti. Trova tutti i dipendenti e il nome dell'azienda con il cognome che inizia con A; l'indice sull'FK non aiuta. In altre parole, non sono sicuro che "poiché ti unisci a esso dovresti indicizzarlo" sia una buona pratica. Mi sto perdendo qualcosa?
Paul

2
Gli indici rendono più veloci le query di join.
ScubaSteve
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.