web-dev-qa-db-fra.com

Création d'une clé primaire sur une table temporaire - Quand?

J'ai une procédure stockée qui fonctionne avec une grande quantité de données. J'ai ces données insérées dans une table temporaire. Le flux général des événements est quelque chose comme

CREATE #TempTable (
    Col1    NUMERIC(18,0) NOT NULL,    --This will not be an identity column.
    ,Col2   INT NOT NULL,
    ,Col3   BIGINT,

    ,Col4   VARCHAR(25) NOT NULL,
    --Etc...

    --
    --Create primary key here?
)


INSERT INTO #TempTable
SELECT ...
FROM MyTable
WHERE ...

INSERT INTO #TempTable
SELECT ...
FROM MyTable2
WHERE ...

--
-- ...or create primary key here?

_ {Ma question est la suivante: quel est le meilleur moment pour créer une clé primaire sur ma table #TempTable?} en tant que clé primaire, les informations sont en cours de création. Mais je me suis rendu compte que mon hypothèse de base était peut-être fausse ...

Au cas où cela serait pertinent, les types de données que j'ai utilisés sont réels. Dans la table #TempTable, Col1 et Col4 constitueront ma clé primaire. 

Update: Dans mon cas, je duplique la clé primaire des tables source. Je sais que les champs qui constitueront ma clé primaire seront toujours uniques. Je n'ai aucune inquiétude quant à l'échec d'une table alter si j'ajoute la clé primaire à la fin. 

Bien que, mis à part cela, {ma question reste posée comme ce qui est plus rapide en supposant que les deux réussiraient}? 

P.S. Je suis désolé s'il s'agit d'un doublon. C'est assez basique pour le faire, mais je n'ai rien trouvé de tel. 

20
Frank V

Ceci dépend beaucoup.

Si vous configurez l'index de clé primaire en cluster après le chargement, l'intégralité de la table sera réécrite car l'index en cluster n'est pas vraiment un index, il s'agit de l'ordre logique des données. Votre plan d'exécution sur les insertions dépendra des index en place lors de la détermination du plan. Si l'index en cluster est en place, il sera trié avant l'insertion. Vous verrez généralement cela dans le plan d'exécution.

Si vous faites de la clé primaire une contrainte simple, il s'agira d'un index régulier (non clusterisé) et la table sera simplement remplie dans l'ordre de l'optimiseur et de la mise à jour de l'index.

Je pense que la performance globale la plus rapide (de ce processus pour charger la table temporaire) consiste généralement à écrire les données sous forme de tas, puis à appliquer l'index (non clusterisé).

Cependant, comme d'autres l'ont noté, la création de l'index pourrait échouer. En outre, la table temporaire n'existe pas de manière isolée. Vraisemblablement, il existe un meilleur index pour lire les données à partir de cela pour la prochaine étape. Cet index devra être en place ou créé. Ceci est l'endroit où vous devez faire un compromis entre la vitesse ici pour la fiabilité (appliquez d'abord la PK et toute autre contrainte) et la vitesse plus tard (ayez au moins l'index clusterisé en place si vous en avez une).

15
Cade Roux

Si le modèle de récupération de votre base de données est défini sur simple ou en bloc, SELECT ... INTO ... UNION ALL peut être la solution la plus rapide. SELECT .. INTO est une opération en bloc et les opérations en bloc sont journalisées de manière minimale. 

par exemple:

-- first, create the table
SELECT ...
INTO #TempTable
FROM MyTable
WHERE ...
UNION ALL
SELECT ...
FROM MyTable2
WHERE ...

-- now, add a non-clustered primary key:
-- this will *not* recreate the table in the background
-- it will only create a separate index
-- the table will remain stored as a heap
ALTER TABLE #TempTable ADD PRIMARY KEY NONCLUSTERED (NonNullableKeyField)

-- alternatively:
-- this *will* recreate the table in the background
-- and reorder the rows according to the primary key
-- CLUSTERED key Word is optional, primary keys are clustered by default
ALTER TABLE #TempTable ADD PRIMARY KEY CLUSTERED (NonNullableKeyField) 

Sinon, Cade Roux avait de bons conseils avant ou après.

6
Peter Radocchia

Vous pouvez également créer la clé primaire avant les insertions. Si la clé primaire se trouve sur une colonne d'identité, les insertions seront effectuées séquentiellement de toute façon et il n'y aura aucune différence.

3
Justin

Encore plus important que les considérations de performance, si vous n'êtes pas ABSOLUMENT, 100% sûr que vous aurez des valeurs uniques insérées dans la table, créez d'abord la clé primaire. Sinon, la clé primaire ne sera pas créée. 

Cela vous empêche d'insérer des données en double/incorrect.

2
Jeff Meatball Yang

Je me demandais si je pouvais améliorer une procédure stockée très très "coûteuse" impliquant un tas de vérifications à chaque insertion dans des tables et j'ai trouvé cette réponse. Dans le Sproc, plusieurs tables temporaires sont ouvertes et se référencent. J'ai ajouté la clé primaire à l'instruction CREATE TABLE (même si mes personnes choisissent d'utiliser les instructions WHERE NOT EXISTS pour insérer des données et garantir l'unicité) et mon temps d'exécution a été considérablement réduit. Je recommande fortement d'utiliser les clés primaires. Toujours au moins l'essayer même quand on pense ne pas en avoir besoin. 

1
user1076406

Si vous ajoutez la clé primaire lors de la création de la table, la première insertion sera libre (aucune vérification requise). La deuxième insertion doit simplement voir si elle est différente de la première. La troisième insertion doit vérifier deux lignes, etc. Les vérifications seront des recherches d'index, car il existe une contrainte unique.

Si vous ajoutez la clé primaire après toutes les insertions, chaque ligne doit être comparée à toutes les autres lignes. Donc, je suppose que l'ajout d'une clé primaire au début est moins cher. 

Mais peut-être que Sql Server dispose d’un moyen vraiment intelligent de vérifier l’unicité. Alors si vous voulez être sûr, mesurez-le!

1
Andomar

Je ne pense pas que cela fasse une différence significative dans votre cas:

  • soit vous payez la pénalité petit à petit, avec chaque insertion 
  • ou vous paierez une pénalité plus grande une fois que toutes les insertions auront été faites, mais seulement une fois. 

Lorsque vous le créez avant le début des insertions, vous pourriez potentiellement attraper des violations de clé PK lors de l'insertion des données, si la valeur de la PK n'est pas créée par le système. 

Mais à part ça - pas de grande différence, vraiment.

Marc

0
marc_s

Lorsque vous ajoutez une PK à la création de table, la vérification d'insertion est O(Tn) (où Tn est "le n-ème nombre triangulaire", qui est 1 + 2 + 3 ... + n), car lorsque vous insérez la x-ème ligne, elle est comparée aux "x - 1" lignes insérées

Lorsque vous ajoutez PK after en insérant toutes les valeurs - le vérificateur est O(n^2) car lorsque vous insérez la xième rangée, il est comparé à toutes les lignes n existantes.

Le premier est évidemment plus rapide puisque O(Tn) est inférieur à O(n^2)

P.S. Exemple: si vous insérez 5 lignes, il s'agit des opérations 1 + 2 + 3 + 4 + 5 = 15 par rapport aux opérations 5^2 = 25.

0
Alex

Je n'avais pas l'intention de répondre à cette question car je ne suis pas sûr à 100% de mes connaissances à ce sujet. Mais comme il ne semble pas que vous obteniez beaucoup de réponses ...

Ma compréhension est qu'un PK est un index unique et lorsque vous insérez chaque enregistrement, votre index est mis à jour et optimisé. Donc ... si vous ajoutez les données en premier, puis créez l'index, l'index n'est optimisé qu'une fois.

Donc, si vous êtes sûr que vos données sont neutres (sans données de duplicata de la PK), je dirais alors insérer, puis ajouter la PK.

Mais si vos données peuvent contenir des données PK en double, je dirais tout d'abord de créer le PK afin qu'il soit bombardé dès que possible.

0
John MacIntyre