How to ensure table table contact?

In SQL for Smarties , Joe Celko provides an ANSI SQL definition for the Series table (elsewhere called Tally or Numbers). Defining it ensures that the values ​​in the column are unique, positive, and adjacent from 1 to the maximum value:

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)) ); 

Uniqueness is ensured by the PRIMARY KEY declaration. Positivity is provided by the non_negative_nbr constraint. With these two constraints, adjacency is ensured by the numbers_are_complete constraint.

SQL Server does not support subqueries in control constraints. When I try to create a Series table, I get this error:

 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 ')'. 

If I remove the unsupported numbers_are_complete restriction, I will leave this definition:

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

When I try to create this version of Series, it succeeds:

 Command(s) completed successfully. 

This version of Series is weaker because it does not provide the adjacency of numbers in the table.

To demonstrate this, I first need to fill out a table. I applied the method described by Itzik Ben-Gan in his article β€œ Virtual Auxiliary Number Table” to do this effectively for 65,536 rows:

 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; 

The query produces the output as follows:

 (65536 row(s) affected) 

Now I can choose from a table like this to create 65,536 rows:

 SELECT seq FROM Series; 

I trimmed the result set, but it looks like this:

 seq 1 2 ... 65535 65536 

Check it yourself, and you will see that each number in the interval [1, 65536] is in the result set. The row is adjacent.

But I can break the contact by deleting any line that is not the endpoint of the range:

 DELETE FROM Series WHERE seq = 25788; 

If the matching has been completed, this statement raises an error, but instead succeeds:

 (1 row(s) affected) 

It would be difficult for a person to find the missing value through visual inspection. They would have to suspect that value was lost in the first place before going on occasion. For these reasons, Series data spoofing is an easy way to introduce subtle errors into a SQL Server application based on Series table continuity.

Suppose a user writes a query that reads from Sequence to list strings from another source. After my intervention, this query will now produce incorrect results around a certain value - on the 25,788th line, everything is disabled by one.

You can write a query to detect missing values ​​in the Series table, but how to limit the table so that missing values ​​are impossible?

+4
source share
3 answers

I have three possible suggestions:


(1) Make the table of numbers read-only (e.g. deny update / insert / delete). Why would you leave this table EVER? Your application, of course, should not do this, and your users will not be able to do this manually either. There is no need for all of these validation restrictions for users who click β€œwhat does this button do?” When you can simply remove the button.

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

(2) It would be even simpler to create instead of a trigger to prevent deletion in the first place:

 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 

Yes, it can be defeated, but someone really has to go out of their way to do this. And if you hire people who can do this, and trusting them to share the database, pray that this is the biggest damage that they plan to do.

And yes, you can forget to repeat the implementation of the trigger if you reset / re-create the table of numbers or implement it somewhere else. But you can also forget everything you could do manually to deal with the gaps.


(3) You can avoid the numbers table altogether if you are ready to print numbers on the fly. For this, I use catalog representations such as sys.all_columns and sys.all_objects, depending on the number of numbers I need:

 ;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! 

If you need only 100 lines, you can simply use one of the views without cross-connection; if you need more, you can add more views. Do not try to push you away from the table of numbers, but this creates restrictions for you, such as (a) building a table of numbers on each individual copy and (b) people who philosophically object to such a thing (I have met many in my career).


Aside, it really should be in the product. Please vote and indicate the real cases of using the business in the next Connect section:

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

+4
source

One way to solve this problem is to replace the table with a view.

This definition definition is based on the same article the question refers to, and creates up to 65,536 unique, positive, and contiguous lines:

 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; 

Thus, line numbers are always generated during a request by the ROW_NUMBER function. The set of values ​​output by the ROW_NUMBER function is contiguous, and each value is unique and positive.

If you try to remove from the view:

 DELETE FROM SeriesView WHERE seq = 25788; 

The server will throw an error because the view is not updating:

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

contains a derivative or constant field.

I did not compare the performance of this method with storing values ​​in a table. Both seem fast enough in practice, although I admit that I have not yet used representation in the production process.

Tuning the performance of queries that are selected from a series is likely to be more difficult due to the large execution plan created by a simple selection from the view.

Just compare the lengths of these execution plans to compare their apparent complexity:

This is the execution plan generated by selecting from the table in the 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" CompileTime="0" CompileCPU="0" CompileMemory="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> 

This is the execution plan generated by choosing from a view in my answer:

 <?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" CompileTime="6" CompileCPU="6" CompileMemory="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 ScalarString="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 ScalarString="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> 

The second is significantly larger due to the many cross-connections.

+2
source

Move the numbers_are_complete constraint numbers_are_complete to INSERT/UPDATE/DELETE instead, and you shouldn't have a problem.

+1
source

All Articles