Що саме означає “No Join Predicate” у 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);

Відповіді:


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 White «s оптимізатор запитів Deep Dive серії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.