Erstellen eines Index für eine Tabellenvariable

189

Können Sie in SQL Server 2000 einen Index für eine Tabellenvariable erstellen?

dh

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

Kann ich einen Index für erstellen Name?

GordyII
quelle
3
Das Erstellen beider Arten von temporären Tabellen ist mit Kosten verbunden. und wenn Sie so viele Daten haben, dass Sie einen Index benötigen, ist es möglicherweise an der Zeit, eine reale Tabelle zu verwenden. dass Sie eingerichtet haben, um transaktionssicher zu sein; Filtern Sie nach Spid oder Benutzer-ID und löschen Sie sie am Ende. Echte Tabellen v temporäre Tabellen haben beide ihre Höhen und Tiefen, aber wenn die Leistung ein Problem darstellt; Probieren Sie es auch mit einem echten Tisch.
U07ch
Ein temporärer Tisch 'IST' ein echter Tisch, er verschwindet einfach, wenn Sie fertig sind. Der wirkliche Unterschied (außer dass es automatisch verschwindet) ist, dass es in TempDB ist. Dies ist in Bezug auf Indizes und Einschränkungen tatsächlich enorm, da es zu Namenskonflikten kommen kann, nicht nur bei anderen Ausführungen Ihres Codes, sondern auch bei Code, der in anderen Datenbanken in Ihrer Instanz ausgeführt wird.
Bielawski
@bielawski Dies ist eine Tabellenvariable, keine temporäre Tabelle. Tabellenvariablen erlauben keine explizit benannten Einschränkungen. Die vom System generierten Namen sind garantiert eindeutig. Sie erlauben benannte Indizes aus dem Jahr 2014, aber das ist kein Problem, da Indizes nur innerhalb eines Objekts und nicht objektübergreifend eindeutig benannt werden müssen.
Martin Smith
Mein Punkt war 2-fach. 1) Abgesehen von der Verwendung einer Variablen zur Vermeidung von Transaktionsverflechtungen gibt es keinen wesentlichen Unterschied zwischen einer temporären Tabelle und einer Tabellenvariablen. In V-2000 gibt es jedoch keine Syntax zum Hinzufügen von Einschränkungen, Indizes ... zu einer Variablen. 2) Da kann man stattdessen eine temporäre Tabelle verwenden, benannte Tabelle Anhängsel wie Indizes WILL mit gleichzeitig ausgeführten Kopien des gleichen SP kollidieren , wenn ein statischer Name verwendet wird! Der folgende Mechanismus wurde explizit entwickelt, weil ich SP-Fehler auf benannte Indizes zurückführte, die unter genau diesen Umständen zusammenstießen. Sie müssen einzigartig sein.
Bielawski
1
@bielawski - Keine Indexnamen müssen nicht eindeutig zwischen Objekten sein - einzige Einschränkung Namen tun. Dies ist trivial zu testen. Einfach ausführenCREATE TABLE #T1(X INT); CREATE TABLE #T2(X INT); CREATE INDEX IX ON #T1(X); CREATE INDEX IX ON #T2(X);
Martin Smith

Antworten:

362

Die Frage ist mit SQL Server 2000 gekennzeichnet, aber zum Nutzen der Entwickler der neuesten Version werde ich dies zuerst ansprechen.

SQL Server 2014

Zusätzlich zu den unten beschriebenen Methoden zum Hinzufügen von auf Einschränkungen basierenden Indizes ermöglicht SQL Server 2014 auch die direkte Angabe nicht eindeutiger Indizes mit Inline-Syntax für Tabellenvariablendeklarationen.

Beispielsyntax dafür ist unten.

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

