¿Qué significa exactamente "Sin predicado de unión" en SQL Server?

23

MSDN " Clase de evento de predicado de unión faltante " dice que " indica que se está ejecutando una consulta que no tiene predicado de unión ".

Pero desafortunadamente no parece ser tan fácil como eso.

Por ejemplo, situación muy simple:

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

No hay datos en las tablas, tampoco hay advertencia, aunque obviamente no tiene un predicado de unión.

Si analizo la documentación de SQL Server 2005 (el mismo enlace, solo otra versión del servidor), hay una oración adicional: " Este evento se produce solo si ambos lados de la unión devuelven más de una fila " . sentido perfecto en la situación anterior. No hay datos, por lo que ambos lados devuelven 0 filas y no hay advertencia. Insertar filas, obtener advertencia. Está bien.

Pero para la siguiente situación confusa, inserto los mismos valores en ambas tablas:

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

Y obtengo:

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

¿Por qué esto es tan?

Nota : algunas secuencias de comandos que utilicé para detectar estas consultas incorrectas en mi servidor.

  1. por supuesto, plan de ejecucion de procedimientos
  2. utiliza el rastreo predeterminado del servidor para buscar advertencias

    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. caché del plan de ejecución, para encontrar esos planes con advertencias (como esta)

    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
fuente

Respuestas:

17

Tu pregunta es similar a esta . A veces, SQL Server puede eliminar un predicado de unión de la consulta original.

En el caso de que vea una advertencia de predicado de unión, SQL Server detecta en tiempo de compilación que la tabla de constantes solo tiene un valor distinto y ese valor se 1reescribe la consulta como

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

Hay un predicado en la exploración de tabla de la #tempsiguiente manera[tempdb].[dbo].[#temp1].[i] =(1)

El predicado de unión de on t1.i = t2.ino se puede eliminar de esta manera en tiempo de compilación cuando se usan dos tablas o si la tabla de constantes contiene más de un valor distinto.


Más información sobre esto se puede encontrar en Paul White 's optimizador de consultas del buceo de profundidad serie.

Martin Smith
fuente