Comment assurer la contiguïté d'une table de comptage?

Dans SQL For Smarties , Joe Celko fournit une définition ANSI SQL d'une table Series (appelée ailleurs Tally ou Numbers). Sa définition garantit que les valeurs dans la colonne sont uniques, positives et contiguës de 1 jusqu'à la valeur maximale:

CREATE TABLE Series ( seq INTEGER NOT NULL PRIMARY KEY, CONSTRAINT non_negative_nbr CHECK (seq > 0), CONSTRAINT numbers_are_complete CHECK ((SELECT COUNT(*) FROM Series) = (SELECT MAX(seq) FROM Series)) ); 

L'unicité est assurée par la déclaration PRIMARY KEY. La positivité est assurée par la contrainte non_negative_nbr . Avec ces deux contraintes en place, la contiguïté est assurée par la contrainte numbers_are_complete .

SQL Server ne prend pas en charge les sous-requêtes dans les contraintes de vérification. Lorsque j'essaie de créer la table Series, je reçois une erreur comme celle-ci:

 Msg 1046, Level 15, State 1, Line 4 Subqueries are not allowed in this context. Only scalar expressions are allowed. Msg 102, Level 15, State 1, Line 4 Incorrect syntax near ')'. 

Si je supprime la contrainte non supscope numbers_are_complete , il me rest cette définition:

 CREATE TABLE Series ( seq INTEGER NOT NULL PRIMARY KEY, CONSTRAINT non_negative_nbr CHECK (seq > 0) ); 

Lorsque j'essaie de créer cette version de Series, elle réussit:

 Command(s) completed successfully. 

Cette version de Series est plus faible car elle n'applique pas la contiguïté des nombres dans la table.

Pour le démontrer, je dois d'abord remplir la table. J'ai adapté une technique décrite par Itzik Ben-Gan dans son article « Virtual Table des nombres auxiliaires » pour le faire efficacement pour 65 536 lignes:

 WITH N0(_) AS (SELECT NULL UNION ALL SELECT NULL), N1(_) AS (SELECT NULL FROM N0 AS L CROSS JOIN N0 AS R), N2(_) AS (SELECT NULL FROM N1 AS L CROSS JOIN N1 AS R), N3(_) AS (SELECT NULL FROM N2 AS L CROSS JOIN N2 AS R), N4(_) AS (SELECT NULL FROM N3 AS L CROSS JOIN N3 AS R) INSERT INTO Series ( seq ) SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM N4; 

La requête produit une sortie comme celle-ci:

 (65536 row(s) affected) 

Maintenant, je peux choisir dans la table comme ceci pour produire 65 536 lignes:

 SELECT seq FROM Series; 

J'ai tronqué le jeu de résultats, mais il ressemble à ceci:

 seq 1 2 ... 65535 65536 

Vérifiez-le par vous-même, et vous verrez que chaque nombre dans l'intervalle [1, 65536] est dans le jeu de résultats. La série est contiguë.

Mais je peux casser la contiguïté en supprimant n'importe quelle ligne qui n'est pas une extrémité de la gamme:

 DELETE FROM Series WHERE seq = 25788; 

Si la contiguïté était appliquée, cette instruction générerait une erreur, mais à la place elle réussirait:

 (1 row(s) affected) 

Il serait difficile pour un humain de find la valeur manquante par inspection visuelle. Ils devraient soupçonner qu'une valeur manquait en premier lieu avant d'aller à la peine. Pour ces raisons, la falsification des données de la série est un moyen facile d'introduire des bogues subtils dans une application SQL Server qui repose sur la table de série contiguë.

Supposons qu'un user a écrit une requête qui lit à partir de la séquence pour énumérer les lignes d'une autre source. Après ma falsification, cette requête produirait maintenant des résultats incorrects autour d'une certaine valeur – par la 25 788ème rangée, tout est éteint par un.

Il est possible d'écrire une requête pour détecter les valeurs manquantes dans la table Séries, mais comment puis-je contraindre la table pour que les valeurs manquantes soient impossibles?

J'ai trois suggestions potentielles:


(1) Faites en sorte que votre table de numbers soit en lecture seule (par exemple, refuser la mise à jour / insertion / suppression). Pourquoi voudriez-vous supprimer de cette table, JAMAIS? Votre application ne devrait certainement pas le faire, et vos users ne devraient pas être en mesure de le faire manuellement non plus. Pas besoin de toutes ces contraintes de vérification pour les users en appuyant sur le button "Que fait ce button?" button, lorsque vous pouvez simplement supprimer le button.

 DENY DELETE ON dbo.Serial TO [your_app_user]; -- repeat for individual users/roles 

