O que exatamente significa "No Join Predicate" significa no SQL Server?

23

O MSDN " Classe de Eventos de Predicado de Junta Ausente " diz que " indica que está sendo executada uma consulta que não tem predicado de junção ".

Infelizmente, porém, não parece tão fácil assim.

Por exemplo, situação muito simples:

create table #temp1(i int);
create table #temp2(i int);
Select * from #temp1, #temp2 option (recompile);

Não há dados nas tabelas, também não há aviso, embora obviamente não tenha predicado de associação.

Se eu der uma olhada na documentação do SQL Server 2005 (o mesmo link, apenas outra versão do servidor), há uma frase extra: " Este evento é produzido apenas se os dois lados da associação retornarem mais de uma linha " . perfeito sentido na situação anterior. Como não há dados, os dois lados retornam 0 linhas e nenhum aviso. Inserir linhas, receber aviso. OK legal.

Mas para a próxima situação confusa, insiro os mesmos valores nas duas tabelas:

Insert into #temp1 (i) values (1)
Insert into #temp1 (i) values (1)
Insert into #temp2 (i) values (1)
Insert into #temp2 (i) values (1)

E eu recebo:

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

Porque isto é assim?

Nota : alguns scripts que usei para detectar essas consultas incorretas no meu servidor.

  1. é claro, plano de execução de procedimentos
  2. rastreio de servidor padrão usado para localizar avisos

    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. cache do plano de execução, para encontrar esses planos com avisos (como este)

    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);
    
Jānis
fonte

Respostas:

17

Sua pergunta é semelhante a esta . Às vezes, o SQL Server pode remover um predicado de associação da consulta original.

No caso em que você vê um aviso de predicado de junção, o SQL Server detecta em tempo de compilação que a tabela de constantes possui apenas um valor distinto e esse valor é, 1então, reescreve a consulta como

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

Há um predicado na varredura de tabela da #tempseguinte maneira[tempdb].[dbo].[#temp1].[i] =(1)

O predicado de junção de on t1.i = t2.inão pode ser removido dessa maneira no tempo de compilação ao usar duas tabelas ou se a tabela de constantes contiver mais de um valor distinto.


Mais informações sobre este podem ser encontrados em Paul White 's Query Optimizer Deep Dive série.

Martin Smith
fonte