4

In SQL For Smarties, Joe Celko provides an ANSI SQL definition of a Series table (elsewhere called Tally or Numbers). His definition ensures the values in the column are unique, positive and contiguous from 1 up 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 ensured by the constraint non_negative_nbr. With these two constraints in place, contiguity is ensured by the constraint numbers_are_complete.

SQL Server does not support subqueries in check constraints. When I try to create the Series table, I receive an error like this:

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 constraint numbers_are_complete, I'm left with 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 doesn't enforce contiguity of the numbers in the table.

To demonstrate this, first I have to populate the table. I have adapted a technique described by Itzik Ben-Gan in his article 'Virtual Auxiliary Table of Numbers' to do this efficiently 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 output like this:

(65536 row(s) affected)

Now I can select from the table like this to produce 65,536 rows:

SELECT seq
FROM Series;

I've truncated the result set, but it looks like this:

seq
1
2
...
65535
65536

Check it for yourself, and you'll see that every number in the interval [1, 65536] is in the result set. The series is contiguous.

But I can break contiguity by deleting any row that is not an endpoint of the range:

DELETE FROM Series
WHERE seq = 25788;

If contiguity were enforced, this statement would raise an error, but instead it succeeds:

(1 row(s) affected)

It would be difficult for a human to find the missing value by visual inspection. They would have to suspect that a value were missing in the first place before going to the trouble. For these reasons, tampering with the Series data is an easy way to introduce subtle bugs into an SQL Server application that relies on the Series table being contiguous.

Assume a user has written a query that reads from Sequence to enumerate rows from another source. After my tampering, that query would now produce incorrect results around a certain value - by the 25,788th row, everything is off by one.

It is possible to write a query to detect missing values in the Series table, but how do I constrain the table so that missing values are impossble?

Iain Samuel McLean Elder
  • 19,791
  • 12
  • 64
  • 80
  • 1
    Why allow deletes at all, no matter where in the range they fall? This is your database, you do have power over what DML is allowed against what objects. A check constraint is like dusting for prints on the cookie jar, and only prosecuting if it was the kid, IMHO. Lock the cookie jar up instead. – Aaron Bertrand Aug 29 '12 at 17:40
  • @AaronBertrand I don't understand what you say about check constraints. The constraint `numbers_are_complete` would enforce logically a single contiguous interval, without procedural code or reference to users. The constraint still allows one to extend or contract the interval, so you would use permissions to control who can do that. In reality, SQL Server does yet not support such a check constraint, so "locking up the cookie jar" with procedural code becomes the only option. – Iain Samuel McLean Elder Aug 30 '12 at 12:07
  • How do you equate "procedural code" with "permissions"? If users can't delete from the table, you don't need to check which rows they're deleting, do you? Do you have a good reason to allow users to delete from this auxiliary table? – Aaron Bertrand Aug 30 '12 at 12:43
  • Sorry: by procedural code I meant triggers that enforce data integrity like the those in your answer. The permissions are declarative, and should be in place regardless of the mechanism used to enforce integrity. In practice, a user should never delete from this table. The only delete operation that would make sense would be to shorten the interval of integers. Logically, this table could be infinite, so shortening doesn't happen in practice. If the interval ever had to be extended because 65,536 rows were not enough, an administrator would perform the insert operation rather than a user. – Iain Samuel McLean Elder Aug 30 '12 at 21:56

3 Answers3

4

I have three potential suggestions:


(1) Make your numbers table read-only (e.g. deny update/insert/delete). Why would you be deleting from this table, EVER? Your app certainly shouldn't be doing it, and your users shouldn't be able to manually do so either. No need for all these check constraints for users pressing the "what does this button do?" button, when you can simply remove the button.

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

(2) Even easier would be to create an instead of trigger to prevent deletes 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, this can be defeated, but someone has to really go out of their way to do it. And if you're employing folks that are likely to do this, and trusting them with generic access to the database, pray that this is the most damage they're planning to do.

