Hiệu suất của a = 0 và b = 0 và Giảm z = 0 so với a + b + c + d = 0


20

Đây là một câu hỏi đơn giản mà tôi dường như không thể tìm thấy câu trả lời.

Về mặt hiệu suất, nếu tôi có một WHEREmệnh đề như a=0 and b=0 and ... z=0, tôi có đạt được hiệu suất nào không nếu tôi thay thế điều kiện đó bằng a+b+...+z=0?

Nói cách khác, có bất kỳ hiệu suất tăng bằng cách thay thế sau đây

Select * 
From MyTable 
Where A=0 and B=0 and C=0 and D=0...

Với

Select * 
From MyTable 
Where A+B+C+D=0...

Tôi biết nó có thể phụ thuộc vào chỉ mục, nhưng với mục đích này, hãy nói rằng không có chỉ mục nào tồn tại. Toán tử số học (+) có hoạt động tốt hơn toán tử logic "HOẶC" hay "VÀ" không?

Tôi có ấn tượng rằng việc bổ sung thực hiện tốt hơn nhiều điều kiện với AND hoặc OR.

Kết quả kiểm tra

Trên bảng 4.2 triệu hàng

Trả về các hàng Trong đó A = 0 B = 0 và C = 0 -> 351748 Hàng

Việc bổ sung (A + B + C = 0) mất 5 giây trong khi các điều kiện logic A = 0 và B = 0 và C = 0 mất 11 giây.

Mặt khác

Trả về các hàng trong đó A <> 0 B <> 0 hoặc C <> 0 -> 3829750 Hàng 58 giây

Trả về các hàng Trong đó F65 + F67 + f64 <> 0 -> 3829750 Hàng 57 giây

Đối với OR, dường như không có sự khác biệt đáng kể.

Tôi đồng ý với gbn:

Nếu A là -1 và B là 1, A + B = 0 nhưng A = 0 và B = 0 là sai

và với AMtwo:

ABS (A) + ABS (B) + ABS (C) + ABS (D) ... Ngay cả khi bạn chỉ mong đợi các giá trị dương, nếu cột chấp nhận các giá trị âm, bạn nên cho rằng bạn có thể gặp phải một

Kết quả rất ấn tượng, như tôi nghĩ, có vẻ như việc bổ sung nhanh hơn nhiều so với các toán tử logic.

A = Float, B = Tiền và C = Float. Các truy vấn được sử dụng là như được hiển thị. Trong trường hợp của tôi, tất cả đều là số dương. Không có chỉ số. Theo suy nghĩ của tôi, việc bổ sung sẽ nhanh hơn các điều kiện logic!


Đây có phải là boolean? Có bao nhiêu cột bạn đang nói về 4 (trong các ví dụ) hoặc 26 (trong tiêu đề)? Nó làm cho một sự khác biệt. Phiên bản nào của SQL Server? Trường hợp FLOAT và TIỀN phát huy tác dụng? Có bao nhiêu hàng chúng ta đang đoán? Câu hỏi này có rất nhiều yếu tố.
Evan Carroll

@Evan Carroll Chúng không phải là Boolean, chúng là các số không được lập chỉ mục (int, float, money, v.v.). Bất kể Phiên bản SQL (SQL2012 trở lên), số lượng hàng hoặc cột, Câu hỏi là tìm ra toán tử nào thực hiện tốt hơn - logic so với toán tử số học. Như bạn có thể thấy Max Vernon chứng minh lý thuyết với các ví dụ của mình một cách hoàn hảo.
JohnG

Câu trả lời:


46

Trong câu hỏi của bạn, bạn nêu chi tiết một số bài kiểm tra mà bạn đã chuẩn bị khi bạn "chứng minh" rằng tùy chọn bổ sung nhanh hơn so với việc so sánh các cột rời rạc. Tôi nghi ngờ phương pháp thử nghiệm của bạn có thể bị thiếu sót theo nhiều cách, vì @gbn và @srutzky đã ám chỉ.

Trước tiên, bạn cần đảm bảo rằng bạn không kiểm tra SQL Server Management Studio (hoặc bất kỳ ứng dụng khách nào bạn đang sử dụng). Chẳng hạn, nếu bạn đang chạy một SELECT *bảng từ 3 triệu hàng, bạn chủ yếu kiểm tra khả năng của SSMS để kéo các hàng từ SQL Server và hiển thị chúng trên màn hình. Tốt hơn hết là bạn nên sử dụng một cái gì đó như SELECT COUNT(1)phủ nhận nhu cầu kéo hàng triệu hàng trên mạng và hiển thị chúng trên màn hình.

