Kinerja indeks pada ON versus WHERE

26

Saya punya dua meja

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Tabel ini memiliki indeks non-clustered pada (Id, Tanggal)

Dan saya bergabung dengan tabel ini

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
WHERE 
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Ini juga dapat ditulis sebagai

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
    AND
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Pertanyaan saya adalah, manakah dari dua pertanyaan ini yang memberikan kinerja lebih baik dan mengapa? Atau apakah mereka setara?

Erik Bergstedt
sumber
1
Apakah Anda benar-benar memiliki tabel @ variabel dengan indeks non-cluster yang mencakup semua bidang, dan tidak ada indeks cluster? atau hanya penyederhanaan?
Remus Rusanu
1
Ini penyederhanaan ekstrem
Erik Bergstedt
1
Terkait: Apakah gabungan dioptimalkan ke klausa tempat saat runtime?
Paul White mengatakan GoFundMonica

Jawaban:

32

Performanya akan sama. Pengoptimal akan mengenali ini dan membuat rencana yang sama.

Di sisi lain saya tidak akan mengatakan mereka setara. Bentuk pertama dalam pertanyaan jauh lebih mudah dibaca dan secara umum diharapkan.

Sebagai contoh menggunakan beberapa tabel yang saya miliki Anda dapat melihat rencana eksekusi persis sama tidak peduli bagaimana saya menulis permintaan.

Anda harus dapat menentukan rencana kueri untuk tabel dan kumpulan data Anda sendiri sehingga Anda dapat melihat apa yang terjadi dalam situasi Anda.

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

Berikan rencana eksekusi ini

masukkan deskripsi gambar di sini

Tom V - Tim Monica
sumber
Saya setuju, bentuk pertama lebih mudah dibaca, dan dengan demikian saya lega bahwa mereka setara. Saya hanya akan menggunakan formulir ini di masa depan.
Erik Bergstedt
@ErikBergstedt Saya telah mengedit jawaban saya, Anda harus dapat memverifikasi ini untuk dataset Anda sendiri dan struktur tabel dengan cukup mudah ketika Anda melihat rencana eksekusi
Tom V - Team Monica
Ya saya lakukan. Terima kasih. Saya hanya mencari pendapat ke-2 karena saya tidak menemukan jawaban yang ada.
Erik Bergstedt
Catatan: HANYA sama jika itu adalah INNER JOIN. Jika Anda memasukkan OUTER JOINmaka mereka jelas tidak sama.
Kenneth Fisher
22

Mereka identik secara semantik dan pengoptimal seharusnya tidak kesulitan mengenali fakta ini dan menghasilkan rencana yang identik.

Saya cenderung untuk menempatkan kondisi referensi kedua tabel di ONdan kondisi referensi hanya satu tabel di tabel WHERE.

Untuk OUTER JOINSmemindahkan kondisi dapat mempengaruhi semantik.

Martin Smith
sumber
7

Dalam kasus sederhana, itu akan sama. Namun, saya telah melihat pertanyaan yang sangat kompleks dengan beberapa bergabung memiliki rencana yang sangat berbeda. Yang baru-baru ini saya kerjakan dimulai dengan sebuah tabel yang memiliki hampir 6 juta baris bergabung dengan sekitar 20 tabel yang berbeda. Hanya gabungan pertama ke tabel ini yang merupakan gabungan internal , semua yang lain merupakan gabungan luar. Filter di mana klausa parameter sesuatu seperti ini:

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

Filter ini digunakan kemudian dalam paket alih-alih sebelumnya. Ketika saya memindahkan kondisi ini ke gabung bagian dalam pertama, rencananya berubah secara dramatis ketika filter diterapkan sejak awal dalam rencana untuk membatasi set hasil dan CPU saya dan waktu yang berlalu turun sekitar 310%. Jadi, seperti banyak pertanyaan SQL Server, itu tergantung.

