我收到了如下查询:
DELETE FROM tbl_Object
WHERE ID = 3265;
当我运行此查询时,它非常慢并且呈现一个奇怪的执行计划。 两个表之间的密钥没有级联。
有没有人有任何想法为什么会这么慢以及如何加快它?
这是执行计划:
详情如下。
<?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>
有人可以帮我理解原因吗?
谢谢。
答案 0 :(得分:2)
您有FDN_ALERTOBJECT
的外键引用。因此,当您从FDN_ALERTOBJECT
删除任何行时,服务器需要确保您不会违反这些限制。
E.g。它必须同时检查FDN_ALERT.OBJECT_ID
和FDN_ALERT.PLACE_ID
,以确保它没有引用您要删除的FDN_ALERTOBJECT.ID
。
我在FDN_ALERT.OBJECT_ID
和FDN_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
删除它们会有很大改进。