Gefilterte Indizes und Indizes mit eingeschlossenen Spalten können derzeit mit dieser Syntax nicht deklariert werden. SQL Server 2016 lockert dies jedoch etwas weiter. Ab CTP 3.1 können jetzt gefilterte Indizes für Tabellenvariablen deklariert werden. Nach RTM kann es vorkommen, dass eingeschlossene Spalten ebenfalls zulässig sind, aber die aktuelle Position ist, dass sie "aufgrund von Ressourcenbeschränkungen wahrscheinlich nicht in SQL16 gelangen".

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

Kann ich einen Index für den Namen erstellen?

Kurze Antwort: Ja.

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

Eine detailliertere Antwort finden Sie unten.

Herkömmliche Tabellen in SQL Server können entweder einen Clustered-Index haben oder als Heaps strukturiert sein .

Clustered-Indizes können entweder als eindeutig deklariert werden, um doppelte Schlüsselwerte nicht zuzulassen, oder standardmäßig als nicht eindeutig. Wenn dies nicht eindeutig ist, fügt SQL Server allen doppelten Schlüsseln stillschweigend einen eindeutigen Bezeichner hinzu , um sie eindeutig zu machen.

Nicht gruppierte Indizes können auch explizit als eindeutig deklariert werden. Andernfalls fügt SQL Server für den nicht eindeutigen Fall den Zeilenlokator (Clustered Index Key oder RID für einen Heap) allen Indexschlüsseln (nicht nur Duplikaten) hinzu, um sicherzustellen, dass sie eindeutig sind.

In SQL Server 2000 - 2012 können Indizes für Tabellenvariablen nur implizit durch Erstellen einer UNIQUEoder einer PRIMARY KEYEinschränkung erstellt werden. Der Unterschied zwischen diesen Einschränkungstypen besteht darin, dass sich der Primärschlüssel in nicht nullbaren Spalten befinden muss. Die an einer eindeutigen Einschränkung beteiligten Spalten können nullwertfähig sein. (obwohl die Implementierung eindeutiger Einschränkungen durch SQL Server in Gegenwart von NULLs nicht den im SQL-Standard angegebenen entspricht). Eine Tabelle kann auch nur einen Primärschlüssel, aber mehrere eindeutige Einschränkungen haben.

Diese beiden logischen Einschränkungen werden physisch mit einem eindeutigen Index implementiert. Wenn nicht explizit anders angegeben, PRIMARY KEYwird dies zum Clustered-Index und zu eindeutigen Constraints, die nicht geclustert sind. Dieses Verhalten kann jedoch durch Angabe CLUSTEREDoder NONCLUSTEREDexplizit mit der Constraint-Deklaration (Beispielsyntax) überschrieben werden.

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

Infolgedessen können die folgenden Indizes implizit für Tabellenvariablen in SQL Server 2000 - 2012 erstellt werden.

+-------------------------------------+-------------------------------------+
|             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                                 |
+-------------------------------------+-------------------------------------+

Der letzte bedarf einiger Erklärung. In der Tabellenvariablendefinition zu Beginn dieser Antwort wird der nicht eindeutige nicht gruppierte Index on Namedurch einen eindeutigen Index on simuliert Name,Id(denken Sie daran, dass SQL Server den gruppierten Indexschlüssel ohnehin stillschweigend zum nicht eindeutigen NCI-Schlüssel hinzufügen würde).

Ein nicht eindeutiger Clustered-Index kann auch durch manuelles Hinzufügen einer IDENTITYSpalte als eindeutiger Bezeichner erreicht werden.

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

Dies ist jedoch keine genaue Simulation, wie ein nicht eindeutiger Clustered-Index normalerweise in SQL Server implementiert wird, da dadurch allen Zeilen der "Uniqueifier" hinzugefügt wird. Nicht nur diejenigen, die es benötigen.

Martin Smith
quelle
1
Hinweis: Die Lösung 2000-2012 funktioniert nur, wenn die Textspalte <= 900 Byte ist. dh. varchar (900), nvarchar (450)
Andre Figueiredo
1
@AndreFigueiredo yep, das ist die maximale Größe für einen Indexschlüssel auch für permanente Tabellen in diesen Versionen.
Martin Smith
1
Ich wollte nur beachten, dass die SQL 2014-Antwort in Azure gut funktioniert. Danke Martin!
Jaxidian
13

