Cốt lõi của câu hỏi không phải là "tại sao đơn hàng lại quan trọng với LINQ?". LINQ chỉ dịch theo nghĩa đen mà không cần sắp xếp lại. Câu hỏi thực sự là "tại sao hai truy vấn SQL có hiệu suất khác nhau?".
Tôi đã có thể tái tạo vấn đề bằng cách chỉ chèn 100k hàng. Trong trường hợp đó, một điểm yếu trong trình tối ưu hóa đang được kích hoạt:nó không nhận ra rằng nó có thể thực hiện tìm kiếm trên Colour
do điều kiện phức tạp. Trong truy vấn đầu tiên, trình tối ưu hóa không nhận ra mẫu và tạo một tìm kiếm chỉ mục.
Không có lý do ngữ nghĩa nào tại sao phải như vậy. Có thể tìm kiếm trên một chỉ mục ngay cả khi tìm kiếm trên NULL
. Đây là một điểm yếu / lỗi trong trình tối ưu hóa. Đây là hai kế hoạch:
EF cố gắng hữu ích ở đây vì nó giả định rằng cả cột và biến bộ lọc đều có thể rỗng. Trong trường hợp đó, nó cố gắng cung cấp cho bạn một kết quả phù hợp (theo ngữ nghĩa C # là điều đúng đắn).
Tôi đã thử hoàn tác điều đó bằng cách thêm bộ lọc sau:
Colour IS NOT NULL AND @p__linq__0 IS NOT NULL
AND Size IS NOT NULL AND @p__linq__1 IS NOT NULL
Hy vọng rằng trình tối ưu hóa hiện sử dụng kiến thức đó để đơn giản hóa biểu thức bộ lọc EF phức tạp. Nó đã không quản lý để làm như vậy. Nếu điều này hoạt động, bộ lọc tương tự có thể đã được thêm vào truy vấn EF để cung cấp một giải pháp khắc phục dễ dàng.
Dưới đây là các bản sửa lỗi mà tôi đề xuất theo thứ tự mà bạn nên thử chúng:
- Làm cho các cột cơ sở dữ liệu không bị rỗng trong cơ sở dữ liệu
- Đặt các cột không rỗng trong mô hình dữ liệu EF với hy vọng rằng điều này sẽ ngăn EF tạo điều kiện lọc phức tạp
- Tạo chỉ mục:
Colour, Size
và / hoặcSize, Colour
. Họ cũng loại bỏ chúng vấn đề. - Đảm bảo rằng quá trình lọc được thực hiện theo đúng thứ tự và để lại nhận xét về mã
- Cố gắng sử dụng
INTERSECT
/Queryable.Intersect
để kết hợp các bộ lọc. Điều này thường dẫn đến các hình dạng kế hoạch khác nhau. - Tạo một hàm có giá trị bảng nội dòng để thực hiện lọc. EF có thể sử dụng một hàm như một phần của truy vấn lớn hơn
- Thả xuống SQL thô
- Sử dụng hướng dẫn kế hoạch để thay đổi kế hoạch
Tất cả những điều này là cách giải quyết, không phải là bản sửa lỗi nguyên nhân gốc rễ.
Cuối cùng, tôi không hài lòng với cả SQL Server và EF ở đây. Cả hai sản phẩm nên được sửa chữa. Rất tiếc, chúng có thể sẽ không xảy ra và bạn cũng không thể chờ đợi điều đó.
Đây là các tập lệnh chỉ mục:
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]