MSDN " Missing Join Predicate Event Class "はそれを "は、結合述語がないクエリが実行されていることを示します"と示しています。
しかし、残念ながらそれはそれほど簡単ではないようです。
たとえば、非常に単純な状況:
create table #temp1(i int);
create table #temp2(i int);
Select * from #temp1, #temp2 option (recompile);
テーブルにはデータがなく、警告もありませんが、結合述語はありません。
SQL Server 2005のドキュメント(同じリンク、他のサーバーバージョンのみ)を見ると、「このイベントは、結合の両側がより多くを返す場合にのみ生成されます1行。 "これは、前の状況では完全に理にかなっています。データがないため、どちらの側も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)
なぜそうなのですか?
注:サーバーでこれらの不正なクエリを検出するために使用したいくつかのスクリプト。
警告を見つけるためにデフォルトのサーバートレースを使用しました
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
実行プランのキャッシュ、警告のあるプランを見つける(このような)
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);
あなたの質問は これ に似ています。 SQL Serverは、元のクエリから結合述語を削除できる場合があります。
結合述語の警告が表示された場合、SQL Serverはコンパイル時に定数のテーブルに1つの異なる値しかなく、その値が_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
_の結合述語は、2つのテーブルを使用する場合、または定数のテーブルに複数の異なる値が含まれている場合、コンパイル時にこの方法で削除できません。
この詳細については、 Paul White の Query Optimizer Deep Dive シリーズを参照してください。