Em todos os lugares que li, diz que o custo estimado do operador é a soma do custo estimado da CPU e do custo estimado de E/S. No entanto, em muitos operadores que vejo, esse não é o caso. Aqui está um exemplo:
SELECT Column2
INTO Object1
FROM Object2
WHERE Column3 >= Variable2
AND Column3 <= Variable1
AND ( Column4 = Variable5
OR Variable5 = ? )
EstimateIO="0.01" EstimateCPU="0.000246492"
Soma: 0,010246492
No entanto, o SSMS mostra esse 0,073823 como o custo estimado do operador. Estou completamente perdido sobre como isso está sendo calculado. Abaixo está o xml do plano de execução (anônimo). Nó Id 0 é o nó em questão.
<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.2" Build="11.0.6537.0">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementText="	SELECT Column2 INTO Object1 
	FROM Object2
	WHERE Column3>=Variable2 AND Column3<=Variable1 
	AND (Column4=Variable5 OR Variable5=?)

" StatementId="1" StatementCompId="7" StatementType="SELECT INTO" RetrievedFromCache="true" StatementSubTreeCost="0.405134" StatementEstRows="246.492" StatementOptmLevel="FULL" QueryHash="0x180DF38DFFFEAFA2" QueryPlanHash="0x45A4295471B90968" StatementOptmEarlyAbortReason="GoodEnoughPlanFound">
<StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="false" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false" />
<QueryPlan CachedPlanSize="48" CompileTime="23" CompileCPU="6" CompileMemory="360">
<MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0" />
<OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="157286" EstimatedPagesCached="314572" EstimatedAvailableDegreeOfParallelism="16" />
<RelOp NodeId="0" PhysicalOp="Table Insert" LogicalOp="Insert" EstimateRows="246.492" EstimateIO="0.01" EstimateCPU="0.000246492" AvgRowSize="9" EstimatedTotalSubtreeCost="0.405134" Parallel="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row">
<OutputList />
<Update DMLRequestSort="0">
<Object Table="Object1" />
<SetPredicate>
<ScalarOperator ScalarString="ScalarString1">
<ScalarExpressionList>
<ScalarOperator>
<MultipleAssign>
<Assign>
<ColumnReference Table="Object1" Column="Column2" />
<ScalarOperator>
<Identifier>
<ColumnReference Database="Database1" Schema="Schema1" Table="Object2" Column="Column2" />
</Identifier>
</ScalarOperator>
</Assign>
</MultipleAssign>
</ScalarOperator>
</ScalarExpressionList>
</ScalarOperator>
</SetPredicate>
<RelOp NodeId="1" PhysicalOp="Index Seek" LogicalOp="Index Seek" EstimateRows="246.492" EstimateIO="0.22831" EstimateCPU="0.103001" AvgRowSize="15" EstimatedTotalSubtreeCost="0.331311" TableCardinality="1.03883e+006" Parallel="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row">
<OutputList>
<ColumnReference Database="Database1" Schema="Schema1" Table="Object2" Column="Column2" />
</OutputList>
<IndexScan Ordered="1" ScanDirection="FORWARD" ForcedIndex="0" ForceSeek="0" ForceScan="0" NoExpandHint="0" Storage="RowStore">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="Database1" Schema="Schema1" Table="Object2" Column="Column2" />
</DefinedValue>
</DefinedValues>
<Object Database="Database1" Schema="Schema1" Table="Object2" Index="Index1" IndexKind="NonClustered" />
<SeekPredicates>
<SeekPredicateNew>
<SeekKeys>
<StartRange ScanType="GE">
<RangeColumns>
<ColumnReference Database="Database1" Schema="Schema1" Table="Object2" Column="Column3" />
</RangeColumns>
<RangeExpressions>
<ScalarOperator ScalarString="ScalarString2">
<Identifier>
<ColumnReference Column="Column7" />
</Identifier>
</ScalarOperator>
</RangeExpressions>
</StartRange>
<EndRange ScanType="LE">
<RangeColumns>
<ColumnReference Database="Database1" Schema="Schema1" Table="Object2" Column="Column3" />
</RangeColumns>
<RangeExpressions>
<ScalarOperator ScalarString="ScalarString3">
<Identifier>
<ColumnReference Column="Column8" />
</Identifier>
</ScalarOperator>
</RangeExpressions>
</EndRange>
</SeekKeys>
</SeekPredicateNew>
</SeekPredicates>
<Predicate>
<ScalarOperator ScalarString="ScalarString4">
<Logical Operation="OR">
<ScalarOperator>
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="Database1" Schema="Schema1" Table="Object2" Column="Column4" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Identifier>
<ColumnReference Column="Column9" />
</Identifier>
</ScalarOperator>
</Compare>
</ScalarOperator>
<ScalarOperator>
<Identifier>
<ColumnReference Column="Column10">
<ScalarOperator>
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Column="Column9" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Const ConstValue="Value4" />
</ScalarOperator>
</Compare>
</ScalarOperator>
</ColumnReference>
</Identifier>
</ScalarOperator>
</Logical>
</ScalarOperator>
</Predicate>
</IndexScan>
</RelOp>
</Update>
</RelOp>
<ParameterList>
<ColumnReference Column="Column9" ParameterCompiledValue="Value1" />
</ParameterList>
</QueryPlan>
</StmtSimple>
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>
EDIT: Percebi que não postei uma pergunta bem formulada. Aqui está a pergunta:
Dado o plano de exemplo, qual fórmula ou cálculo o SSMS e o Plan Explorer usaram para chegar ao custo estimado do operador de 0,073823 para o nó 0?
A única maneira de responder adequadamente a essa pergunta é iniciar o depurador e ver quais escolhas foram feitas pelo otimizador ao longo do caminho. Os custos não são apenas IO e CPU. Existem custos adicionais associados a um determinado operador que são refletidos no custo total, mas não são refletidos nas estimativas de custo de IO e CPU. Você pode ler mais sobre alguns dos custos adicionais neste excelente artigo de Paul White .
Não tenho uma resposta precisa para sua pergunta (não tenho dúvidas, Paul teria). No entanto, estou disposto a dar um palpite. O que você está vendo é sobrecarga adicional para a operação conforme determinado pelo otimizador acima e além do que está exibindo como sobrecarga para IO e CPU conforme determinado pelas linhas estimadas, etc. Acredito que seja um cálculo baseado no que necessário em termos de IO para criar a tabela e armazenar as 246.492 linhas * 9b de dados em cada uma que é calculada como estando na instrução INSERT. 246,492 * 9/1024 = 2,1664 é menor que uma página de 8k. No entanto, temos que criar pelo menos uma página, portanto, quando você calcula 8 * o custo de 0,01, isso nos coloca um pouco acima do valor estimado de 0,073832. Esse é o meu palpite, e é um palpite. No entanto, sei que há sobrecarga nos custos que não é
Grant, acredito que um colega de trabalho (Dennis Rogers) e eu respondemos à pergunta. Aqui aparece a fórmula definitiva que o SSMS usa para calcular o custo da operadora e a % de custo.
Custo estimado do operador == @EstimatedTotalSubtreeCost - Sum(Immediate Children@EstimatedTotalSubtreeCost)
Porcentagem de custo estimado do operador = Custo estimado do operador / StmtSimple@StatementSubTreeCost * 100
Eu testei isso com vários planos e isso parece estar certo.
Para representar o cálculo acima como xpath, ele se transforma em:
A soma localiza o primeiro descendente que é do tipo RelOp, depois faz backup de um nível e obtém todos os RelOps naquele nível e extrai seu EstimatedTotalSubtreeCost.