Mengapa mereferensikan variabel dalam bergabung dengan predikat kekuatan loop bersarang?

16

Saya menemukan masalah ini baru - baru ini dan tidak dapat menemukan diskusi apa pun secara online.

Kueri di bawah ini

DECLARE @S VARCHAR(1) = '';

WITH T
     AS (SELECT name + @S AS name2,
                *
         FROM   master..spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2;

Selalu mendapat paket loop bersarang

masukkan deskripsi gambar di sini

Mencoba memaksa masalah dengan INNER HASH JOINatau INNER MERGE JOINpetunjuk menghasilkan kesalahan berikut.

Prosesor kueri tidak dapat menghasilkan rencana kueri karena petunjuk yang ditentukan dalam kueri ini. Kirim ulang kueri tanpa menentukan petunjuk apa pun dan tanpa menggunakan SET FORCEPLAN.

Saya menemukan solusi yang memungkinkan hash atau gabungan bergabung - membungkus variabel dalam agregat. Paket yang dihasilkan berbiaya lebih rendah secara signifikan (19,2025 vs 0,261987)

DECLARE @S2 VARCHAR(1) = '';

WITH T
     AS (SELECT name + (SELECT MAX(@S2)) AS name2,
                *
         FROM   spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2; 

masukkan deskripsi gambar di sini

Apa alasan perilaku ini? dan adakah solusi yang lebih baik daripada yang saya temukan? (yang mungkin tidak memerlukan cabang rencana eksekusi tambahan)

Martin Smith
sumber

Jawaban:

13

Saya sudah mencoba kueri Anda pada contoh SQL 2012 dan melacak bendera 4199 tampaknya untuk memperbaiki masalah. Dengan mengaktifkannya saya mendapatkan gabungan gabung dengan total biaya 0,24 dan tidak ada cabang tambahan.

Artikel KB khusus untuk masalah ini adalah Masalah kinerja terjadi ketika predikat gabungan dalam kueri Anda memiliki kolom referensi luar di SQL Server 2005 atau di SQL Server 2008

masukkan deskripsi gambar di sini

Agar lebih memenuhi syarat, TF 4199 memungkinkan semua perbaikan optimizer. Lihat tautan ini untuk informasi lebih lanjut. Mengaktifkan semuanya sekaligus dapat memiliki efek samping yang aneh, jadi jika Anda dapat menemukan perbaikan spesifik mungkin lebih baik untuk mengaktifkan perbaikan itu sendiri.

Anda dapat mengaktifkan tanda jejak pada basis per kueri menggunakan OPTION (QUERYTRACEON 4199);

Tom V - Tim Monica
sumber
0

Pertanyaan lama, tetapi melihat jawabannya bukan super definitif, saya pikir saya akan memposting solusi yang saya temukan. Tidak yakin mengapa pengoptimal kueri menolak keras HASH, tapi saya pikir itu tidak suka MERGEkarena tidak ada input yang diurutkan. Pada 2012/14,

DECLARE @S VARCHAR(1) = '';

    WITH T
        AS (SELECT TOP (2147483647)
                name + @S AS name2,
                *
            FROM   master..spt_values
            ORDER BY name + @S)
    SELECT *
    FROM   T T1
           INNER JOIN T T2
             ON T1.name2 = T2.name2;

menghasilkan rencana berikut:

masukkan deskripsi gambar di sini

Memaksa TOPdan ORDER BYdalam cte tampaknya memberikan pengoptimal pengetahuan yang cukup tentang dataset untuk melakukan MERGE JOIN.

VBlades
sumber