MSDN“缺少连接谓词事件类”说它“表示正在执行一个没有连接谓词的查询”。
但不幸的是,这似乎并不那么容易。
比如很简单的情况:
create table #temp1(i int);
create table #temp2(i int);
Select * from #temp1, #temp2 option (recompile);
表中没有数据,也没有警告,尽管它显然没有连接谓词。
如果我看一下 SQL Server 2005 的文档(相同的链接,只是其他服务器版本),有一个额外的句子:“只有当连接的双方返回多行时才会产生这个事件。 ”这将使在以前的情况下完美的感觉。没有数据,所以双方都返回0行并且没有警告。插入行,得到警告。嗯不错。
但是对于下一个令人困惑的情况,我在两个表中插入了相同的值:
Insert into #temp1 (i) values (1)
Insert into #temp1 (i) values (1)
Insert into #temp2 (i) values (1)
Insert into #temp2 (i) values (1)
我得到:
-- no warning:
Select * from #temp1 t1
inner join #temp2 t2 on t1.i = t2.i
option (recompile)
-- has warning:
Select * from #temp1 t1
inner join (select 1 i union all select 1) t2 on t1.i = t2.i
option (recompile)
为什么会这样?
注意:我用来在我的服务器上检测这些错误查询的一些脚本。
- 当然,程序的执行计划
使用默认服务器跟踪来查找警告
Declare @trace nvarchar(500); Select @trace = cast(value as nvarchar(500)) From sys.fn_trace_getinfo(Null) Where traceid = 1 and property = 2; Select t.StartTime, te.name, * From sys.fn_trace_gettable(@trace, 1) t Inner join sys.trace_events te on t.EventClass = te.trace_event_id where EventClass = 80 order by t.StartTime desc
执行计划缓存,找到那些带有警告的计划(比如这个)
WITH XMLNAMESPACES (default 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') SELECT Cast('<?SQL ' + st.text + ' ?>' as xml) sql_text, pl.query_plan, ps.execution_count, ps.last_execution_time, ps.last_elapsed_time, ps.last_logical_reads, ps.last_logical_writes FROM sys.dm_exec_query_stats ps with (NOLOCK) Cross Apply sys.dm_exec_sql_text(ps.sql_handle) st Cross Apply sys.dm_exec_query_plan(ps.plan_handle) pl WHERE pl.query_plan.value('(//Warnings/@NoJoinPredicate)[1]', 'bit') = 1 Order By last_execution_time desc OPTION (RECOMPILE);
您的问题与此类似。有时 SQL Server 可以从原始查询中删除连接谓词。
在您看到连接谓词警告的情况下,SQL Server 在编译时检测到常量表只有一个不同的值,并且该值
1
将查询重写为表扫描上有一个谓词
#temp
如下[tempdb].[dbo].[#temp1].[i] =(1)
on t1.i = t2.i
当使用两个表或常量表包含多个不同的值时,无法在编译时以这种方式删除连接谓词。有关这方面的更多信息,请参阅Paul White的Query Optimizer Deep Dive系列。