SQL Server删除操作期间的意外执行计划

时间:2018-04-01 01:17:44

标签: sql-server performance

我收到了如下查询:

DELETE FROM tbl_Object 
WHERE ID = 3265;

当我运行此查询时,它非常慢并且呈现一个奇怪的执行计划。 两个表之间的密钥没有级联。

有没有人有任何想法为什么会这么慢以及如何加快它?

这是执行计划:

Weird execution plan

详情如下。

<?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="12.0.4213.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
<BatchSequence>
    <Batch>
    <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="1" StatementId="1" StatementOptmLevel="TRIVIAL" CardinalityEstimationModelVersion="70" StatementSubTreeCost="0.0302709" StatementText="DELETE FROM FDN_AlertObject WHERE ID = 3265" StatementType="DELETE" ParameterizedText="(@1 smallint)DELETE [FDN_AlertObject]  WHERE [ID]=@1" QueryHash="0x5F72C08D4BF22BF4" QueryPlanHash="0x16D4813B4F8FB73E" RetrievedFromCache="false">
        <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
        <QueryPlan CachedPlanSize="32" CompileTime="2" CompileCPU="2" CompileMemory="248">
            <MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0" />
            <OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="223696" EstimatedPagesCached="209715" EstimatedAvailableDegreeOfParallelism="4" />
            <RelOp AvgRowSize="9" EstimateCPU="1.8E-07" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Assert" NodeId="1" Parallel="false" PhysicalOp="Assert" EstimatedTotalSubtreeCost="0.0302709">
            <OutputList />
            <Assert StartupExpression="false">
                <RelOp AvgRowSize="9" EstimateCPU="4.18E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Left Semi Join" NodeId="2" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0302707">
                <OutputList>
                    <ColumnReference Column="Expr1008" />
                    <ColumnReference Column="Expr1009" />
                </OutputList>
                <NestedLoops Optimized="false">
                    <DefinedValues>
                    <DefinedValue>
                        <ColumnReference Column="Expr1009" />
                    </DefinedValue>
                    </DefinedValues>
                    <OuterReferences>
                    <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Column="ID" />
                    </OuterReferences>
                    <ProbeColumn>
                    <ColumnReference Column="Expr1009" />
                    </ProbeColumn>
                    <RelOp AvgRowSize="16" EstimateCPU="4.18E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Left Semi Join" NodeId="3" Parallel="false" PhysicalOp="Nested Loops" EstimatedTotalSubtreeCost="0.0267779">
                    <OutputList>
                        <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Column="ID" />
                        <ColumnReference Column="Expr1008" />
                    </OutputList>
                    <NestedLoops Optimized="false">
                        <DefinedValues>
                        <DefinedValue>
                            <ColumnReference Column="Expr1008" />
                        </DefinedValue>
                        </DefinedValues>
                        <OuterReferences>
                        <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Column="ID" />
                        </OuterReferences>
                        <ProbeColumn>
                        <ColumnReference Column="Expr1008" />
                        </ProbeColumn>
                        <RelOp AvgRowSize="15" EstimateCPU="2E-06" EstimateIO="0.02" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Delete" NodeId="4" Parallel="false" PhysicalOp="Clustered Index Delete" EstimatedTotalSubtreeCost="0.0232851">
                        <OutputList>
                            <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Column="ID" />
                        </OutputList>
                        <SimpleUpdate DMLRequestSort="false">
                            <Object Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Index="[PK__FDN_ALER__3214EC2790A10D93]" IndexKind="Clustered" Storage="RowStore" />
                            <Object Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Index="[INDEX_ALERT_OBJECT_KEYS]" IndexKind="NonClustered" Storage="RowStore" />
                            <SeekPredicateNew>
                            <SeekKeys>
                                <Prefix ScanType="EQ">
                                <RangeColumns>
                                    <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Column="ID" />
                                </RangeColumns>
                                <RangeExpressions>
                                    <ScalarOperator ScalarString="CONVERT_IMPLICIT(bigint,[@1],0)">
                                    <Convert DataType="bigint" Style="0" Implicit="true">
                                        <ScalarOperator>
                                        <Identifier>
                                            <ColumnReference Column="@1" />
                                        </Identifier>
                                        </ScalarOperator>
                                    </Convert>
                                    </ScalarOperator>
                                </RangeExpressions>
                                </Prefix>
                            </SeekKeys>
                            </SeekPredicateNew>
                        </SimpleUpdate>
                        </RelOp>
                        <RelOp AvgRowSize="15" EstimateCPU="11.7081" EstimateIO="25.3253" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Clustered Index Scan" NodeId="5" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.00347834" TableCardinality="10643600">
                        <OutputList />
                        <IndexScan Ordered="false" ForcedIndex="true" ForceScan="false" NoExpandHint="false" Storage="RowStore">
                            <DefinedValues />
                            <Object Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERT]" Index="[PK__FDN_ALER__3214EC273DF32C1B]" IndexKind="Clustered" Storage="RowStore" />
                            <Predicate>
                            <ScalarOperator ScalarString="[my_DB].[dbo].[FDN_ALERT].[OBJECT_ID]=[my_DB].[dbo].[FDN_ALERTOBJECT].[ID]">
                                <Compare CompareOp="EQ">
                                <ScalarOperator>
                                    <Identifier>
                                    <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERT]" Column="OBJECT_ID" />
                                    </Identifier>
                                </ScalarOperator>
                                <ScalarOperator>
                                    <Identifier>
                                    <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Column="ID" />
                                    </Identifier>
                                </ScalarOperator>
                                </Compare>
                            </ScalarOperator>
                            </Predicate>
                        </IndexScan>
                        </RelOp>
                    </NestedLoops>
                    </RelOp>
                    <RelOp AvgRowSize="15" EstimateCPU="11.7081" EstimateIO="25.3253" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Clustered Index Scan" NodeId="6" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.00347834" TableCardinality="10643600">
                    <OutputList />
                    <IndexScan Ordered="false" ForcedIndex="true" ForceScan="false" NoExpandHint="false" Storage="RowStore">
                        <DefinedValues />
                        <Object Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERT]" Index="[PK__FDN_ALER__3214EC273DF32C1B]" IndexKind="Clustered" Storage="RowStore" />
                        <Predicate>
                        <ScalarOperator ScalarString="[my_DB].[dbo].[FDN_ALERT].[PLACE_ID]=[my_DB].[dbo].[FDN_ALERTOBJECT].[ID]">
                            <Compare CompareOp="EQ">
                            <ScalarOperator>
                                <Identifier>
                                <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERT]" Column="PLACE_ID" />
                                </Identifier>
                            </ScalarOperator>
                            <ScalarOperator>
                                <Identifier>
                                <ColumnReference Database="[my_DB]" Schema="[dbo]" Table="[FDN_ALERTOBJECT]" Column="ID" />
                                </Identifier>
                            </ScalarOperator>
                            </Compare>
                        </ScalarOperator>
                        </Predicate>
                    </IndexScan>
                    </RelOp>
                </NestedLoops>
                </RelOp>
                <Predicate>
                <ScalarOperator ScalarString="CASE WHEN NOT [Expr1008] IS NULL THEN (0) ELSE CASE WHEN NOT [Expr1009] IS NULL THEN (1) ELSE NULL END END">
                    <IF>
                    <Condition>
                        <ScalarOperator>
                        <Logical Operation="NOT">
                            <ScalarOperator>
                            <Logical Operation="IS NULL">
                                <ScalarOperator>
                                <Identifier>
                                    <ColumnReference Column="Expr1008" />
                                </Identifier>
                                </ScalarOperator>
                            </Logical>
                            </ScalarOperator>
                        </Logical>
                        </ScalarOperator>
                    </Condition>
                    <Then>
                        <ScalarOperator>
                        <Const ConstValue="(0)" />
                        </ScalarOperator>
                    </Then>
                    <Else>
                        <ScalarOperator>
                        <IF>
                            <Condition>
                            <ScalarOperator>
                                <Logical Operation="NOT">
                                <ScalarOperator>
                                    <Logical Operation="IS NULL">
                                    <ScalarOperator>
                                        <Identifier>
                                        <ColumnReference Column="Expr1009" />
                                        </Identifier>
                                    </ScalarOperator>
                                    </Logical>
                                </ScalarOperator>
                                </Logical>
                            </ScalarOperator>
                            </Condition>
                            <Then>
                            <ScalarOperator>
                                <Const ConstValue="(1)" />
                            </ScalarOperator>
                            </Then>
                            <Else>
                            <ScalarOperator>
                                <Const ConstValue="NULL" />
                            </ScalarOperator>
                            </Else>
                        </IF>
                        </ScalarOperator>
                    </Else>
                    </IF>
                </ScalarOperator>
                </Predicate>
            </Assert>
            </RelOp>
            <ParameterList>
            <ColumnReference Column="@1" ParameterCompiledValue="(3266)" />
            </ParameterList>
        </QueryPlan>
        </StmtSimple>
    </Statements>
    </Batch>
