Itu tergantung pada data di tabel Anda, indeks Anda, .... Sulit dikatakan tanpa bisa membandingkan rencana eksekusi / statistik waktu + io +.
Perbedaan yang saya harapkan adalah pemfilteran ekstra terjadi sebelum GABUNG di antara dua tabel. Dalam contoh saya, saya mengubah pembaruan untuk memilih untuk menggunakan kembali tabel saya.
Rencana eksekusi dengan "optimasi"
Rencana eksekusi
Anda dengan jelas melihat operasi filter terjadi, dalam data pengujian saya tidak ada catatan di mana disaring dan akibatnya tidak ada perbaikan di mana dilakukan.
Rencana eksekusi, tanpa "optimasi"
Rencana eksekusi
Filter hilang, yang berarti bahwa kita harus bergantung pada gabungan untuk menyaring catatan yang tidak dibutuhkan.
Alasan
lain Alasan / konsekuensi lain dari mengubah kueri bisa jadi, bahwa rencana eksekusi baru dibuat ketika mengubah kueri, yang kebetulan lebih cepat. Contoh dari ini adalah mesin memilih operator Bergabung yang berbeda, tetapi itu hanya menebak pada titik ini.
EDIT:
Klarifikasi setelah mendapatkan dua paket permintaan:
Permintaan membaca 550M Baris dari tabel besar, dan menyaringnya.
Berarti predikat adalah yang melakukan sebagian besar penyaringan, bukan predikat pencarian. Menghasilkan data yang sedang dibaca, tetapi tidak terlalu dikembalikan.
Membuat sql server menggunakan indeks yang berbeda (rencana kueri) / menambahkan indeks bisa menyelesaikannya.
Jadi mengapa kueri pengoptimalan tidak memiliki masalah yang sama?
Karena rencana kueri yang berbeda digunakan, dengan pemindaian alih-alih pencarian.
Tanpa melakukan apa pun, tetapi hanya mengembalikan 4M baris untuk bekerja dengannya.
Perbedaan selanjutnya
Mengabaikan perbedaan pembaruan (tidak ada yang diperbarui pada kueri yang dioptimalkan) kecocokan hash digunakan pada kueri yang dioptimalkan:
Alih-alih loop bersarang bergabung pada yang tidak dioptimalkan:
Nested loop adalah yang terbaik ketika satu meja kecil dan yang lainnya besar. Karena keduanya dekat dengan ukuran yang sama, saya berpendapat bahwa pertandingan hash adalah pilihan yang lebih baik dalam kasus ini.
Gambaran
Kueri yang dioptimalkan
Paket kueri yang dioptimalkan memiliki parallellism, menggunakan gabungan hash, dan perlu melakukan lebih sedikit penyaringan IO residual. Itu juga menggunakan bitmap untuk menghilangkan nilai-nilai kunci yang tidak bisa menghasilkan baris gabungan apa pun. (Juga tidak ada yang diperbarui)
Kueri yang tidak dioptimalkan
Rencana kueri yang tidak Dioptimalkan tidak memiliki parallellism, menggunakan gabungan loop bersarang, dan perlu melakukan penyaringan IO residual pada catatan 550M. (Juga pembaruan sedang terjadi)
Apa yang dapat Anda lakukan untuk meningkatkan kueri yang tidak dioptimalkan?
Mengubah indeks untuk memiliki first_name & last_name dalam daftar kolom kunci:
CREATE INDEX IX_largeTableOfPeople_birth_date_first_name_last_name di dbo.largeTableOfPeople (birth_date, first_name, last_name) termasuk (id)
Tetapi karena penggunaan fungsi dan tabel ini menjadi besar ini mungkin bukan solusi yang optimal.
- Memperbarui statistik, menggunakan kompilasi ulang untuk mencoba dan mendapatkan rencana yang lebih baik.
- Menambahkan OPSI
(HASH JOIN, MERGE JOIN)
ke kueri
- ...
Data uji + Pertanyaan yang digunakan
CREATE TABLE #smallTableOfPeople(importantValue int, birthDate datetime2, first_name varchar(50),last_name varchar(50));
CREATE TABLE #largeTableOfPeople(importantValue int, birth_date datetime2, first_name varchar(50),last_name varchar(50));
set nocount on;
DECLARE @i int = 1
WHILE @i <= 1000
BEGIN
insert into #smallTableOfPeople (importantValue,birthDate,first_name,last_name)
VALUES(NULL, dateadd(mi,@i,'2018-01-18 11:05:29.067'),'Frodo','Baggins');
set @i += 1;
END
set nocount on;
DECLARE @j int = 1
WHILE @j <= 20000
BEGIN
insert into #largeTableOfPeople (importantValue,birth_Date,first_name,last_name)
VALUES(@j, dateadd(mi,@j,'2018-01-18 11:05:29.067'),'Frodo','Baggins');
set @j += 1;
END
SET STATISTICS IO, TIME ON;
SELECT smallTbl.importantValue , largeTbl.importantValue
FROM #smallTableOfPeople smallTbl
JOIN #largeTableOfPeople largeTbl
ON largeTbl.birth_date = smallTbl.birthDate
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.last_name)),RTRIM(LTRIM(largeTbl.last_name))) = 4
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.first_name)),RTRIM(LTRIM(largeTbl.first_name))) = 4
WHERE smallTbl.importantValue IS NULL
-- The following line is "the optimization"
AND LEFT(RTRIM(LTRIM(largeTbl.last_name)), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å');
SELECT smallTbl.importantValue , largeTbl.importantValue
FROM #smallTableOfPeople smallTbl
JOIN #largeTableOfPeople largeTbl
ON largeTbl.birth_date = smallTbl.birthDate
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.last_name)),RTRIM(LTRIM(largeTbl.last_name))) = 4
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.first_name)),RTRIM(LTRIM(largeTbl.first_name))) = 4
WHERE smallTbl.importantValue IS NULL
-- The following line is "the optimization"
--AND LEFT(RTRIM(LTRIM(largeTbl.last_name)), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å')
drop table #largeTableOfPeople;
drop table #smallTableOfPeople;
AND LEFT(TRIM(largeTbl.last_name), 1) BETWEEN 'a' AND 'z' COLLATE LATIN1_GENERAL_CI_AI
harus melakukan apa yang Anda inginkan di sana tanpa mengharuskan Anda untuk membuat daftar semua karakter dan memiliki kode yang sulit dibaca