“ 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ไม่สามารถลบด้วยวิธีนี้ในเวลารวบรวมเมื่อใช้สองตารางหรือถ้าตารางค่าคงที่มีค่าที่แตกต่างกันมากกว่าหนึ่งค่า


ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้สามารถพบได้ในพอลไวท์ 's เพิ่มประสิทธิภาพการค้นหาดำน้ำลึกชุด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.