CTEの両方の発生に対して単一のスプールを再利用する方法(2012年までのSQL Serverバージョン)はありません。詳細については、SQLKiwiの回答をご覧ください。さらに、CTEを2回具体化する2つの方法がありますが、これはクエリの性質上避けられません。どちらのオプションでも、6の正味の別個のGUIDカウントが得られます。
MartinのコメントからCTEを導く計画についてのブログの Quassnoiのサイトへのリンクは、この質問の部分的なインスピレーションでした。相関サブクエリの目的でCTEを具体化する方法について説明します。相関サブクエリは一度だけ参照されますが、相関によって複数回評価される可能性があります。質問のクエリには適用されません。
オプション1-プランガイド
SQLKiwiの答えからヒントを得て、私はまだ仕事をする最低限にガイドを縮小しました。例えば、ConstantScan
ノードは、任意の数に十分に拡張できる2つのスカラー演算子のみをリストします。
;with cte(guid,other) as (
select newid(),1 union all
select newid(),2 union all
select newid(),3)
select a.guid, a.other, b.guid guidb, b.other otherb
from cte a
cross join cte b
order by a.other, b.other
OPTION(USE PLAN
N'<?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.2" Build="11.0.2100.60" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementCompId="1" StatementEstRows="1600" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" StatementSubTreeCost="0.0444433" StatementText="with cte(guid,other) as (
 select newid(),1 union all
 select newid(),2 union all
 select newid(),3
select a.guid, a.other, b.guid guidb, b.other otherb
from cte a
cross join cte b
order by a.other, b.other;
" StatementType="SELECT" QueryHash="0x43D93EF17C8E55DD" QueryPlanHash="0xF8E3B336792D84" RetrievedFromCache="true">
<StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
<QueryPlan NonParallelPlanReason="EstimatedDOPIsOne" CachedPlanSize="96" CompileTime="13" CompileCPU="13" CompileMemory="1152">
<MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0" />
<OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="157240" EstimatedPagesCached="1420" EstimatedAvailableDegreeOfParallelism="1" />
<RelOp AvgRowSize="47" EstimateCPU="0.006688" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1600" LogicalOp="Inner Join" NodeId="0" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0444433">
<OutputList>
<ColumnReference Column="Union1163" />
</OutputList>
<Warnings NoJoinPredicate="true" />
<NestedLoops Optimized="false">
<RelOp AvgRowSize="27" EstimateCPU="0.000432115" EstimateIO="0.0112613" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="40" LogicalOp="Sort" NodeId="1" Parallel="false" PhysicalOp="Sort" EstimatedTotalSubtreeCost="0.0117335">
<OutputList>
<ColumnReference Column="Union1080" />
<ColumnReference Column="Union1081" />
</OutputList>
<MemoryFractions Input="0" Output="0" />
<Sort Distinct="false">
<OrderBy>
<OrderByColumn Ascending="true">
<ColumnReference Column="Union1081" />
</OrderByColumn>
</OrderBy>
<RelOp AvgRowSize="27" EstimateCPU="4.0157E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="40" LogicalOp="Constant Scan" NodeId="2" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="4.0157E-05">
<OutputList>
<ColumnReference Column="Union1080" />
<ColumnReference Column="Union1081" />
</OutputList>
<ConstantScan>
<Values>
<Row>
<ScalarOperator ScalarString="newid()">
<Intrinsic FunctionName="newid" />
</ScalarOperator>
<ScalarOperator ScalarString="(1)">
<Const ConstValue="(1)" />
</ScalarOperator>
</Row>
<Row>
<ScalarOperator ScalarString="newid()">
<Intrinsic FunctionName="newid" />
</ScalarOperator>
<ScalarOperator ScalarString="(2)">
<Const ConstValue="(2)" />
</ScalarOperator>
</Row>
</Values>
</ConstantScan>
</RelOp>
</Sort>
</RelOp>
<RelOp AvgRowSize="27" EstimateCPU="0.0001074" EstimateIO="0.01" EstimateRebinds="0" EstimateRewinds="39" EstimatedExecutionMode="Row" EstimateRows="40" LogicalOp="Lazy Spool" NodeId="83" Parallel="false" PhysicalOp="Table Spool" EstimatedTotalSubtreeCost="0.0260217">
<OutputList>
<ColumnReference Column="Union1162" />
<ColumnReference Column="Union1163" />
</OutputList>
<Spool>
<RelOp AvgRowSize="27" EstimateCPU="0.000432115" EstimateIO="0.0112613" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="40" LogicalOp="Sort" NodeId="84" Parallel="false" PhysicalOp="Sort" EstimatedTotalSubtreeCost="0.0117335">
<OutputList>
<ColumnReference Column="Union1162" />
<ColumnReference Column="Union1163" />
</OutputList>
<MemoryFractions Input="0" Output="0" />
<Sort Distinct="false">
<OrderBy>
<OrderByColumn Ascending="true">
<ColumnReference Column="Union1163" />
</OrderByColumn>
</OrderBy>
<RelOp AvgRowSize="27" EstimateCPU="4.0157E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="40" LogicalOp="Constant Scan" NodeId="85" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="4.0157E-05">
<OutputList>
<ColumnReference Column="Union1162" />
<ColumnReference Column="Union1163" />
</OutputList>
<ConstantScan>
<Values>
<Row>
<ScalarOperator ScalarString="newid()">
<Intrinsic FunctionName="newid" />
</ScalarOperator>
<ScalarOperator ScalarString="(1)">
<Const ConstValue="(1)" />
</ScalarOperator>
</Row>
<Row>
<ScalarOperator ScalarString="newid()">
<Intrinsic FunctionName="newid" />
</ScalarOperator>
<ScalarOperator ScalarString="(2)">
<Const ConstValue="(2)" />
</ScalarOperator>
</Row>
</Values>
</ConstantScan>
</RelOp>
</Sort>
</RelOp>
</Spool>
</RelOp>
</NestedLoops>
</RelOp>
</QueryPlan>
</StmtSimple>
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>'
);
オプション2-リモートスキャン
クエリの費用を増やし、リモートスキャンを導入することにより、結果が具体化されます。
with cte(guid,other) as (
select *
from OPENQUERY([TESTSQL\V2012], '
select newid(),1 union all
select newid(),2 union all
select newid(),3') x)
select a.guid, a.other, b.guid guidb, b.other otherb
from cte a
cross join cte b
order by a.other, b.other;