SQL Server 2008 trở lên
Trong SQL Server 2008 trở lên, tất nhiên là cách nhanh nhất Convert(date, @date)
. Điều này có thể được chuyển trở lại a datetime
hoặc datetime2
nếu cần.
Điều gì thực sự tốt nhất trong SQL Server 2005 và cũ hơn?
Tôi đã thấy các tuyên bố không nhất quán về việc cắt ngắn thời gian từ một ngày trong SQL Server nhanh nhất và một số người thậm chí còn nói rằng họ đã thử nghiệm, nhưng trải nghiệm của tôi thì khác. Vì vậy, hãy thực hiện một số kiểm tra nghiêm ngặt hơn và để mọi người có kịch bản để nếu tôi mắc bất kỳ lỗi nào, mọi người có thể sửa cho tôi.
Chuyển đổi nổi không chính xác
Đầu tiên, tôi sẽ tránh chuyển đổi datetime
sang float
, vì nó không chuyển đổi chính xác. Bạn có thể tránh xa việc thực hiện chính xác việc loại bỏ thời gian, nhưng tôi nghĩ không nên sử dụng nó vì nó ngầm thông báo với các nhà phát triển rằng đây là một hoạt động an toàn và không phải vậy . Hãy xem:
declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
Đây không phải là điều mà chúng ta nên dạy mọi người về mã của chúng ta hoặc trong các ví dụ trực tuyến của chúng ta.
Ngoài ra, nó thậm chí không phải là cách nhanh nhất!
Bằng chứng - Kiểm tra hiệu suất
Nếu bạn muốn tự mình thực hiện một số thử nghiệm để xem các phương pháp khác nhau thực sự xếp chồng lên nhau như thế nào, thì bạn sẽ cần tập lệnh thiết lập này để chạy các thử nghiệm sâu hơn:
create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED);
declare @d datetime;
set @d = DateDiff(Day, 0, GetDate());
insert AllDay select @d;
while @@ROWCOUNT != 0
insert AllDay
select * from (
select Tm =
DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm)
from AllDay
) X
where Tm < DateAdd(Day, 1, @d);
exec sp_spaceused AllDay;
Xin lưu ý rằng điều này tạo ra một bảng 427,57 MB trong cơ sở dữ liệu của bạn và sẽ mất khoảng 15-30 phút để chạy. Nếu cơ sở dữ liệu của bạn nhỏ và được đặt ở mức tăng trưởng 10% thì sẽ mất nhiều thời gian hơn nếu bạn kích thước đủ lớn trước.
Bây giờ là kịch bản kiểm tra hiệu suất thực tế. Xin lưu ý rằng mục đích là không trả lại các hàng cho khách hàng vì điều này rất đắt trên 26 triệu hàng và sẽ che giấu sự khác biệt về hiệu suất giữa các phương pháp.
Kết quả hoạt động
set statistics time on;
GO
declare
@dd date,
@d datetime,
@di int,
@df float,
@dv varchar(10);
select @d = CONVERT(date, Tm) from AllDay;
select @d = CAST(Tm - 0.50000004 AS int) from AllDay;
select @d = DATEDIFF(DAY, 0, Tm) from AllDay;
select @d = FLOOR(CAST(Tm as float)) from AllDay;
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
select @dd = Tm from AllDay;
select @di = CAST(Tm - 0.50000004 AS int) from AllDay;
select @di = DATEDIFF(DAY, 0, Tm) from AllDay;
select @df = FLOOR(CAST(Tm as float)) from AllDay;
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
GO
set statistics time off;
Một số phân tích lan man
Một số lưu ý về điều này. Trước hết, nếu chỉ thực hiện GROUP BY hoặc so sánh, thì không cần phải chuyển đổi trở lại datetime
. Vì vậy, bạn có thể tiết kiệm một số CPU bằng cách tránh điều đó, trừ khi bạn cần giá trị cuối cùng cho mục đích hiển thị. Bạn thậm chí có thể NHÓM THEO giá trị chưa được chuyển đổi và chỉ đặt chuyển đổi trong mệnh đề CHỌN:
select Convert(datetime, DateDiff(dd, 0, Tm))
from (select '2010-09-12 00:00:00.003') X (Tm)
group by DateDiff(dd, 0, Tm)
Ngoài ra, hãy xem cách chuyển đổi số chỉ mất thêm một chút thời gian để chuyển đổi trở lại datetime
, nhưng varchar
chuyển đổi gần như tăng gấp đôi? Điều này cho thấy phần của CPU được dành cho tính toán ngày tháng trong các truy vấn. Có một số phần của việc sử dụng CPU không liên quan đến tính toán ngày tháng và điều này dường như gần bằng 19875 ms trong các truy vấn trên. Sau đó, chuyển đổi cần một số tiền bổ sung, vì vậy nếu có hai chuyển đổi, số tiền đó sẽ được sử dụng gần gấp đôi.
Kiểm tra nhiều hơn cho thấy rằng so với Convert(, 112)
, Convert(, 101)
truy vấn có một số chi phí CPU bổ sung (vì nó sử dụng lâu hơn varchar
?), Bởi vì chuyển đổi thứ hai trở lại date
không tốn nhiều như chuyển đổi ban đầu varchar
, nhưng Convert(, 112)
nó gần với cùng 20000 ms chi phí cơ sở CPU.
Dưới đây là những tính toán về thời gian CPU mà tôi đã sử dụng cho phân tích ở trên:
method round single base
date 21324 19891 18458
int 23031 21453 19875
datediff 23782 23218 22654
float 36891 29312 21733
varchar-112 102984 64016 25048
varchar-101 123375 65609 7843
vòng là thời gian CPU cho một vòng quay trở lại datetime
.
đơn là thời gian CPU cho một lần chuyển đổi sang kiểu dữ liệu thay thế (kiểu dữ liệu có tác dụng phụ là loại bỏ phần thời gian).
cơ sở là việc tính trừ từ single
phần chênh lệch giữa hai lời gọi: single - (round - single)
. Đó là một hình vẽ quả bóng giả định việc chuyển đổi đến và đi từ kiểu dữ liệu đó và datetime
gần giống nhau theo cả hai hướng. Có vẻ như giả định này không hoàn hảo nhưng gần đúng vì tất cả các giá trị đều gần 20000 ms với chỉ một ngoại lệ.
Một điều thú vị nữa là chi phí cơ sở gần bằng với Convert(date)
phương pháp đơn (phải gần như bằng 0, vì máy chủ có thể trích xuất nội bộ phần ngày số nguyên ngay trong bốn byte đầu tiên của datetime
kiểu dữ liệu).
Phần kết luận
Vì vậy, nó trông như thế nào là varchar
phương pháp chuyển đổi một hướng mất khoảng 1,8 μs và DateDiff
phương pháp một hướng mất khoảng 0,18 μs. Tôi đang dựa trên điều này dựa trên thời gian "CPU cơ bản" thận trọng nhất trong thử nghiệm của tôi là tổng cộng 18458 ms cho 25,920,000 hàng, vì vậy 23218 ms / 25920000 = 0,18 μs. Sự cải thiện 10x rõ ràng có vẻ như rất nhiều, nhưng nói thật là nó khá nhỏ cho đến khi bạn xử lý hàng trăm nghìn hàng (617k hàng = tiết kiệm 1 giây).
Ngay cả với cải tiến tuyệt đối nhỏ này, theo ý kiến của tôi, DateAdd
phương pháp này vẫn chiến thắng vì nó là sự kết hợp tốt nhất giữa hiệu suất và độ rõ ràng. Câu trả lời đòi hỏi một "con số kỳ diệu" 0.50000004
là sẽ cắn ai đó vào một ngày nào đó (năm số 0 hoặc sáu ???), cộng với nó khó hiểu hơn.
Ghi chú bổ sung
Khi tôi có thời gian, tôi sẽ thay đổi 0.50000004
để '12:00:00.003'
xem nó hoạt động như thế nào. Nó được chuyển đổi thành cùng một datetime
giá trị và tôi thấy nó dễ nhớ hơn nhiều.
Đối với những người quan tâm, các thử nghiệm ở trên đã được chạy trên máy chủ mà @@ Phiên bản trả về như sau:
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) ngày 9 tháng 7 năm 2008 14:43:34 Bản quyền (c) 1988-2008 Microsoft Corporation Standard Edition trên Windows NT 5.2 (Bản dựng 3790: Gói dịch vụ 2)