Thứ hai, bạn cần lưu ý về bộ đệm dữ liệu của SQL Server. Thông thường, chúng tôi kiểm tra tốc độ đọc dữ liệu từ bộ lưu trữ và xử lý dữ liệu đó, từ bộ đệm lạnh (tức là bộ đệm của SQL Server trống). Đôi khi, thật hợp lý khi thực hiện tất cả thử nghiệm của bạn với bộ đệm ấm, nhưng bạn cần tiếp cận thử nghiệm của mình một cách rõ ràng với ý nghĩ đó.

Đối với thử nghiệm bộ đệm lạnh, bạn cần chạy CHECKPOINTDBCC DROPCLEANBUFFERStrước mỗi lần chạy thử.

Đối với bài kiểm tra bạn đã hỏi về câu hỏi của bạn, tôi đã tạo ra bài kiểm tra sau:

IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
    DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
    TestID INT NOT NULL
        PRIMARY KEY 
        IDENTITY(1,1)
    , A INT NOT NULL
    , B FLOAT NOT NULL
    , C MONEY NOT NULL
    , D BIGINT NOT NULL
);

INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
    , sys.objects o2
    , sys.objects o3
    , sys.objects o4;

SELECT COUNT(1) 
FROM #SomeTest;

Điều này trả về số lượng 260.144.641 trên máy của tôi.

Để kiểm tra phương pháp "bổ sung", tôi chạy:

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;

Tab tin nhắn hiển thị:

Bảng '#SomeTest'. Quét số 3, đọc logic 1322661, đọc vật lý 0, đọc trước đọc 1313877, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0.

Thời gian thực thi của máy chủ SQL: Thời gian CPU = 49047 ms, thời gian đã trôi qua = 173451 ms.

Đối với thử nghiệm "cột rời rạc":

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
    AND st.B = 0
    AND st.C = 0
    AND st.D = 0;
GO

SET STATISTICS IO, TIME OFF;

một lần nữa, từ tab tin nhắn:

Bảng '#SomeTest'. Quét số 3, đọc logic 1322661, đọc vật lý 0, đọc trước đọc 1322661, đọc logic 0, đọc vật lý 0, đọc đọc trước 0, đọc trước 0.

Thời gian thực thi máy chủ SQL: Thời gian CPU = 8938 ms, thời gian trôi qua = 162581 ms.

Từ các số liệu thống kê ở trên, bạn có thể thấy biến thể thứ hai, với các cột rời rạc so với 0, thời gian trôi qua ngắn hơn khoảng 10 giây và thời gian CPU ít hơn khoảng 6 lần. Thời lượng dài trong các thử nghiệm của tôi ở trên chủ yếu là kết quả của việc đọc rất nhiều hàng từ đĩa. Nếu bạn giảm số lượng hàng xuống còn 3 triệu, bạn sẽ thấy các tỷ lệ vẫn giữ nguyên nhưng thời gian trôi qua giảm đáng kể, vì I / O của đĩa có ít tác dụng hơn.

Với phương pháp "Bổ sung":

Bảng '#SomeTest'. Quét số 3, đọc logic 15255, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

Thời gian thực thi máy chủ SQL: Thời gian CPU = 499 ms, thời gian trôi qua = 256 ms.

Với phương pháp "cột rời rạc":

Bảng '#SomeTest'. Quét số 3, đọc logic 15255, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

Thời gian thực thi máy chủ SQL: Thời gian CPU = 94 ms, thời gian trôi qua = 53 ms.

Điều gì sẽ tạo ra một sự khác biệt thực sự lớn cho bài kiểm tra này? Một chỉ số thích hợp, chẳng hạn như:

CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);

Phương pháp "bổ sung":

Bảng '#SomeTest'. Quét số 3, đọc logic 14235, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

Thời gian thực thi máy chủ SQL: Thời gian CPU = 546 ms, thời gian trôi qua = 314 ms.

Phương pháp "cột rời rạc":

Bảng '#SomeTest'. Quét số 1, đọc logic 3, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

Thời gian thực thi máy chủ SQL: Thời gian CPU = 0 ms, thời gian trôi qua = 0 ms.

Kế hoạch thực hiện cho từng truy vấn (với chỉ mục ở trên tại chỗ) là khá rõ ràng.

Phương thức "bổ sung", phải thực hiện quét toàn bộ chỉ mục:

