2013-03-11 42 views
21

Tôi có một trường SQL datetime trong một bảng rất lớn. Nó được lập chỉ mục và cần được truy vấn.Cách tối ưu để so sánh ngày tháng trong máy chủ Microsoft SQL là gì?

Vấn đề là SQL luôn lưu trữ thành phần thời gian (mặc dù nó luôn là nửa đêm), nhưng các tìm kiếm là ngày, chứ không phải là thời gian.

declare @dateVar datetime = '2013-03-11; 

select t.[DateColumn] 
from MyTable t 
where t.[DateColumn] = dateVar; 

Sẽ không trả lại bất kỳ điều gì vì t.[DateColumn] luôn bao gồm thành phần thời gian.

Câu hỏi của tôi là cách tốt nhất là gì?

Dường như có hai nhóm chính của lựa chọn:

  1. Tạo một biến thứ hai sử dụng dateadd và sử dụng một between ... and hoặc >= ... and ... <=.

  2. Chuyển đổi t.[DateColumn] thành thành phần chỉ có ngày - Tôi nghĩ điều này sẽ khiến mọi chỉ mục bị bỏ qua.

Cả hai điều này dường như rất lộn xộn - Tôi thực sự không muốn so sánh phạm vi hoặc quét bảng.

Có cách nào tốt hơn không?

Nếu một trong các tùy chọn này là cách tối ưu nhất quán thì làm cách nào và tại sao?

Trả lời

24

Chuyển đổi thành DATE hoặc sử dụng phạm vi ngày mở trong mọi trường hợp sẽ mang lại hiệu suất tốt nhất. FYI, chuyển đổi sang ngày bằng cách sử dụng một chỉ mục là những người biểu diễn tốt nhất. Nhiều thử nghiệm một kỹ thuật khác nhau trong bài viết: What is the most efficient way to trim time from datetime? văn bởi Aaron Bertrand

Từ bài viết rằng:

DECLARE @dateVar datetime = '19700204'; 

-- Quickest when there is an index on t.[DateColumn], 
-- because CONVERT can still use the index. 
SELECT t.[DateColumn] 
FROM MyTable t 
WHERE = CONVERT(DATE, t.[DateColumn]) = CONVERT(DATE, @dateVar); 

-- Quicker when there is no index on t.[DateColumn] 
DECLARE @dateEnd datetime = DATEADD(DAY, 1, @dateVar); 
SELECT t.[DateColumn] 
FROM MyTable t 
WHERE t.[DateColumn] >= @dateVar AND 
     t.[DateColumn] < @dateEnd; 

Cũng từ bài viết rằng: sử dụng BETWEEN, DATEDIFF hoặc CONVERT(CHAR(8)... đều chậm hơn.

+2

@Keith Cảm ơn bạn đã chỉ định các ví dụ .. và câu hỏi hay;) –

10

Dưới đây là ví dụ:

Tôi có bảng Đơn hàng có trường DateTime được gọi là OrderDate. Tôi muốn lấy tất cả các đơn đặt hàng mà ngày đặt hàng bằng 01/01/2006. có những cách tiếp theo để làm điều đó:

1) WHERE DateDiff(dd, OrderDate, '01/01/2006') = 0 
2) WHERE Convert(varchar(20), OrderDate, 101) = '01/01/2006' 
3) WHERE Year(OrderDate) = 2006 AND Month(OrderDate) = 1 and Day(OrderDate)=1 
4) WHERE OrderDate LIKE '01/01/2006%' 
5) WHERE OrderDate >= '01/01/2006' AND OrderDate < '01/02/2006' 

Được tìm thấy here

+0

của tất cả những người, # 1 được coi là hiệu quả nhất: http://www.sqlservercentral.com/Forums/Topic937765-338-1.aspx – RandomUs1r

+1

@ RandomUs1r tùy chọn # 1 cần chạy phép tính 'dateiff' cho mỗi hàng trong bảng, nó chắc chắn đã thắng không phải là nhanh nhất hoặc hiệu quả nhất. Tương tự cho tùy chọn # 2 với chuyển đổi 'varchar (20)'. Các tùy chọn # 4 và # 5 hứa hẹn hơn, và tôi sẽ bổ sung thêm hai: 6) 'trong đó OrderDate giữa @dateVar và dateadd (ngày, 1, @dateVar)' và 7) 'WHERE convert (date, OrderDate) = @ dateVar' – Keith

+3

Trong số 5 phương pháp được đề xuất 1-4 này đều rất chậm. 5 là nhanh chóng cho bảng heaped và phương pháp nhanh nhất ('chuyển đổi (ngày, OrderDate)' xem câu trả lời được lựa chọn) không phải là ngay cả trong danh sách. – Keith

0

Bạn có thể thêm một cột tính toán rằng chỉ bao gồm ngày mà không cần thời gian. Giữa hai lựa chọn, tôi muốn đi với nhà điều hành BETWEEN vì nó 'sạch hơn' với tôi và nên sử dụng tốt hơn các chỉ mục. So sánh kế hoạch thực hiện dường như chỉ ra rằng BETWEEN sẽ nhanh hơn; tuy nhiên, trong thử nghiệm thực tế họ đã thực hiện tương tự.

+1

Nó chỉ ra rằng ['between' là một ý tưởng tồi ở đây] (http://sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/what-do-between-and-the-devil-have- in-common.aspx). – Keith

+1

@Keith +1 Cảm ơn bạn đã liên kết. Tôi đã nhận thức được hầu hết các vấn đề (tôi biết nó đã được bao gồm và tôi thường xuyên thêm một giá trị thời gian vào ngày kết thúc khi cần thiết), nhưng số cuối cùng là mới đối với tôi. Tại nơi làm việc, tất cả các giá trị thời gian mà chúng tôi chọn đều bị cắt ngắn đến phút hoặc giây (không, đó không phải là quyết định của tôi. Có, sự thiếu chính xác gây phiền toái.) Do đó các vấn đề nano-giây chưa xuất hiện nhưng chúng có khả năng đủ nghiêm túc, tôi có thể sẽ thay đổi việc sử dụng 'BETWEEN' thành' => ... <'để thảo luận với các nhà phát triển khác ngày hôm nay. –

0

Nhận các mục khi ngày nằm trong khoảng từ ngày và giờ sang ngày.

nơi chuyển đổi (ngày, FROMNgày, 103) < = '2016/07/26' và chuyển đổi (ngày, NHCTVN 103)> = '2016/07/26'

+2

Xin chào @gaze, chào mừng bạn đến với Stack Overflow. Câu trả lời của bạn không thực sự thêm bất cứ điều gì ở đây - nếu bạn đọc câu trả lời được chấp nhận, bạn sẽ thấy rằng chúng đã bao hàm 'convert' và giải thích việc thay đổi kiểu hay sử dụng tốt hơn dựa trên các chỉ mục. cho. Để nhận được phiếu bầu, bạn thực sự cần phải thêm một thứ gì đó khác không có hoặc trả lời trước. – Keith

Các vấn đề liên quan