2009-05-20 19 views
130

È possibile creare un indice su una variabile di tabella in SQL Server 2000?Creazione di un indice su una variabile di tabella

cioè

DECLARE @TEMPTABLE TABLE (
     [ID] [int] NOT NULL PRIMARY KEY 
     ,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL 
) 

Posso creare un indice sul nome?

+3

C'è un costo nella creazione di entrambi i tipi di tabelle temporanee; e se hai così tanti dati in quanto hai bisogno di un indice, potrebbe essere il momento di guardare usando una tabella reale; che hai impostato per essere sicuro per le transazioni; filtra per spid o id utente e poi cancellalo alla fine. Le tabelle reali e le tabelle temporanee hanno entrambi i loro alti e bassi, ma se le prestazioni sono un problema; provalo anche con un vero tavolo. – u07ch

+0

Un tavolo temporaneo "È" un vero tavolo, appena finito quando hai finito. La vera differenza (a parte che andrà via automaticamente) è che è in TempDB. Questo è davvero enorme quando si tratta di indici e vincoli perché si potrebbero finire con scontri sul nome, non solo con altre esecuzioni del codice ma con l'esecuzione di codice in altri database nella propria istanza. – bielawski

+0

@bielawski questa è una variabile di tabella non una tabella temporanea. Le variabili di tabella non consentono vincoli esplicitamente denominati, i nomi generati dal sistema garantiscono che siano univoci.Consentono di consentire indici nominati a partire dal 2014 ma ciò non rappresenta un problema in quanto gli indici devono essere nominati univocamente all'interno di un oggetto e non tra gli oggetti. –

risposta

256

La domanda viene codificata in SQL Server 2000 ma, a beneficio delle persone che stanno sviluppando l'ultima versione, mi occuperò prima di tutto.

SQL Server 2014

In aggiunta ai metodi di aggiunta degli indici dei vincoli basato discussi qui di seguito SQL Server 2014 permette anche indici non univoci da specificare direttamente con la sintassi linea sulla tavola dichiarazioni di variabili.

La seguente sintassi di esempio è riportata di seguito.

/*SQL Server 2014+ compatible inline index syntax*/ 
DECLARE @T TABLE (
C1 INT INDEX IX1 CLUSTERED, /*Single column indexes can be declared next to the column*/ 
C2 INT INDEX IX2 NONCLUSTERED, 
     INDEX IX3 NONCLUSTERED(C1,C2) /*Example composite index*/ 
); 

indici filtrati e indici con colonne incluse non possono attualmente essere dichiarate con questa sintassi tuttavia SQL Server 2016 rilassa questo un po 'più lontano. Da CTP 3.1 è ora possibile dichiarare gli indici filtrati per le variabili di tabella. Con RTM è può essere il caso che comprese le colonne sono anche permesso, ma la posizione attuale è che "will likely not make it into SQL16 due to resource constraints"

/*SQL Server 2016 allows filtered indexes*/ 
DECLARE @T TABLE 
(
c1 INT NULL INDEX ix UNIQUE WHERE c1 IS NOT NULL /*Unique ignoring nulls*/ 
) 

SQL Server 2000 - 2012

Posso creare un indice su Nome?

Risposta breve: Sì.