</BatchSequence>
</ShowPlanXML>

有人可以帮我理解原因吗?

谢谢。

1 个答案:

答案 0 :(得分:2)

更复杂计划的原因

您有FDN_ALERTOBJECT的外键引用。因此,当您从FDN_ALERTOBJECT删除任何行时,服务器需要确保您不会违反这些限制。

E.g。它必须同时检查FDN_ALERT.OBJECT_IDFDN_ALERT.PLACE_ID,以确保它没有引用您要删除的FDN_ALERTOBJECT.ID

表现不佳的原因

我在FDN_ALERT.OBJECT_IDFDN_ALERT.PLACE_ID上看不到任何索引。这意味着在从FDN_ALERTOBJECT删除任何行之前检查约束,除了需要任何其他处理之外,还需要至少2个FDN_ALERT表的表扫描。

提高性能

创建缺少的索引。请注意,SQL Server Management Studio具有内置工具来推荐缺少的索引。如果你曾经使用它,它应该建议下面的索引(可能还有其他)。

create index ixfk_Alert_ObjectId on FDN_ALERT (OBJECT_ID)
create index ixfk_Alert_PlaceId on FDN_ALERT (PLACE_ID)

SQL Server将为FDN_ALERT的每次插入/更新更新这些索引,但性能影响很小。但是,从FDN_ALERTOBJECT删除它们会有很大改进。