(2) Encore plus facile serait de créer un au lieu de triggersr pour empêcher les suppressions en premier lieu:

 CREATE TRIGGER dbo.LeaveMyNumbersAlone ON dbo.Serial INSTEAD OF DELETE AS BEGIN SET NOCOUNT ON; RAISERROR('Please leave my numbers table alone.', 11, 1); END 

Oui, cela peut être vaincu, mais quelqu'un doit vraiment faire tout son possible pour le faire. Et si vous employez des gens qui sont susceptibles de faire cela, et leur faire confiance avec un access générique à la database, priez pour que ce soit le plus de dégâts qu'ils ont l'intention de faire.

Et oui, vous pourriez oublier de ré-implémenter le triggersur si vous supprimez / recréer la table de nombres ou l'implémenter ailleurs. Mais vous pourriez également oublier tout ce que vous pourriez faire manuellement pour faire face aux lacunes de toute façon.


(3) Vous pouvez éviter complètement un tableau de nombres si vous êtes prêt à dériver des nombres à la volée. J'utilise des vues de catalogue comme sys.all_columns et sys.all_objects pour cela, en fonction du nombre de nombres dont j'ai besoin:

 ;WITH n AS (SELECT TOP (10000) n FROM (SELECT n = ROW_NUMBER() OVER (ORDER BY s1.[object_id]) FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2 ) AS x ORDER BY n ) SELECT n FROM n ORDER BY n; -- look ma, no gaps! 

