Che cosa significa esattamente "Nessun join predicato" in SQL Server?


23

MSDN " Classe evento predicato join mancante " afferma che " indica che è in esecuzione una query che non ha predicato di join ".

Ma sfortunatamente non sembra essere così facile.

Ad esempio, situazione molto semplice:

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

Non ci sono dati nelle tabelle, né avvisi, anche se ovviamente non ha predicato di join.

Se do un'occhiata alla documentazione di SQL Server 2005 (lo stesso collegamento, solo un'altra versione del server), c'è una frase in più: " Questo evento viene prodotto solo se entrambi i lati del join restituiscono più di una riga " . senso perfetto nella situazione precedente. Non ci sono dati, quindi entrambe le parti restituiscono 0 righe e nessun avviso. Inserisci righe, ricevi avviso. Ok bello.

Ma per la prossima situazione confusa, inserisco gli stessi valori in entrambe le tabelle:

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 ottengo:

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

Perché è così?

Nota : alcuni script che ho usato per rilevare queste cattive query sul mio server.

  1. ovviamente, piano di esecuzione delle procedure
  2. utilizzato la traccia del server predefinito per trovare gli avvisi

    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 del piano di esecuzione, per trovare quei piani con avvisi (come questo)

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

Risposte:


17

La tua domanda è simile a questa . A volte SQL Server può rimuovere un predicato di join dalla query originale.

Nel caso in cui venga visualizzato un avviso di predicato di join, SQL Server rileva in fase di compilazione che la tabella delle costanti ha solo un valore distinto e che tale valore 1riscrive la query come

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

Esiste un predicato sull'analisi della tabella #tempcome segue[tempdb].[dbo].[#temp1].[i] =(1)

Il predicato di join di on t1.i = t2.inon può essere rimosso in questo modo al momento della compilazione quando si utilizzano due tabelle o se la tabella delle costanti contiene più di un valore distinto.


Maggiori informazioni su questo può essere trovato in Paul White 's Query Optimizer Deep Dive serie.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.