Creazione di un indice su una variabile di tabella


190

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

vale a dire

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

Posso creare un indice su Name?


3
C'è un costo nella creazione di entrambi i tipi di tabelle temporanee; e se hai così tanti dati da aver bisogno di un indice, potrebbe essere il momento di guardare usando una tabella reale; che hai impostato per essere sicuro per le transazioni; filtrare per spid o ID utente e quindi cancellarlo 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

Una tabella temporanea "È" una tabella reale, scompare quando hai finito. La vera differenza (oltre a quando andrà via automaticamente) è che è in TempDB. Questo è in realtà enorme quando si tratta di indici e vincoli perché potresti finire con scontri di nomi, non solo con altre esecuzioni del tuo codice ma con l'esecuzione di codice in altri database nella tua istanza.
bielawski,

@bielawski questa è una variabile di tabella non una tabella temporanea. Le variabili di tabella non consentono vincoli con nome esplicito, i nomi generati dal sistema sono garantiti per essere univoci. Consentono indici nominati dal 2014, ma questo non è un problema in quanto gli indici devono solo essere nominati in modo univoco all'interno di un oggetto non tra gli oggetti.
Martin Smith,

Il mio punto era 2 volte. 1) Oltre all'utilizzo di una variabile per evitare l'entanglement delle transazioni, non vi è alcuna differenza sostanziale tra una tabella temporanea e una variabile di tabella. In V-2000 tuttavia non esiste sintassi per l'aggiunta di vincoli, indici ... a una variabile. 2) Tenuto conto si può utilizzare una tabella temporanea, invece, appendici tabella denominata come indici SARANNO scontrarsi con Eseguendo contemporaneamente copie della stessa SP, se si utilizza un nome statico! Il meccanismo di seguito è stato sviluppato esplicitamente perché ho rintracciato gli errori SP in indici nominati in conflitto in queste circostanze esatte. DEVONO essere unici.
bielawski,

1
@bielawski - Non è necessario che i nomi degli indici siano univoci tra gli oggetti, ma solo i nomi dei vincoli. questo è banale da testare. Basta eseguireCREATE TABLE #T1(X INT); CREATE TABLE #T2(X INT); CREATE INDEX IX ON #T1(X); CREATE INDEX IX ON #T2(X);
Martin Smith il

Risposte:


363

La domanda è taggata SQL Server 2000 ma a beneficio delle persone che sviluppano sull'ultima versione mi occuperò prima di tutto.

SQL Server 2014

Oltre ai metodi di aggiunta degli indici basati sui vincoli discussi di seguito in SQL Server 2014, è anche possibile specificare indici non univoci direttamente con la sintassi incorporata nelle dichiarazioni delle variabili di tabella.

La sintassi di esempio è sotto.

/*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*/
);

Gli indici filtrati e gli indici con colonne incluse non possono attualmente essere dichiarati con questa sintassi, tuttavia SQL Server 2016 lo rilassa ulteriormente. Da CTP 3.1 è ora possibile dichiarare indici filtrati per variabili di tabella. Con RTM può accadere che anche le colonne incluse siano consentite, ma la posizione attuale è che "probabilmente non lo faranno in SQL16 a causa di vincoli di risorse"

/*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 è di seguito.

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

Gli indici cluster possono essere dichiarati come univoci per impedire valori di chiave duplicati o per impostazione predefinita su non univoci. Se non univoco, SQL Server aggiunge silenziosamente un identificatore a qualsiasi chiave duplicata per renderli univoci.

Gli indici non cluster possono anche essere dichiarati esplicitamente come univoci. In caso contrario, per il caso non univoco, SQL Server aggiunge il localizzatore di righe (chiave di indice cluster o RID per un heap) a tutte le chiavi di indice (non solo ai duplicati), in modo da garantire che siano univoci.

In SQL Server 2000 - 2012 gli indici sulle variabili di tabella possono essere creati in modo implicito solo creando un vincolo UNIQUEo PRIMARY KEY. La differenza tra questi tipi di vincoli è che la chiave primaria deve trovarsi su colonne non annullabili. Le colonne che partecipano a un vincolo univoco potrebbero essere nullable. (sebbene l'implementazione di SQL Server di vincoli univoci in presenza di NULLs 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 implementati fisicamente con un indice univoco. Se non specificato esplicitamente, altrimenti PRIMARY KEYdiventerà l'indice cluster e i vincoli univoci non cluster ma questo comportamento può essere ignorato specificando CLUSTEREDo NONCLUSTEREDesplicitamente con la dichiarazione di vincolo (sintassi di esempio)

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

Di conseguenza, i seguenti indici possono essere implicitamente creati su 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 della variabile di tabella all'inizio di questa risposta, l' indice non cluster non univoco attivo Nameè simulato da un indice univoco attivato Name,Id(ricordare che SQL Server aggiungerebbe silenziosamente la chiave di indice cluster alla chiave NCI non univoca).

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

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 verrebbe effettivamente implementato in SQL Server in quanto ciò aggiunge "Uniqueifier" a 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)
Andre Figueiredo,

1
@AndreFigueired Sì, questa è la dimensione massima per una chiave di indice anche su tabelle permanenti in quelle versioni.
Martin Smith,

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

13

Dovrebbe essere chiaro che dal punto di vista delle prestazioni non ci sono 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 funzionalità aggiuntive. Guarda questo articolo incredibilmente completo: /dba/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

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

Lo svantaggio dell'uso di indici (o vincoli) denominati in tempdb è che i nomi possono quindi scontrarsi. 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 con i nomi, qualcosa di simile di solito funziona:

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

Questo assicura che il nome sia sempre unico anche tra esecuzioni simultanee della stessa procedura.


Ha una parentesi mancante dopo varchar (40), aggiungo che
Tejasvi Hegde,

1
Non vi sono problemi con gli indici con nome: gli indici devono essere nominati in modo univoco all'interno di una tabella. Il problema è con i vincoli con nome e la soluzione migliore generalmente non è di nominarli nelle tabelle temporanee - i vincoli con nome impediscono la memorizzazione nella cache degli oggetti della tabella temporanea.
Martin Smith,

1
Questo deve essere vero solo per alcune versioni (se è vero per qualsiasi versione). Ho dovuto escogitare questa soluzione alternativa in particolare perché ho rintracciato gli errori SP nello scontro di indici nominati durante le esecuzioni simultanee.
bielawski,

@bielawski Stai usando il 2016? Sono molto curioso di sapere se gli indici denominati nelle tabelle temporanee sono un rischio per ambienti concorrenti.
Elaskanator,

1
@Elaskanator sì, lo sono. Abbiamo trovato contesa nelle tabelle dei metadati SQL sotto carico, rimuovendo il nome dell'indice risolto il problema. Questo era SQL 2016.
Dan Def

0

Se la variabile Table contiene dati di grandi dimensioni, al posto della variabile table (@table) creare la tabella temporanea (#table) .table variabile non consente di creare indice dopo l'inserimento.

 CREATE TABLE #Table(C1 int,       
  C2 NVarchar(100) , C3 varchar(100)
  UNIQUE CLUSTERED (c1) 
 ); 
  1. Crea una tabella con un indice cluster univoco

  2. Inserire i dati nella tabella Temp "#Table"

  3. Crea indici non cluster.

     CREATE NONCLUSTERED INDEX IX1  ON #Table (C2,C3);

creare l'indice dopo l'istruzione insert per evitare ordinamenti non necessari
Boopathi.Indotnet,

Nota che questo non è possibile se la variabile della tabella è in una funzione
Geoff il
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.