Jared Karney
sumber
2
Bisakah Anda menambahkan lebih banyak detail - mungkin screenshot dari diagram rencana eksekusi - karena jawaban Anda tampaknya bertentangan dengan yang lainnya?
Kenny Evitt
2
Apakah paket tersebut menunjukkan batas waktu pengoptimal?
Martin Smith
Bagaimana mungkin CPU memuat lebih dari 100%?
Michael Green
2

Secara umum, tempat Anda meletakkan filter membuat perbedaan.
Sementara Tom V mengatakan Pengoptimal akan mengenali bahwa kueri itu sama dan menghasilkan rencana yang sama, itu tidak selalu benar. Tergantung pada versi SQL yang Anda gunakan, seberapa kompleks kueri Anda, dan seberapa penting untuk keseluruhan kumpulan yang ditentukan oleh Pengoptimal.

Pengoptimal dapat memutuskan bahwa bagian dari kumpulan ini tidak layak menghabiskan cukup waktu untuk memungkinkannya menghasilkan rencana terbaik. Secara umum Anda akan mendapatkan kinerja yang lebih baik jika Anda meletakkan kondisi yang mengurangi jumlah data yang perlu dikerjakan dalam klausa ON alih-alih klausa WHERE (jika mungkin, karena melakukan ini dengan sambungan luar akan menghasilkan produk Cartesian .)

Ini sedikit lebih mudah untuk Pengembang SQL sesekali untuk melihat filter di klausa WHERE, tapi saya telah bekerja pada beberapa tabel besar di mana memiliki filter di klausa ON memangkas jam dari run time.

Jadi, jika klausa memiliki potensi untuk secara drastis mengurangi jumlah baris kueri akan dibaca, saya akan selalu memasukkannya dalam klausa ON untuk membantu Pengoptimal memilih rencana yang lebih baik.

Tom Evers
sumber
1

Dalam keadaan biasa, kondisi filter dapat ditentukan dalam klausa WHERE atau JOIN. Saya cenderung menempatkan filter di bawah DI MANA kecuali jika prioritas OUTER JOIN dapat terpengaruh (lihat di bawah) atau jika filter tersebut sangat spesifik untuk tabel itu (mis. TYPE = 12 untuk menentukan subset spesifik dari baris dalam tabel).

Di sisi lain, klausa ON dan WHERE dapat digunakan untuk menentukan kondisi gabungan (sebagai lawan dari kondisi filter). Selama Anda hanya menggunakan INNER bergabung, itu masih tidak masalah yang Anda gunakan dalam keadaan biasa.

Jika Anda menggunakan OUTER bergabung, bagaimanapun, itu bisa membuat banyak perbedaan. Jika, misalnya, Anda menentukan GABUNGAN LUAR antara dua tabel (t1 dan t2) tetapi kemudian, dalam klausa WHERE, lanjutkan untuk menentukan hubungan eqijoin antara tabel (misalnya t1.col = t2.col), Anda baru saja dikonversi menjadi OUTER join menjadi INNER join! Ini karena WHERE dapat digunakan untuk menentukan equijoin (atau mungkin bahkan OUTER bergabung, tergantung pada versinya, menggunakan sintaks yang sudah usang * =) tanpa menggunakan klausa ON, dan ketika WHERE menunjukkan equijoin bagian dalam di antara tabel, itu menimpa OUTER GABUNG (jika ada).

Pertanyaan aslinya adalah tentang filter, di mana jenis gabung sering kali tidak boleh menjadi masalah, tetapi gabung juga dapat bertindak sebagai filter dan dalam situasi tersebut penempatan kondisi gabung tentu saja bisa berarti.

McB2K3
sumber
-1

Dengan INNER JOINs, ini adalah masalah gaya.

Namun, itu menjadi jauh lebih menarik dengan GABUNGAN LUAR. Anda harus menjelajahi perbedaan antara kueri dengan GABUNGAN LUAR dan kondisi di kedua klausa ON dan klausa WHERE. Hasil-set tidak selalu sama. Apakah, misalnya,

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

sama seperti

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL
Sean Redmond
sumber
8
Jika hasilnya berbeda (yang tentu saja), apa gunanya membandingkan kinerja?
ypercubeᵀᴹ