Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Sử dụng hợp lý IsNULL và Coalesce

Điều này đã được băm và băm lại. Ngoài mẹo tôi đã chỉ ra trong nhận xét và các liên kết và giải thích @xQbert đã đăng ở trên, theo yêu cầu, đây là giải thích về COALESCE so với ISNULL bằng cách sử dụng truy vấn con. Hãy xem xét hai truy vấn này, về mặt kết quả là giống nhau:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');

(Nhận xét về việc sử dụng TOP mà không cần ORDER BY tới / dev / null / thanks.)

Trong trường hợp COALESCE, logic thực sự được mở rộng thành một cái gì đó như thế này:

SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
    THEN (SELECT TOP (1) ...)
    ELSE N'foo'
END

Với ISNULL, điều này không xảy ra. Có một tối ưu hóa nội bộ dường như đảm bảo rằng truy vấn con chỉ được đánh giá một lần. Tôi không biết có ai bên ngoài Microsoft biết chính xác cách tối ưu hóa này hoạt động hay không, nhưng bạn có thể làm được điều này nếu so sánh các kế hoạch. Đây là kế hoạch cho phiên bản COALESCE:

Và đây là kế hoạch cho phiên bản ISNULL - lưu ý rằng nó đơn giản hơn nhiều (và quá trình quét chỉ diễn ra một lần):

Trong trường hợp COALESCE, quá trình quét diễn ra hai lần. Có nghĩa là truy vấn con được đánh giá hai lần, ngay cả khi nó không mang lại bất kỳ kết quả nào. Nếu bạn thêm mệnh đề WHERE sao cho truy vấn con tạo ra 0 hàng, bạn sẽ thấy sự chênh lệch tương tự - hình dạng kế hoạch có thể thay đổi, nhưng bạn vẫn sẽ thấy một tìm kiếm kép + tra cứu hoặc quét trường hợp COALESCE. Đây là một ví dụ khác nhỏ:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');

Kế hoạch cho phiên bản COALESCE lần này - một lần nữa bạn có thể thấy toàn bộ nhánh đại diện cho truy vấn con được lặp lại nguyên văn:

Và một kế hoạch đơn giản hơn nhiều, thực hiện gần một nửa công việc, sử dụng ISNULL:

Bạn cũng có thể xem câu hỏi này trên dba.se để thảo luận thêm:

Đề xuất của tôi là thế này (và bạn có thể thấy lý do của tôi tại sao trong mẹo và câu hỏi ở trên):hãy tin tưởng nhưng hãy xác minh. Tôi luôn sử dụng COALESCE (vì nó là tiêu chuẩn ANSI, hỗ trợ nhiều hơn hai đối số và không thực hiện những điều khó hiểu với ưu tiên kiểu dữ liệu) trừ khi Tôi biết tôi đang sử dụng truy vấn con như một trong các biểu thức (mà tôi không nhớ đã từng làm ngoài công việc lý thuyết như thế này chưa) hoặc tôi đang gặp sự cố hiệu suất thực sự và chỉ muốn so sánh xem liệu COALESCE so với ISNULL có bất kỳ sự khác biệt đáng kể về hiệu suất (mà tôi vẫn chưa tìm thấy bên ngoài trường hợp truy vấn con). Vì tôi hầu như luôn sử dụng COALESCE với các đối số kiểu dữ liệu tương tự, tôi hiếm khi phải thực hiện bất kỳ thử nghiệm nào ngoài việc nhìn lại những gì tôi đã nói về nó trong quá khứ (tôi cũng là tác giả của bài báo aspfaq mà xQbert đã chỉ ra , 7 năm trước).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chọn tất cả các ngày từ một bảng trong một phạm vi ngày và bao gồm 1 hàng cho mỗi ngày trống

  2. Tuyên bố đã chấm dứt. Đệ quy tối đa 100 đã hết trước khi hoàn thành câu lệnh

  3. CEILING () Ví dụ trong SQL Server

  4. Làm cách nào để lấy danh sách Máy chủ SQL có sẵn bằng C # Code?

  5. SQL Server:INNER JOIN sau UNION dẫn đến Hash Match (Tổng hợp) chậm