And yes, you might forget to re-implement the trigger if you drop / re-create the numbers table or implement it somewhere else. But you might also forget anything you might manually do to deal with gaps anyway.


(3) You can avoid a numbers table altogether if you're willing to derive numbers on the fly. I use catalog views like sys.all_columns and sys.all_objects for this, depending on how many 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 only need 100 rows, you can just use one of the views without the cross join; if you need more, you can add more views. Not trying to push you away from a numbers table but this gets you around limitations such as (a) building a numbers table on every single instance and (b) people who are philosophically opposed to such a thing (I have come across many in my career).


As an aside, this really should be in the product. Please vote and state real business use cases in the following Connect item:

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

Aaron Bertrand
  • 272,866
  • 37
  • 466
  • 490
  • +1. The triggers and permissions express no ability to introduce contiguity, whereas the constraint expresses contiguity as a property of the data. Without the constraint, contiguity is only ever implicit. Unfortunately, SQL Server doesn't yet support sub-queries in a check constraint. In reality, A combination of your suggestions 1 and 2 I think would be the most effective. Thanks! – Iain Samuel McLean Elder Aug 30 '12 at 12:19
  • As for forgetting to create triggers or permissions: I use SQL Compare to script my database schemas to version control, and to create new databases from version control. Each table script contains the permissions and triggers associated with the table, so I deploy them all in one step. By doing this I have to go out of my way to forget them! – Iain Samuel McLean Elder Aug 30 '12 at 12:22
  • Jeff Moden's [comment](http://stackoverflow.com/questions/12183062/how-to-ensure-contiguity-of-a-tally-table/12183063#comment25108475_12183063) made me reconsider. Your solution is the most practical. My solution produces messy query plans and makes it easy to spawn four billion rows by accident. I'd never want to put that into production! – Iain Samuel McLean Elder Dec 08 '13 at 22:59
2

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

This view definition is based on the same article referenced in the question and produces up to 65,536 unique, positive, and contiguous rows:

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;

In this way, the row numbers are always generated at query time by the ROW_NUMBER function. The set of values output by the ROW_NUMBER functon is contiguous, and every value is unique and positive.

If you try to delete from the view:

DELETE FROM SeriesView
WHERE seq = 25788;

The server will raise an error because the view is not updatable:

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

contains a derived or constant field.

I have not compared the performance of this technique compared to storing the values in a table. Both seem fast enough in practice, though I admit I've yet to use the view in production.

Performance-tuning of queries that select from Series is probably going to be more difficult because of the large execution plan generated by simply selecting from the view.

Simply 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 selecting from the 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 much larger because of the many cross joins.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Iain Samuel McLean Elder
  • 19,791
  • 12
  • 64
  • 80
  • 1
    Consider NOT using a view for this because it is missing the TOP optimization to keep overruns from happening with poorly formed joins. – Jeff Moden Jun 26 '13 at 05:37
  • @JeffModen Good point. [Itzik Ben-Gan](http://sqlmag.com/sql-server/virtual-auxiliary-table-numbers) shows how to include the TOP optimization by using a table-valued function istead of a view. You have to specify how many rows you want to use the function, so it's harder to accidentally join to four billion rows. – Iain Samuel McLean Elder Jun 26 '13 at 10:13
  • 13
    This is the [longest Stack Overflow post](http://data.stackexchange.com/stackoverflow/query/248047). Mother of nesting… – bjb568 Nov 17 '14 at 11:50
  • 3
    @bjb568 A dubious honor :-) It's not a great answer either. Perhaps one day I'll delete it and replace it with a better, shorter answer. – Iain Samuel McLean Elder Nov 17 '14 at 17:29
1

Move your numbers_are_complete constraint query into in INSERT/UPDATE/DELETE trigger instead, and you should have no problems.

D'Arcy Rittich
  • 167,292
  • 40
  • 290
  • 283