DECLARE @TEMPTABLE TABLE (
    [ID] [INT] NOT NULL PRIMARY KEY, 
    [Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL, 
    UNIQUE NONCLUSTERED ([Name], [ID]) 
) 

Una risposta più dettagliata è riportata di seguito.

Le tabelle tradizionali in SQL Server possono avere un indice cluster o sono strutturate come heaps.

Gli indici clusterizzati possono essere dichiarati come univoci per non consentire valori di chiave duplicati o predefiniti a non univoci. Se non è univoco, SQL Server aggiunge silenziosamente uno uniqueifier a qualsiasi chiave duplicata per renderli univoci.

Gli indici non cluster possono anche essere dichiarati esplicitamente come univoci. Altrimenti, per il caso non univoco SQL Server adds the row locator (chiave indice cluster o RID per un heap) a tutte le chiavi indice (non solo ai duplicati), ciò garantisce nuovamente che siano univoci.

In SQL Server 2000 - 2012 gli indici sulle variabili di tabella possono essere creati solo implicitamente creando un vincolo UNIQUE o PRIMARY KEY. La differenza tra questi tipi di vincoli è che la chiave primaria deve essere su una colonna non nullable. Le colonne che partecipano a un vincolo univoco potrebbero essere annullabili. (sebbene l'implementazione di SQL di vincoli univoci in presenza di NULL s non sia conforme a quella specificata nello standard SQL). Inoltre, una tabella può avere solo una chiave primaria ma più vincoli univoci.

Entrambi questi vincoli logici sono fisicamente implementati con un indice univoco. Se non diversamente specificato il PRIMARY KEY diventerà l'indice cluster e vincoli univoci non cluster ma questo comportamento può essere modificato specificando CLUSTERED o NONCLUSTERED esplicitamente alla dichiarazione di vincolo (Esempio di sintassi)

DECLARE @T TABLE 
(
A INT NULL UNIQUE CLUSTERED, 
B INT NOT NULL PRIMARY KEY NONCLUSTERED 
) 

Per effetto di quanto precede i seguenti indici possono essere creati su implicitamente le variabili di tabella in SQL Server 2000 - 2012.

+-------------------------------------+-------------------------------------+ 
|    Index Type    | Can be created on a table variable? | 
+-------------------------------------+-------------------------------------+ 
| Unique Clustered Index    | Yes         | 
| Nonunique Clustered Index   |          | 
| Unique NCI on a heap    | Yes         | 
| Non Unique NCI on a heap   |          | 
| Unique NCI on a clustered index  | Yes         | 
| Non Unique NCI on a clustered index | Yes         | 
+-------------------------------------+-------------------------------------+ 

L'ultimo richiede un po 'di spiegazione. Nella definizione di variabile della tabella all'inizio di questa risposta l'indice non cluster non univoco su Name viene simulato da un indice univoco su Name,Id (si ricordi che SQL Server aggiunge silenziosamente la chiave dell'indice cluster alla chiave NCI non univoca in ogni caso).

Un indice cluster non univoco può anche essere ottenuto aggiungendo manualmente una colonna IDENTITY per fungere da unificatore.

DECLARE @T TABLE 
(
A INT NULL, 
B INT NULL, 
C INT NULL, 
Uniqueifier INT NOT NULL IDENTITY(1,1), 
UNIQUE CLUSTERED (A,Uniqueifier) 
) 

Ma questa non è una simulazione accurata di come un indice cluster non univoco normalmente in realtà essere implementato in SQL Server come questo aggiunge la "Uniqueifier" per tutte le righe. Non solo quelli che lo richiedono.

+1

Nota: la soluzione 2000-2012 funziona solo se la colonna di testo <= 900 byte. vale a dire. varchar (900), nvarchar (450) –

+1

@AndreFigueiredo sì, questa è la dimensione massima per un indice su tabelle permanenti anche in quelle versioni. –

+0

Volevo solo notare che la risposta di SQL 2014 funziona bene in Azure. Grazie Martin! – Jaxidian

11

Si deve comprendere che dal punto di vista delle prestazioni non esistono differenze tra le tabelle @temp e #temp che favoriscono le variabili. Risiedono nello stesso posto (tempdb) e sono implementati allo stesso modo. Tutte le differenze appaiono in funzioni aggiuntive. Vedere questo articolo incredibilmente completo: https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

Sebbene esistano casi in cui una tabella temporanea non può essere utilizzata come nelle funzioni tabella o scalare, per la maggior parte degli altri casi precedenti alla v2016 (in cui è possibile aggiungere anche indici filtrati a una tabella variabile) puoi semplicemente usare una tabella #temp.

Lo svantaggio di utilizzare indici nominati (o vincoli) in tempdb è che i nomi possono quindi essere in conflitto. Non solo teoricamente con altre procedure, ma spesso abbastanza facilmente con altre istanze della procedura stessa che proverebbero a mettere lo stesso indice sulla sua copia della tabella #temp.

Per evitare scontri nome, qualcosa di simile a questo di solito funziona:

declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);'; 
exec (@cmd); 

Questo assicura il nome è sempre unico anche tra le esecuzioni simultanee della stessa procedura.

+0

Ha una parentesi mancante dopo varchar (40), aggiunge che –

+0

Non c'è alcun problema con gli indici nominati - gli indici devono essere nominati univocamente all'interno di una tabella. Il problema è con i vincoli denominati e la soluzione migliore in genere non è il loro nome nelle tabelle temporanee - i vincoli denominati impediscono la memorizzazione nella cache degli oggetti della tabella temporanea. –

+0

Deve essere vero solo per alcune versioni (se è vero per qualsiasi versione). Ho dovuto inventare questa soluzione in modo specifico perché ho tracciato gli errori dello sp nello scontro degli indici nominati durante le esecuzioni simultanee. – bielawski

Problemi correlati