我知道出于性能原因应该避免它,但我试图展示它作为演示出现的情况,以确保它不会出现。
然而,我最终得到一个缺少索引的警告,但优化器选择不创建临时索引。
我正在使用的查询是
SELECT
z.a
FROM dbo.t5 AS z WITH(INDEX(0))
WHERE
EXISTS
(
SELECT y.a
FROM dbo.t4 AS y
WHERE y.a = z.a
)
OPTION (MAXDOP 1);
表模式是:
CREATE TABLE dbo.t4
(
a integer NULL,
b varchar(1000) NULL,
p varchar(100) NULL
);
CREATE TABLE dbo.t5
(
a integer NULL,
b varchar(1000) NULL
);
CREATE UNIQUE CLUSTERED INDEX c1
ON dbo.t5 (a);
两个表都有 10,000 行,您可以使用以下方法进行模拟:
UPDATE STATISTICS dbo.t4
WITH
ROWCOUNT = 10000,
PAGECOUNT = 1000;
UPDATE STATISTICS dbo.t5
WITH
ROWCOUNT = 10000,
PAGECOUNT = 1000;
查询计划为:
<?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.2218.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementCompId="1" StatementEstRows="5532.16" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" StatementSubTreeCost="0.407384" StatementText="select a from t5 z WITH(INDEX(0)) where exists (select a from t4 where a=z.a )" StatementType="SELECT" QueryHash="0x1B882FCEA34AEAF4" QueryPlanHash="0x1B276DC04B718F7C" 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 DegreeOfParallelism="1" MemoryGrant="2912" CachedPlanSize="32" CompileTime="10" CompileCPU="10" CompileMemory="296">
<MissingIndexes>
<MissingIndexGroup Impact="82.4536">
<MissingIndex Database="[planoper]" Schema="[dbo]" Table="[t4]">
<ColumnGroup Usage="EQUALITY">
<Column Name="[a]" ColumnId="1" />
</ColumnGroup>
</MissingIndex>
</MissingIndexGroup>
</MissingIndexes>
<MemoryGrantInfo SerialRequiredMemory="1024" SerialDesiredMemory="2912" RequiredMemory="1024" DesiredMemory="2912" RequestedMemory="2912" GrantWaitTime="0" GrantedMemory="2912" MaxUsedMemory="896" />
<OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="104846" EstimatedPagesCached="11834" EstimatedAvailableDegreeOfParallelism="2" />
<RelOp AvgRowSize="11" EstimateCPU="0.228447" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="5532.16" LogicalOp="Left Semi Join" NodeId="0" Parallel="false" PhysicalOp="Hash Match" EstimatedTotalSubtreeCost="0.407384">
<OutputList>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t5]" Alias="[z]" Column="a" />
</OutputList>
<MemoryFractions Input="1" Output="1" />
<RunTimeInformation>
<RunTimeCountersPerThread Thread="0" ActualRows="10000" ActualEndOfScans="1" ActualExecutions="1" />
</RunTimeInformation>
<Hash>
<DefinedValues />
<HashKeysBuild>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t5]" Alias="[z]" Column="a" />
</HashKeysBuild>
<HashKeysProbe>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t4]" Column="a" />
</HashKeysProbe>
<ProbeResidual>
<ScalarOperator ScalarString="[planoper].[dbo].[t4].[a]=[planoper].[dbo].[t5].[a] as [z].[a]">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t4]" Column="a" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Identifier>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t5]" Alias="[z]" Column="a" />
</Identifier>
</ScalarOperator>
</Compare>
</ScalarOperator>
</ProbeResidual>
<RelOp AvgRowSize="11" EstimateCPU="0.0110785" EstimateIO="0.0565368" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="10000" LogicalOp="Clustered Index Scan" NodeId="1" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.0676153" TableCardinality="10000">
<OutputList>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t5]" Alias="[z]" Column="a" />
</OutputList>
<RunTimeInformation>
<RunTimeCountersPerThread Thread="0" ActualRows="10000" ActualEndOfScans="1" ActualExecutions="1" />
</RunTimeInformation>
<IndexScan Ordered="false" ForcedIndex="true" ForceScan="false" NoExpandHint="false">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t5]" Alias="[z]" Column="a" />
</DefinedValue>
</DefinedValues>
<Object Database="[planoper]" Schema="[dbo]" Table="[t5]" Index="[c1]" Alias="[z]" IndexKind="Clustered" />
</IndexScan>
</RelOp>
<RelOp AvgRowSize="11" EstimateCPU="0.011157" EstimateIO="0.100162" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="10000" LogicalOp="Table Scan" NodeId="2" Parallel="false" PhysicalOp="Table Scan" EstimatedTotalSubtreeCost="0.111319" TableCardinality="10000">
<OutputList>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t4]" Column="a" />
</OutputList>
<RunTimeInformation>
<RunTimeCountersPerThread Thread="0" ActualRows="10000" ActualEndOfScans="1" ActualExecutions="1" />
</RunTimeInformation>
<TableScan Ordered="false" ForcedIndex="false" ForceScan="false" NoExpandHint="false">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[planoper]" Schema="[dbo]" Table="[t4]" Column="a" />
</DefinedValue>
</DefinedValues>
<Object Database="[planoper]" Schema="[dbo]" Table="[t4]" IndexKind="Heap" />
</TableScan>
</RelOp>
</Hash>
</RelOp>
</QueryPlan>
</StmtSimple>
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>
它甚至告诉我创建这个索引:
USE [planoper];
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[t4] ([a]);
让索引假脱机自然出现的一种方法是使用稍微不同的语法来表达需求:
这会产生一个执行计划,例如:
将等式重写为一对等价的不等式鼓励使用索引假脱机,尽管假脱机谓词并不完全是您所追求的,但语义最终是相同的。
另一种方法是滥用
TOP
:使用原始语法引入所需的索引假脱机并不容易;但是,这并不是说不可能。由于您只需要它来进行演示,并且不会在生产系统附近的任何地方使用它,因此我将向您展示另一种方式:
执行计划是:
索引假脱机谓词是所需的:
您将无法在
USE PLAN
提示中使用此计划,因为优化器通常不会考虑它。进一步阅读: