Inti pertanyaannya bukanlah "mengapa urutan penting dengan LINQ?". LINQ hanya menerjemahkan secara harfiah tanpa menyusun ulang. Pertanyaan sebenarnya adalah "mengapa dua kueri SQL memiliki kinerja yang berbeda?".
Saya dapat mereproduksi masalah dengan hanya memasukkan 100k baris. Dalam hal ini, kelemahan dalam pengoptimal dipicu:ia tidak mengenali bahwa ia dapat melakukan pencarian di Colour
karena kondisi yang kompleks. Dalam kueri pertama, pengoptimal mengenali pola dan membuat pencarian indeks.
Tidak ada alasan semantik mengapa ini harus terjadi. Pencarian di indeks dimungkinkan bahkan ketika mencari di NULL
. Ini adalah kelemahan/bug di pengoptimal. Berikut adalah dua rencana:
EF mencoba membantu di sini karena mengasumsikan bahwa kolom dan variabel filter bisa nol. Dalam hal ini mencoba memberi Anda kecocokan (yang menurut semantik C# adalah hal yang benar).
Saya mencoba membatalkannya dengan menambahkan filter berikut:
Colour IS NOT NULL AND @p__linq__0 IS NOT NULL
AND Size IS NOT NULL AND @p__linq__1 IS NOT NULL
Berharap pengoptimal sekarang menggunakan pengetahuan itu untuk menyederhanakan ekspresi filter EF yang kompleks. Itu tidak berhasil melakukannya. Jika ini berhasil, filter yang sama dapat ditambahkan ke kueri EF untuk memberikan perbaikan yang mudah.
Berikut adalah perbaikan yang saya sarankan dalam urutan yang harus Anda coba:
- Buat kolom database tidak null di database
- Buat kolom tidak nol dalam model data EF dengan harapan ini akan mencegah EF membuat kondisi filter yang rumit
- Buat indeks:
Colour, Size
dan/atauSize, Colour
. Mereka juga menghapus masalah mereka. - Pastikan pemfilteran dilakukan dengan urutan yang benar dan tinggalkan komentar kode
- Coba gunakan
INTERSECT
/Queryable.Intersect
untuk menggabungkan filter. Hal ini sering menghasilkan bentuk denah yang berbeda. - Buat fungsi bernilai tabel sebaris yang melakukan pemfilteran. EF dapat menggunakan fungsi seperti itu sebagai bagian dari kueri yang lebih besar
- Turunkan ke SQL mentah
- Gunakan panduan paket untuk mengubah paket
Semua ini adalah solusi, bukan perbaikan akar masalah.
Pada akhirnya saya tidak senang dengan SQL Server dan EF di sini. Kedua produk harus diperbaiki. Sayangnya, mereka mungkin tidak akan melakukannya dan Anda juga tidak sabar untuk itu.
Berikut adalah skrip indeks:
( idpre>CREATE NONCLUSTERED INDEX IX_Widget_Colour_Size ON dbo.Widget
(
Colour, Size
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX IX_Widget_Size_Colour ON dbo.Widget
(
Size, Colour
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]