Es versteht sich, dass es unter Leistungsgesichtspunkten keine Unterschiede zwischen @ temp-Tabellen und # temp-Tabellen gibt, die Variablen bevorzugen. Sie befinden sich am selben Ort (tempdb) und werden auf dieselbe Weise implementiert. Alle Unterschiede treten in zusätzlichen Funktionen auf. Sehen Sie sich diese erstaunlich vollständige Beschreibung an: /dba/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

Obwohl es Fälle gibt, in denen eine temporäre Tabelle nicht verwendet werden kann, z. B. in Tabellen- oder Skalarfunktionen, können Sie in den meisten anderen Fällen vor v2016 (in denen sogar gefilterte Indizes zu einer Tabellenvariablen hinzugefügt werden können) einfach eine # temp-Tabelle verwenden.

Der Nachteil bei der Verwendung benannter Indizes (oder Einschränkungen) in Tempdb besteht darin, dass die Namen dann zusammenstoßen können. Nicht nur theoretisch mit anderen Prozeduren, sondern oft recht einfach mit anderen Instanzen der Prozedur selbst, die versuchen würden, denselben Index auf ihre Kopie der # temp-Tabelle zu setzen.

Um Namenskonflikte zu vermeiden, funktioniert normalerweise so etwas:

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

Dies stellt sicher, dass der Name auch zwischen gleichzeitigen Ausführungen derselben Prozedur immer eindeutig ist.

bielawski
quelle
Es hat eine fehlende Klammer nach varchar (40), fügen Sie hinzu, dass
Tejasvi Hegde
1
Es gibt kein Problem mit benannten Indizes - Indizes müssen nur innerhalb einer Tabelle eindeutig benannt werden. Das Problem liegt bei benannten Einschränkungen, und die beste Lösung besteht im Allgemeinen darin, sie nicht in temporären Tabellen zu benennen. Benannte Einschränkungen verhindern das Zwischenspeichern von temporären Tabellenobjekten.
Martin Smith
1
Dies muss nur für bestimmte Versionen gelten (wenn dies für eine Version gilt). Ich musste diese Problemumgehung speziell entwickeln, weil ich sp-Fehler auf das Aufeinandertreffen benannter Indizes bei gleichzeitiger Ausführung zurückführte.
Bielawski
@bielawski Benutzt du 2016? Ich bin sehr gespannt, ob benannte Indizes für temporäre Tabellen ein Risiko für gleichzeitige Umgebungen darstellen.
Elaskanator
1
@ Elaskanator ja, das sind sie. Wir haben unter Last Konflikte in den SQL-Metadatentabellen festgestellt. Durch Entfernen des Indexnamens wurde das Problem behoben. Dies war SQL 2016.
Dan Def
0

Wenn die Tabellenvariable große Datenmengen enthält, können Sie anstelle der Tabellenvariablen (@table) keine temporäre Tabelle (#table) erstellen. Mit der Variablen .table kann nach dem Einfügen kein Index erstellt werden.

 CREATE TABLE #Table(C1 int,       
  C2 NVarchar(100) , C3 varchar(100)
  UNIQUE CLUSTERED (c1) 
 ); 
  1. Erstellen Sie eine Tabelle mit einem eindeutigen Clustered-Index

  2. Fügen Sie Daten in die Tabelle "#Table" von Temp ein

  3. Erstellen Sie nicht gruppierte Indizes.

     CREATE NONCLUSTERED INDEX IX1  ON #Table (C2,C3);
Boopathi.Indotnet
quelle
Index nach
Einfügeanweisung
Beachten Sie, dass dies nicht möglich ist, wenn sich die Tabellenvariable in einer Funktion befindet
Geoff