在SQL Server中“无联接谓词”到底是什么意思?


23

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)

为什么会这样呢?

注意:我用来检测服务器上这些错误查询的一些脚本。

  1. 当然,程序的执行计划
  2. 使用默认服务器跟踪来查找警告

    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
  3. 执行计划缓存,以查找带有警告的计划(如此)

    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);

Answers:


17

您的问题与类似。有时,SQL Server可以从原始查询中删除联接谓词。

在看到连接谓词警告的情况下,SQL Server在编译时检测到常量表仅具有一个不同的值,并且该值1如此将查询重写为

SELECT *
FROM   (SELECT *
        FROM   #temp1 t1
        WHERE  t1.i = 1) t1
       CROSS JOIN (SELECT 1 i
                   UNION ALL
                   SELECT 1) t2 

在表扫描上有一个谓词#temp如下[tempdb].[dbo].[#temp1].[i] =(1)

on t1.i = t2.i当使用两个表或常量表包含多个不同值时,无法在编译时以这种方式删除连接谓词。


有关此问题的更多信息,请参阅Paul WhiteQuery Optimizer Deep Dive系列。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.