SQL Server utilise toujours la combinaison d'opérateurs Split, Sort et Collapse lors de la gestion d'un index unique dans le cadre d'une mise à jour qui affecte (ou pourrait affecter) plusieurs lignes.
En examinant l'exemple de la question, nous pourrions écrire la mise à jour en tant que mise à jour à une seule ligne pour chacune des quatre lignes présentes:
-- Per row updates
UPDATE dbo.Banana SET pk = 2 WHERE pk = 1;
UPDATE dbo.Banana SET pk = 3 WHERE pk = 2;
UPDATE dbo.Banana SET pk = 4 WHERE pk = 3;
UPDATE dbo.Banana SET pk = 5 WHERE pk = 4;
Le problème est que la première instruction échouerait, car elle passe pk
de 1 à 2, et il y a déjà une ligne où pk
= 2. Le moteur de stockage SQL Server requiert que les index uniques restent uniques à chaque étape du traitement, même dans une seule instruction . Il s'agit du problème résolu par Split, Sort et Collapse.
Divisé
La première étape consiste à diviser chaque instruction de mise à jour en une suppression suivie d'une insertion:
DELETE dbo.Banana WHERE pk = 1;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
L'opérateur Split ajoute une colonne de code d'action au flux (ici intitulée Act1007):
Le code d'action est 1 pour une mise à jour, 3 pour une suppression et 4 pour une insertion.
Trier
Les instructions fractionnées ci-dessus produiraient toujours une fausse violation de clé unique transitoire, donc l'étape suivante consiste à trier les instructions par les clés de l'index unique en cours de mise à jour ( pk
dans ce cas), puis par le code d'action. Pour cet exemple, cela signifie simplement que les suppressions (3) sur la même clé sont ordonnées avant les insertions (4). L'ordre résultant est:
-- Sort (pk, action)
DELETE dbo.Banana WHERE pk = 1;
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Effondrer
L'étape précédente est suffisante pour garantir l'évitement des fausses violations d'unicité dans tous les cas. À titre d'optimisation, Collapse combine des suppressions et des insertions adjacentes sur la même valeur de clé dans une mise à jour:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1;
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2;
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3;
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Les paires suppression / insertion pour les pk
valeurs 2, 3 et 4 ont été combinées dans une mise à jour, laissant une seule suppression sur pk
= 1 et une insertion pour pk
= 5.
L'opérateur Réduire regroupe les lignes par les colonnes clés et met à jour le code d'action pour refléter le résultat de la réduction:
Mise à jour de l'index en cluster
Cet opérateur est étiqueté comme une mise à jour, mais il est capable d'insertions, de mises à jour et de suppressions. L'action entreprise par la mise à jour d'index cluster par ligne est déterminée par la valeur du code d'action dans cette ligne. L'opérateur a une propriété Action pour refléter ce mode de fonctionnement:
Compteurs de modification de ligne
Notez que les trois mises à jour ci - dessus ne modifient pas la ou les clés de l'index unique en cours de maintenance. En effet, nous avons transformé les mises à jour des colonnes clés de l'index en mises à jour des colonnes non clés ( c1
et c2
), plus une suppression et une insertion. Ni une suppression ni une insertion ne peuvent provoquer une fausse violation de clé unique.
Une insertion ou une suppression affecte chaque colonne de la ligne, les statistiques associées à chaque colonne verront donc leurs compteurs de modification incrémentés. Pour les mises à jour, seules les statistiques avec l'une des colonnes mises à jour comme colonne de tête voient leurs compteurs de modification incrémentés (même si la valeur est inchangée).
Les compteurs de modification de ligne de statistiques affichent donc 2 changements à pk
, et 5 pour c1
et c2
:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1; -- All columns modified
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4; -- c1 and c2 modified
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z'); -- All columns modified
Remarque: seules les modifications appliquées à l' objet de base (segment de mémoire ou index cluster) affectent les compteurs de modification des lignes de statistiques. Les index non groupés sont des structures secondaires, reflétant les modifications déjà apportées à l'objet de base. Ils n'affectent pas du tout les compteurs de modification des lignes de statistiques.
Si un objet a plusieurs index uniques, une combinaison séparée de séparation, tri, réduction est utilisée pour organiser les mises à jour de chacun. SQL Server optimise ce cas pour les index non clusterisés en enregistrant le résultat du fractionnement dans un spouleur de table désireux, puis en relisant cet ensemble pour chaque index unique (qui aura ses propres clés Trier par index + code d'action et Réduire).
Effet sur les mises à jour des statistiques
Les mises à jour automatiques des statistiques (si activées) se produisent lorsque l'optimiseur de requêtes a besoin d'informations statistiques et constate que les statistiques existantes sont obsolètes (ou invalides en raison d'un changement de schéma). Les statistiques sont considérées comme obsolètes lorsque le nombre de modifications enregistrées dépasse un seuil.
L'arrangement Split / Sort / Collapse entraîne l' enregistrement de modifications de ligne différentes de celles attendues. Ceci, à son tour, signifie qu'une mise à jour des statistiques peut être déclenchée tôt ou tard que ce ne serait le cas autrement.
Dans l'exemple ci-dessus, les modifications de ligne pour la colonne clé augmentent de 2 (la modification nette) plutôt que de 4 (une pour chaque ligne de tableau affectée), ou 5 (une pour chaque suppression / mise à jour / insertion produite par la réduction).
En outre, les colonnes non clés qui n'ont pas été logiquement modifiées par la requête d'origine accumulent des modifications de ligne, qui peuvent compter jusqu'à deux fois les lignes de table mises à jour (une pour chaque suppression et une pour chaque insertion).
Le nombre de modifications enregistrées dépend du degré de chevauchement entre les anciennes et les nouvelles valeurs de la colonne clé (et donc du degré auquel les suppressions et les insertions peuvent être réduites). En réinitialisant la table entre chaque exécution, les requêtes suivantes montrent l'effet sur les compteurs de modification de lignes avec différents chevauchements:
UPDATE dbo.Banana SET pk = pk + 0; -- Full overlap
UPDATE dbo.Banana SET pk = pk + 1;
UPDATE dbo.Banana SET pk = pk + 2;
UPDATE dbo.Banana SET pk = pk + 3;
UPDATE dbo.Banana SET pk = pk + 4; -- No overlap