Tiếp theo bài viết trước của tôi về việc cắt bớt thời gian so với datetime, tôi đã được khuyến khích để chứng minh rõ ràng hơn các đặc tính hiệu suất của các phương pháp khác nhau mà không liên quan đến quyền truy cập dữ liệu. Trong bài đăng gốc, tôi nhanh chóng so sánh bảy phương pháp khác nhau để chuyển đổi giá trị datetime sang ngày một cách độc lập, cho thấy rằng sự khác biệt là không đáng kể, sau đó chuyển thẳng sang phân tích việc sử dụng các phương pháp đó trong các truy vấn thực tế trả về dữ liệu.
Trong bài đăng này, tôi muốn chỉ ra một số cách khác nhau để cắt bớt thời gian so với datetime (thực tế là 18 cách khác nhau!), Mà không giới thiệu bất kỳ dữ liệu thực tế nào, để xem liệu chúng tôi có thể công bố cách "nhanh nhất" để thực hiện tác vụ này hay không.
Các phương pháp
Đây là 18 phương pháp tôi sẽ thử nghiệm, một số phương pháp được lấy từ bài đăng trên blog mà Madhivanan đã chỉ ra sau bài viết trước của tôi:
DECLARE @d DATETIME, @ds DATETIME = SYSDATETIME();
Bài kiểm tra
Tôi đã tạo một vòng lặp trong đó tôi sẽ chạy mỗi chuyển đổi 1.000.000 lần và sau đó lặp lại quy trình cho tất cả 18 phương pháp chuyển đổi 10 lần. Điều này sẽ cung cấp số liệu cho 10.000.000 lượt chuyển đổi cho mỗi phương pháp, loại bỏ bất kỳ sai lệch thống kê đáng kể nào.
CREATE TABLE #s(j INT, ms INT); GO SET NOCOUNT ON; GO DECLARE @j INT = 1, @x INT, @i INT = 1000000; DECLARE @t DATETIME2, @d DATETIME, @ds DATETIME = SYSDATETIME(); WHILE @j <= 18 BEGIN SELECT @x = 1, @t = SYSDATETIME(); WHILE @x <= @i BEGIN IF @j = 1 SET @d = DATEDIFF(DAY, 0, @ds); IF @j = 2 SET @d = CAST(@ds AS INT); IF @j = 3 SET @d = CAST(CONVERT(CHAR(8), @ds, 112) AS DATETIME); IF @j = 4 SET @d = DATEADD(DAY, DATEDIFF(DAY, 0, @ds), 0); IF @j = 5 SET @d = CAST(CAST(SUBSTRING(CAST(@ds AS BINARY(8)), 1, 4) AS BINARY(8)) AS DATETIME); IF @j = 6 SET @d = CONVERT(CHAR(8), @ds, 112); IF @J = 7 SET @d = CAST(CAST(@ds AS VARCHAR(11)) AS DATETIME); IF @J = 8 SET @d = @ds - CONVERT(CHAR(10), @ds, 108); IF @J = 9 SET @d = @ds - CAST(CAST(@ds AS TIME) AS DATETIME); IF @J = 10 SET @d = CAST(FLOOR(CAST(@ds AS FLOAT)) AS DATETIME); IF @J = 11 SET @d = CAST(CAST(CAST(CAST(@ds AS BINARY(8)) AS BINARY(4)) AS BINARY(8)) AS DATETIME); IF @J = 12 SET @d = @ds - CAST(@ds AS BINARY(4)); IF @J = 13 SET @d = DATEADD(DAY, CONVERT(INT, @ds - 0.5), 0); IF @J = 14 SET @d = CONVERT(DATETIME, FORMAT(@ds, N'yyyy-MM-dd')); IF @J = 15 SET @d = CONVERT(DATETIME,CONVERT(INT,CONVERT(FLOAT,@ds))); IF @J = 16 SET @d = CAST(CAST(CAST(CAST(@ds AS BINARY(8)) AS BIGINT) & 0XFFFFFFFF00000000 AS BINARY(8)) AS DATETIME); IF @J = 17 SET @d = CONVERT(DATE, @ds); IF @j = 18 SET @d = CAST(@ds AS DATE); SET @x += 1; END INSERT #s SELECT @j, DATEDIFF(MILLISECOND, @t, SYSDATETIME()); SET @j += 1; END GO 10 SELECT j, method = CASE ... END, MIN(ms), MAX(ms), AVG(ms) FROM #s GROUP BY j ORDER BY j;
Kết quả
Tôi đã chạy điều này trên máy ảo Windows 8, với RAM 8 GB và 4 vCPU, chạy SQL Server 2012 (11.0.2376). Đây là kết quả dạng bảng, được sắp xếp theo thời lượng trung bình, nhanh nhất đầu tiên:
Và đây là biểu diễn đồ họa của thời lượng trung bình:
Nếu chúng tôi đã loại bỏ ngoại lệ (sử dụng FORMAT
mới của SQL Server 2012 chức năng, một con chó rõ ràng cho mục đích này), chúng tôi sẽ thực sự khó khăn để chọn ra một kẻ thua cuộc thực sự ở đây. Trong số 17 phương pháp còn lại, để thực hiện chuyển đổi này một triệu lần, phương pháp chậm nhất chỉ chậm hơn phương pháp nhanh nhất trung bình ba giây. Bằng chứng vẫn ủng hộ khẳng định trước đây của tôi rằng sử dụng CAST / CONVERT
nguyên bản là hiệu quả nhất có thể mà bạn có thể nhận được, nhưng sự cải thiện so với các phương pháp tiếp cận khác chỉ là rất nhỏ và nó thậm chí không phải là người chiến thắng trong mỗi lần chạy.