nhập mô tả hình ảnh ở đây

và phương thức "các cột rời rạc", có thể tìm đến hàng đầu tiên của chỉ mục trong đó cột chỉ mục hàng đầu A, bằng không:

nhập mô tả hình ảnh ở đây


24

Giả sử bạn có một chỉ mục trên A, B, C và D. Cũng có thể được lọc.

Điều này có nhiều khả năng sử dụng chỉ số sau đó bổ sung.

Where A=0 and B=0 and C=0 and D=0

Trong một tin khác, nếu A là -1 và B là 1, A+B=0là đúng nhưng A=0 and B=0là sai.


7

(Xin lưu ý rằng câu trả lời này đã được gửi trước khi bất kỳ bài kiểm tra nào được ghi chú trong Câu hỏi: văn bản của Câu hỏi đã kết thúc ngay phía trên phần Kết quả kiểm tra .)

Tôi đoán rằng các ANDđiều kiện riêng biệt sẽ được ưu tiên hơn vì trình tối ưu hóa sẽ có khả năng ngắn mạch hoạt động nếu một trong số chúng không bằng 0, mà không cần phải tính toán trước.

Tuy nhiên, vì đây là một câu hỏi về hiệu suất, trước tiên bạn nên thiết lập một bài kiểm tra để xác định câu trả lời trên phần cứng của bạn . Báo cáo các kết quả đó, hiển thị mã kiểm tra của bạn và yêu cầu người khác xem qua để đảm bảo rằng đó là một bài kiểm tra tốt. Có thể có những yếu tố khác đáng để bạn cân nhắc.


3

Một số lý do chung, nếu bạn không có bất kỳ chỉ mục nào trong tay, tôi không nghĩ nó sẽ quan trọng với hai giải pháp bạn chọn, cả hai sẽ hoạt động kém. Mặt khác, nếu bạn có một chỉ mục trên một hoặc nhiều cột trong vị ngữ thì cột thứ nhất có thể sẽ hoạt động tốt hơn cột thứ hai, vì cột thứ hai có thể sẽ không thể sử dụng (các) chỉ mục.

Các bất đồng (OR) nói chung hoạt động kém hơn các liên từ (AND), nhưng ngay cả khi bạn có một truy vấn với các bất đồng, tôi sẽ đặt tiền của mình vào lần đầu tiên.


2

Đây là một câu hỏi đơn giản

Không có nó không phải là. Câu hỏi (loại) này là điều làm cho nhiều DBA và nhà phát triển phần mềm ngày ngày phải lo lắng, và tất cả chỉ là tầm thường.

mà tôi dường như không thể tìm thấy câu trả lời cho.

Vâng, bạn sẽ không. Ít nhất không phải là một câu trả lời chung chung. Trước hết, nó sẽ phụ thuộc rất nhiều vào RDBMS mà bạn đang sử dụng (OK, bạn đang sử dụng , nhưng vẫn còn). Nó thậm chí có thể thay đổi khi bạn chuyển từ một phiên bản RDBMS sang phiên bản tiếp theo.

Sau đó, nó có thể phụ thuộc vào bất kỳ số lượng chi tiết nhỏ nào khác, ví dụ như cách DB lưu trữ dữ liệu của bạn, nếu bạn có các lựa chọn phụ / tham gia gây nhầm lẫn vấn đề cho trình tối ưu hóa kế hoạch, v.v. Trình tối ưu hóa có thể cung cấp cho bạn các kế hoạch thực hiện khác nhau tùy thuộc vào bạn có bao nhiêu hàng ...

Làm một bài kiểm tra trong thế giới thực thường là cách hữu ích duy nhất để giải quyết các câu hỏi như thế này. Ngoài ra, bất kỳ lợi ích nào đạt được nhờ tối ưu hóa "phức tạp" như thế này thường bị nuốt chửng gấp 10 lần bởi sự lựa chọn chỉ số thông minh, vì vậy tôi sẽ không bận tâm đến việc dành quá nhiều thời gian cho nó, trước khi việc sử dụng chỉ mục thực sự bị loại trừ.


0

Điều này có thể rõ ràng, nhưng nếu các cột là INT, thì a+b+ccó thể bằng 0 ngay cả khi không có cột nào thực sự bằng không. Bạn đang thử nghiệm hai điều khác nhau!


Chỉ cần nhận ra @gbn đã đề cập đến điều này trong câu trả lời của mình.
Ross Presser
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.