Question

J'ai une procédure stockée qui utilise 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? J'ai supposé que je devrais créer la contrainte / index de clé primaire après avoir inséré toutes les données car l'index doit être réorganisé au moment de la création des informations de clé primaire. Mais j’ai réalisé que mon hypothèse sous-jacente é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.

Mettre à jour: 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 de remplacement si j'ajoute la clé primaire à la fin.

Bien que, mis à part, ma question reste posée, à savoir quelle est la solution la 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 simple pour le faire, mais je n’ai rien trouvé de tel.

Était-ce utile?

La solution

Cela dépend beaucoup.

Si vous faites l'index de clé primaire en cluster après le chargement, la table entière sera réécrite car l'index en cluster n'est pas vraiment un index, c'est l'ordre logique des données. Votre plan d'exécution sur les insertions va dépendre 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 simple contrainte, il s'agira d'un index normal (non clusterisé) et la table sera simplement remplie dans l'ordre de l'optimiseur et de l'index mis à jour.

Je pense que la performance globale la plus rapide (de ce processus de chargement de 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éé. C’est là que vous devez faire un compromis entre vitesse et fiabilité (appliquez d’abord le PK et toutes les autres contraintes) et rapidité (ayez au moins l’index clusterisé en place si vous en avez une. ).

Autres conseils

Si le modèle de récupération de votre base de données est défini sur simple ou sur un journal 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 un bon conseil concernant: avant ou après.

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 et il n'y aura aucune différence.

Encore plus important que les considérations de performances, si vous n'êtes pas ABSOLUMENT, sûr à 100% 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.

Ceci vous empêche d'insérer des données dupliquées / incorrectes.

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é. Donc, si vous voulez être sûr, mesurez-le!

Je me demandais si je pouvais améliorer un très très "cher" procédure stockée impliquant un tas de vérifications à chaque insertion à travers les tables et est tombé sur 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 sélections utilisent 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.

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 importante une fois que toutes les insertions auront été effectuées, mais une seule fois

Lorsque vous le créez avant le début des insertions, vous pouvez intercepter potentiellement les 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

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

Je crois comprendre que la PC est un index unique. 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, celui-ci n'est optimisé qu'une fois.

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

Mais si vos données peuvent contenir des données de PC en double, je vous demanderais de créer le PK en premier, il sera bombardé dès que possible.

Lorsque vous ajoutez un PK lors de la création de la table, la vérification d'insertion est O (Tn) (où Tn est "n-ème nombre triangulaire", qui est 1 + 2 + 3 ... + n ), car lorsque vous insérez la xième rangée, elle est comparée à "x - 1" insérée précédemment. rangées

Lorsque vous ajoutez la PK après l'insertion de toutes les valeurs, le vérificateur est O (n ^ 2) , car lorsque vous insérez la xième rangée, elle est comparée à toutes les < code> n des lignes 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 ou 5 ^ 2 = 25

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top