web-dev-qa-db-fra.com

Est-il possible d'ajouter un index à une table temporaire? Et quelle est la différence entre créer #t et déclarer @t

J'ai besoin de faire une requête très complexe. À un moment donné, cette requête doit avoir une jointure avec une vue qui ne peut malheureusement pas être indexée. Cette vue est également une vue complexe joignant de grandes tables.

La sortie de la vue peut être simplifiée comme ceci:

PID (int), Kind (int), Date (date), D1,D2..DN

où les champs PID et Date et Kind ne sont pas uniques (il peut y avoir plus d'une ligne ayant la même combinaison de pid, kind, date), mais sont ceux qui seront utilisés dans join comme ceci

left join ComplexView mkcs on mkcs.PID=q4.PersonID and mkcs.Date=q4.date and mkcs.Kind=1
left join ComplexView mkcl on mkcl.PID=q4.PersonID and mkcl.Date=q4.date and mkcl.Kind=2
left join ComplexView mkco on mkco.PID=q4.PersonID and mkco.Date=q4.date and mkco.Kind=3

Maintenant, si je le fais comme ça, l'exécution de la requête prend beaucoup de temps car la vue complexe est exécutée trois fois, je suppose, et sur son énorme nombre de lignes, seules certaines sont réellement utilisées (comme sur 40000, seules 2000 sont utilisé)

Ce que j'ai fait, c'est déclarer @temptable, et insérer dans @temptable select * de ComplexView où Date ... - une fois par requête, je ne sélectionne que les lignes que je vais utiliser dans mon ComplexView, puis je rejoins ce @temptable.

Cela a considérablement réduit le temps d'exécution.

Cependant, j'ai remarqué que si je crée une table dans ma base de données et que j'ajoute un index clusterisé sur PID, Kind, Date (cluster non unique) et que je prends des données de cette table, puis en supprimant * de cette table et en l'insérant dans cette la table à partir d'une vue complexe prend quelques secondes (3 ou 4), puis en utilisant cette table dans ma requête (à gauche en la joignant trois fois), réduisez le temps de requête de moitié, de 1 minute à 30 secondes!

Donc, ma question est, tout d'abord - est-il possible de créer des index sur les @temptables déclarés. Et puis - j'ai vu des gens parler de la syntaxe "create #temptable". C'est peut-être ce dont j'ai besoin? Où puis-je lire quelle est la différence entre déclarer @temptable et créer #temptable? Que dois-je utiliser pour une requête comme la mienne? (cette requête concerne le rapport MS Reporting Services, le cas échéant).

14
Istrebitel

Ce n'est pas une réponse complète, mais #table créera une table temporaire que vous devrez supprimer ou elle persistera dans votre base de données. @table est une variable de table qui ne persistera pas plus longtemps que votre script.

Aussi, je pense que ce post répondra à l'autre partie de votre question.

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

2
Brian Dishaw

#tablename est une table physique, stockée dans tempdb que le serveur supprimera automatiquement lorsque la connexion qui l'a créé est fermée, @tablename est une table stockée en mémoire et vit pour la durée de vie du lot/de la procédure qui l'a créée, tout comme une variable locale.

Vous pouvez uniquement ajouter un index (non PK) à un #temp table.

create table #blah (fld int)
create nonclustered index idx on #blah (fld)
7
Alex K.

Oui, vous pouvez créer des index sur des tables temporaires ou des variables de table. http://sqlserverplanet.com/sql/create-index-on-table-variable/

2
JeffO

Pour étendre la réponse d'Alex K., vous pouvez créez le PRIMARY KEY sur une table temporaire

IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL
 DROP TABLE #tempTable

CREATE TABLE #tempTable 
(
   Id INT PRIMARY KEY
  ,Value NVARCHAR(128)
)

INSERT INTO #tempTable
VALUES 
     (1, 'first value')
    ,(3, 'second value')
    -- will cause Violation of PRIMARY KEY constraint 'PK__#tempTab__3214EC071AE8C88D'. Cannot insert duplicate key in object 'dbo.#tempTable'. The duplicate key value is (1).
    --,(1, 'first value one more time')


SELECT  * FROM #tempTable
0
svonidze