Memaksakan
Ketika bekerja pada Top Quality Blog PostsĀ®, saya datang di beberapa perilaku optimizer saya menemukan benar-benar menyebalkan menarik. Saya tidak segera memiliki penjelasan, setidaknya bukan yang saya senangi, jadi saya taruh di sini kalau-kalau ada orang pintar yang muncul.
Jika Anda ingin mengikuti, Anda dapat mengambil versi 2013 dari tumpukan data Stack Overflow di sini . Saya menggunakan tabel Komentar, dengan satu indeks tambahan di atasnya.
CREATE INDEX [ix_ennui] ON [dbo].[Comments] ( [UserId], [Score] DESC );
Kueri Satu
Ketika saya meminta tabel seperti itu, saya mendapatkan paket permintaan aneh .
WITH x
AS
(
SELECT TOP 101
c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
ORDER BY c.Score DESC
)
SELECT *
FROM x
WHERE x.Score >= 500;
Predikat SARGable tentang Skor tidak didorong di dalam CTE. Ada dalam operator filter jauh di kemudian hari dalam rencana.
Yang saya temukan aneh, karena ORDER BY
berada di kolom yang sama dengan filter.
Pertanyaan Dua
Jika saya mengubah kueri, itu bisa didorong.
WITH x
AS
(
SELECT c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
)
SELECT TOP 101 *
FROM x
WHERE x.Score >= 500
ORDER BY x.Score DESC;
The rencana permintaan perubahan , juga, dan berjalan lebih cepat, tanpa tumpahan ke disk. Keduanya menghasilkan hasil yang sama, dengan predikat pada pemindaian indeks nonclustered.
Kueri Tiga
Ini sama dengan menulis kueri seperti ini:
SELECT TOP 101
c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
WHERE c.Score >= 500
ORDER BY c.Score DESC;
Kueri Empat
Menggunakan tabel turunan mendapatkan paket kueri "buruk" yang sama dengan kueri CTE awal
SELECT *
FROM ( SELECT TOP 101
c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
ORDER BY c.Score DESC ) AS x
WHERE x.Score >= 500;
Segalanya menjadi lebih aneh ketika ...
Saya mengubah kueri untuk memesan data yang naik, dan filter ke <=
.
Agar tidak membuat pertanyaan ini terlalu lama, saya akan menggabungkan semuanya.
Pertanyaan
--Derived table
SELECT *
FROM ( SELECT TOP 101
c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
ORDER BY c.Score ASC ) AS x
WHERE x.Score <= 500;
--TOP inside CTE
WITH x
AS
(
SELECT TOP 101
c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
ORDER BY c.Score ASC
)
SELECT *
FROM x
WHERE x.Score <= 500;
--Written normally
SELECT TOP 101
c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
WHERE c.Score <= 500
ORDER BY c.Score ASC;
--TOP outside CTE
WITH x
AS
(
SELECT c.UserId, c.Text, c.Score
FROM dbo.Comments AS c
)
SELECT TOP 101 *
FROM x
WHERE x.Score <= 500
ORDER BY x.Score ASC;
Rencana
Perhatikan bahwa tidak satu pun dari kueri ini yang memanfaatkan indeks yang tidak dikelompokkan - satu-satunya hal yang berubah di sini adalah posisi operator filter. Dalam keadaan apa pun, predikat tidak didorong ke akses indeks.
Sebuah Pertanyaan Muncul!
Apakah ada alasan bahwa predikat SARGable dapat ditekan dalam beberapa skenario dan tidak pada skenario lainnya? Perbedaan dalam kueri yang diurutkan dalam urutan menurun itu menarik, tetapi perbedaan antara kueri dan yang naik aneh.
Bagi siapa pun yang tertarik, berikut adalah paket dengan hanya indeks di Score
: