web-dev-qa-db-fra.com

Création d'un index sur une variable de table

Pouvez-vous créer un index sur une variable de table dans SQL Server 2000?

c'est à dire.

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

Puis-je créer un index sur Nom?

176
GordyII

La question porte la mention SQL Server 2000, mais pour le bénéfice des développeurs de la dernière version, je vais d'abord en parler.

SQL Server 2014

Outre les méthodes d'ajout d'index basés sur des contraintes décrites ci-dessous, SQL Server 2014 permet également de spécifier directement des index non uniques avec la syntaxe inline dans les déclarations de variable de table.

Exemple de syntaxe pour cela est ci-dessous.

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

Les index filtrés et les index avec colonnes incluses ne peuvent pas être déclarés avec cette syntaxe, mais SQL Server 2016 l'assouplit un peu plus. À partir de CTP 3.1, il est maintenant possible de déclarer des index filtrés pour les variables de table. Par RTM il peut être le cas où les colonnes incluses sont également autorisées, mais la position actuelle est qu'elles "ne le feront probablement pas en SQL16 en raison de contraintes de ressources "

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

Puis-je créer un index sur Nom?

Réponse courte: oui.

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

Une réponse plus détaillée est ci-dessous.

Les tables traditionnelles dans SQL Server peuvent avoir un index en cluster ou sont structurées comme tas .

Les index clusterisés peuvent être déclarés comme uniques pour interdire les valeurs de clé en double ou par défaut comme non uniques. Si ce n'est pas unique, SQL Server ajoute silencieusement un identifiant à toutes les clés dupliquées pour les rendre uniques.

Les index non clusterisés peuvent également être explicitement déclarés comme uniques. Sinon, pour le cas non unique SQL Server ajoute le localisateur de ligne (clé d'indexation en cluster ou RID pour un segment de mémoire) à toutes les clés d'index (pas seulement les doublons), cela garantit à nouveau ils sont uniques.

Dans SQL Server 2000 - 2012, les index sur les variables de table ne peuvent être créés implicitement qu'en créant une contrainte UNIQUE ou PRIMARY KEY. La différence entre ces types de contraintes réside dans le fait que la clé primaire doit se trouver sur une ou plusieurs colonnes non nullables. Les colonnes participant à une contrainte unique peuvent être nullables. (Bien que l'implémentation par SQL Server de contraintes uniques en présence de NULLs ne soit pas conforme à celle spécifiée dans le standard SQL). De plus, une table ne peut avoir qu'une seule clé primaire mais plusieurs contraintes uniques.

Ces deux contraintes logiques sont implémentées physiquement avec un index unique. Sinon, le PRIMARY KEY deviendra l'index cluster et les contraintes uniques non clusterisées, mais ce comportement peut être remplacé en spécifiant CLUSTERED ou NONCLUSTERED explicitement avec la déclaration de contrainte (syntaxe).

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

En conséquence de ce qui précède, les index suivants peuvent être créés de manière implicite sur des variables de table dans 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                                 |
+-------------------------------------+-------------------------------------+

Le dernier nécessite quelques explications. Dans la définition de variable de table au début de cette réponse, l’index non unique non clusterisé sur Name est simulé par un unique index sur Name,Id (rappelez-vous que SQL Server ajouterait de manière silencieuse la clé d'index en cluster à la clé NCI non unique de toute façon).

Un index cluster non unique peut également être obtenu en ajoutant manuellement une colonne IDENTITY pour agir en tant qu'unificateur.

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

Toutefois, il ne s'agit pas d'une simulation précise de la manière dont un index cluster non unique serait normalement implémenté dans SQL Server, car cela ajoute le "Uniqueifier" à toutes les lignes. Pas seulement ceux qui en ont besoin.

332
Martin Smith

Il faut comprendre que, du point de vue des performances, il n’ya pas de différences entre les tables @temp et les tables #temp privilégiant les variables. Ils résident au même endroit (tempdb) et sont implémentés de la même manière. Toutes les différences apparaissent dans des fonctionnalités supplémentaires. Voir cet article étonnamment complet: https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/ 16386 # 16386

Bien qu'il existe des cas dans lesquels une table temporaire ne peut pas être utilisée, comme dans des fonctions table ou scalaires, pour la plupart des cas antérieurs à v2016 (où même des index filtrés peuvent être ajoutés à une variable de table), vous pouvez simplement utiliser une table #temp.

L'inconvénient d'utiliser des index nommés (ou des contraintes) dans tempdb est que les noms peuvent alors entrer en conflit. Pas seulement théoriquement avec d'autres procédures, mais souvent assez facilement avec d'autres instances de la procédure elle-même qui essaieraient de mettre le même index sur sa copie de la table #temp.

Pour éviter les conflits de noms, cela fonctionne généralement comme suit:

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

Cela garantit que le nom est toujours unique, même entre les exécutions simultanées de la même procédure.

13
bielawski

Si la variable de table a des données volumineuses, alors, au lieu de la variable de table (@table), créer une table temporaire (#table). La variable de table ne permet pas de créer un index après l'insertion.

 CREATE TABLE #Table(C1 int,       
  C2 NVarchar(100) , C3 varchar(100)
  UNIQUE CLUSTERED (c1) 
 ); 
  1. Créer une table avec un index cluster unique

  2. Insérer des données dans la table Temp "#Table"

  3. Créer des index non clusterisés.

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