MSDN " Missing Join Predicate Event Class " diz que " indica que uma consulta está sendo executada sem nenhum predicado de junção ".
Mas infelizmente não parece ser 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 junçã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 ambos os lados da junção retornarem mais de uma linha. " perfeito sentido na situação anterior. Não há dados, então ambos os lados retornam 0 linhas e nenhum aviso. Insira linhas, receba um 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 ruins no meu servidor.
- claro, plano de execução de procedimentos
usou o rastreamento de servidor padrão para encontrar 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
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);
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 tem apenas um valor distinto e esse valor
1
reescreve a consulta comoExiste um predicado na varredura de tabela da
#temp
seguinte forma[tempdb].[dbo].[#temp1].[i] =(1)
O predicado de junção de
on t1.i = t2.i
não pode ser removido dessa maneira em tempo de compilação ao usar duas tabelas ou se a tabela de constantes contiver mais de um valor distinto.Mais informações sobre isso podem ser encontradas na série Query Optimizer Deep Dive de Paul White .