Si vous avez seulement besoin de 100 lignes, vous pouvez simplement utiliser l'une des vues sans la jointure croisée; Si vous avez besoin de plus, vous pouvez append plus de vues. Ne pas essayer de vous éloigner d'une table de numbers, mais cela vous permet de contourner des limitations telles que (a) build une table de numbers sur chaque instance et (b) les gens qui sont philosophiquement opposés à une telle chose (j'ai rencontré beaucoup dans mon carrière).


En aparté, cela devrait vraiment être dans le produit. Veuillez voter et indiquer les cas d'utilisation réels dans l'élément Connect suivant:

http://connect.microsoft.com/SQLServer/feedback/details/258733/add-a-built-in-table-of-numbers

Une façon de résoudre ce problème consiste à replace la table par une vue.

Cette définition de vue est basée sur le même article référencé dans la question et produit jusqu'à 65 536 lignes uniques, positives et contiguës:

 CREATE VIEW SeriesView AS WITH N0(_) AS (SELECT NULL UNION ALL SELECT NULL), N1(_) AS (SELECT NULL FROM N0 AS L CROSS JOIN N0 AS R), N2(_) AS (SELECT NULL FROM N1 AS L CROSS JOIN N1 AS R), N3(_) AS (SELECT NULL FROM N2 AS L CROSS JOIN N2 AS R), N4(_) AS (SELECT NULL FROM N3 AS L CROSS JOIN N3 AS R) SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS seq FROM N4; 

De cette manière, les numéros de ligne sont toujours générés au moment de la requête par la fonction ROW_NUMBER . L'set de valeurs généré par le foncton ROW_NUMBER est contigu et chaque valeur est unique et positive.

Si vous essayez de supprimer de la vue:

 DELETE FROM SeriesView WHERE seq = 25788; 

Le server triggersra une erreur car la vue ne peut pas être mise à jour:

 Msg 4406, Level 16, State 1, Line 1 Update or insert of view or function 'SeriesView' failed because it 

contient un champ dérivé ou constant.

Je n'ai pas comparé les performances de cette technique par rapport au stockage des valeurs dans un tableau. Les deux semblent assez rapides dans la pratique, bien que je reconnaisse que je n'ai pas encore utilisé la vue en production.

L'optimization des performances des requêtes sélectionnées dans la série sera probablement plus difficile en raison du grand plan d'exécution généré en sélectionnant simplement à partir de la vue.

Il suffit de comparer les longueurs de ces plans d'exécution pour comparer leur complexité apparente:

C'est le plan d'exécution généré en sélectionnant dans la table dans la question:

 <?xml version="1.0" encoding="utf-16"?> <ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1.1" Build="10.0.5500.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"> <BatchSequence> <Batch> <Statements> <StmtSimple StatementCompId="1" StatementEstRows="65535" StatementId="1" StatementOptmLevel="TRIVIAL" StatementSubTreeCost="0.153148" StatementText="SELECT seq&#xD;&#xA;FROM Series;" StatementType="SELECT" QueryHash="0x5765DD2692E59AB9" QueryPlanHash="0x598E82F24F85C8B9"> <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" /> <QueryPlan DegreeOfParallelism="1" CachedPlanSize="8" ComstackTime="0" ComstackCPU="0" ComstackMemory="80"> <RelOp AvgRowSize="11" EstimateCPU="0.0722455" EstimateIO="0.0809028" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="65535" LogicalOp="Clustered Index Scan" NodeId="0" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.153148" TableCardinality="65535"> <OutputList> <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[Series]" Column="seq" /> </OutputList> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="65535" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <IndexScan Ordered="false" ForcedIndex="false" NoExpandHint="false"> <DefinedValues> <DefinedValue> <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[Series]" Column="seq" /> </DefinedValue> </DefinedValues> <Object Database="[tempdb]" Schema="[dbo]" Table="[Series]" Index="[PK__Series__DDDFBCBE0F975522]" IndexKind="Clustered" /> </IndexScan> </RelOp> </QueryPlan> </StmtSimple> </Statements> </Batch> </BatchSequence> </ShowPlanXML> 

C'est le plan d'exécution généré en sélectionnant dans la vue dans ma réponse:

 <?xml version="1.0" encoding="utf-16"?> <ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1.1" Build="10.0.5500.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"> <BatchSequence> <Batch> <Statements> <StmtSimple StatementCompId="1" StatementEstRows="65536" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="TimeOut" StatementSubTreeCost="0.692044" StatementText="SELECT seq&#xD;&#xA;FROM SeriesView;" StatementType="SELECT" QueryHash="0xD7D3DE2C825E3F56" QueryPlanHash="0x927D671566369AAC"> <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" /> <QueryPlan DegreeOfParallelism="1" CachedPlanSize="32" ComstackTime="6" ComstackCPU="6" ComstackMemory="680"> <RelOp AvgRowSize="15" EstimateCPU="0.00524288" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="65536" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Sequence Project" EstimatedTotalSubtreeCost="0.692044"> <OutputList> <ColumnReference Column="Expr1065" /> </OutputList> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="65536" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <SequenceProject> <DefinedValues> <DefinedValue> <ColumnReference Column="Expr1065" /> <ScalarOperator ScalarSsortingng="row_number"> <Sequence FunctionName="row_number" /> </ScalarOperator> </DefinedValue> </DefinedValues> <RelOp AvgRowSize="15" EstimateCPU="0.00131072" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="65536" LogicalOp="Segment" NodeId="1" Parallel="false" PhysicalOp="Segment" EstimatedTotalSubtreeCost="0.686801"> <OutputList> <ColumnReference Column="Expr1064" /> <ColumnReference Column="Segment1066" /> </OutputList> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="65536" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <Segment> <GroupBy /> <SegmentColumn> <ColumnReference Column="Segment1066" /> </SegmentColumn> <RelOp AvgRowSize="11" EstimateCPU="0.0065536" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="65536" LogicalOp="Compute Scalar" NodeId="2" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="0.68549"> <OutputList> <ColumnReference Column="Expr1064" /> </OutputList> <ComputeScalar> <DefinedValues> <DefinedValue> <ColumnReference Column="Expr1064" /> <ScalarOperator ScalarSsortingng="NULL"> <Const ConstValue="NULL" /> </ScalarOperator> </DefinedValue> </DefinedValues> <RelOp AvgRowSize="9" EstimateCPU="0.27394" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="65536" LogicalOp="Inner Join" NodeId="3" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.678937"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="65536" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.13697" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="32768" LogicalOp="Inner Join" NodeId="4" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.33946"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="32768" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.0684851" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="16384" LogicalOp="Inner Join" NodeId="5" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.169722"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="16384" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.0342426" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="8192" LogicalOp="Inner Join" NodeId="6" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0848524"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="8192" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.0171213" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="4096" LogicalOp="Inner Join" NodeId="7" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0424177"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="4096" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.00856064" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="2048" LogicalOp="Inner Join" NodeId="8" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0212003"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="2048" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.00428032" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1024" LogicalOp="Inner Join" NodeId="9" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0105915"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="1024" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.00214016" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="512" LogicalOp="Inner Join" NodeId="10" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.00528701"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="512" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.00107008" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="256" LogicalOp="Inner Join" NodeId="11" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0026347"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="256" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.00053504" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="128" LogicalOp="Inner Join" NodeId="12" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.00130846"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="128" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.00026752" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="64" LogicalOp="Inner Join" NodeId="13" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.000645262"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="64" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="0.00013376" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="32" LogicalOp="Inner Join" NodeId="14" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.000313585"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="32" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="6.688E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="16" LogicalOp="Inner Join" NodeId="15" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.000147668"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="16" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="3.344E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="8" LogicalOp="Inner Join" NodeId="16" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="6.4631E-05"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="8" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="1.672E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="4" LogicalOp="Inner Join" NodeId="17" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="2.3034E-05"> <OutputList /> <Warnings NoJoinPredicate="true" /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="4" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <NestedLoops Optimized="false"> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="2" LogicalOp="Constant Scan" NodeId="18" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="2.157E-06"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="2" ActualEndOfScans="1" ActualExecutions="1" /> </RunTimeInformation> <ConstantScan /> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="1" EstimateRows="2" LogicalOp="Constant Scan" NodeId="19" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="4.157E-06"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="4" ActualEndOfScans="2" ActualExecutions="2" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="1" EstimateRows="2" LogicalOp="Constant Scan" NodeId="20" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="4.157E-06"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="8" ActualEndOfScans="4" ActualExecutions="4" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="1" EstimateRows="2" LogicalOp="Constant Scan" NodeId="21" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="4.157E-06"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="16" ActualEndOfScans="8" ActualExecutions="8" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="15" EstimateRows="2" LogicalOp="Constant Scan" NodeId="22" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="3.2157E-05"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="32" ActualEndOfScans="16" ActualExecutions="16" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="15" EstimateRows="2" LogicalOp="Constant Scan" NodeId="23" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="3.2157E-05"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="64" ActualEndOfScans="32" ActualExecutions="32" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="15" EstimateRows="2" LogicalOp="Constant Scan" NodeId="24" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="3.2157E-05"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="128" ActualEndOfScans="64" ActualExecutions="64" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="15" EstimateRows="2" LogicalOp="Constant Scan" NodeId="25" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="3.2157E-05"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="256" ActualEndOfScans="128" ActualExecutions="128" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="255" EstimateRows="2" LogicalOp="Constant Scan" NodeId="26" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.000512157"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="512" ActualEndOfScans="256" ActualExecutions="256" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="255" EstimateRows="2" LogicalOp="Constant Scan" NodeId="27" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.000512157"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="1024" ActualEndOfScans="512" ActualExecutions="512" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="255" EstimateRows="2" LogicalOp="Constant Scan" NodeId="28" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.000512157"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="2048" ActualEndOfScans="1024" ActualExecutions="1024" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="255" EstimateRows="2" LogicalOp="Constant Scan" NodeId="29" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.000512157"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="4096" ActualEndOfScans="2048" ActualExecutions="2048" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="4095" EstimateRows="2" LogicalOp="Constant Scan" NodeId="30" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.00819216"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="8192" ActualEndOfScans="4096" ActualExecutions="4096" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="4095" EstimateRows="2" LogicalOp="Constant Scan" NodeId="31" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.00819216"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="16384" ActualEndOfScans="8192" ActualExecutions="8192" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="4095" EstimateRows="2" LogicalOp="Constant Scan" NodeId="32" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.00819216"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="32768" ActualEndOfScans="16384" ActualExecutions="16384" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> <RelOp AvgRowSize="9" EstimateCPU="2.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="4095" EstimateRows="2" LogicalOp="Constant Scan" NodeId="33" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="0.00819216"> <OutputList /> <RunTimeInformation> <RunTimeCountersPerThread Thread="0" ActualRows="65536" ActualEndOfScans="32768" ActualExecutions="32768" /> </RunTimeInformation> <ConstantScan /> </RelOp> </NestedLoops> </RelOp> </ComputeScalar> </RelOp> </Segment> </RelOp> </SequenceProject> </RelOp> </QueryPlan> </StmtSimple> </Statements> </Batch> </BatchSequence> </ShowPlanXML> 

La seconde est beaucoup plus grande à cause des nombreuses jointures croisées.

Déplacez votre numbers_are_complete contrainte numbers_are_complete dans le triggersur INSERT/UPDATE/DELETE place, et vous ne devriez avoir aucun problème.