Tất cả các câu trả lời hiện có (đang hoạt động) có một trong hai vấn đề:
- Họ sẽ bỏ qua các chỉ số trên cột đang được tìm kiếm
- Ý chí (có khả năng) chọn dữ liệu không theo ý muốn, âm thầm làm hỏng kết quả của bạn.
1. Các chỉ số bị Bỏ qua:
Đối với hầu hết các phần, khi một cột đang được tìm kiếm có một hàm được gọi trên nó (bao gồm ngầm định, như for CAST
), trình tối ưu hóa phải bỏ qua các chỉ số trên cột và tìm kiếm qua mọi bản ghi. Đây là một ví dụ nhanh:
Chúng tôi đang xử lý các dấu thời gian và hầu hết các RDBMS có xu hướng lưu trữ thông tin này dưới dạng giá trị ngày càng tăng của một số loại, thường là một long
hoặc BIGINTEGER
đếm mili / nano giây. Do đó, thời gian hiện tại trông / được lưu trữ như sau:
1402401635000000
Bạn không thấy giá trị 'Năm' ( '2014'
) trong đó, phải không? Trên thực tế, có một chút toán học phức tạp để dịch qua lại. Vì vậy, nếu bạn gọi bất kỳ hàm phần trích xuất / ngày nào trên cột được tìm kiếm, máy chủ phải thực hiện tất cả phép toán đó chỉ để tìm ra liệu bạn có thể đưa nó vào kết quả hay không. Trên các bảng nhỏ, đây không phải là một vấn đề, nhưng khi tỷ lệ phần trăm các hàng được chọn giảm, điều này trở nên lớn hơn và lớn hơn. Sau đó, trong trường hợp này, bạn đang làm điều đó lần thứ hai để hỏi về MONTH
... tốt, bạn sẽ có được bức tranh.
2. Dữ liệu ngoài ý muốn:
Tùy thuộc vào phiên bản SQL Server cụ thể và kiểu dữ liệu cột, việc sử dụng BETWEEN
(hoặc các phạm vi giới hạn trên bao gồm tương tự <=
:) có thể dẫn đến việc chọn sai dữ liệu . Về cơ bản, bạn có thể kết thúc việc bao gồm dữ liệu từ nửa đêm của ngày "tiếp theo" hoặc loại trừ một số phần của bản ghi của ngày "hiện tại".
Những gì bạn nên làm:
Vì vậy, chúng tôi cần một cách an toàn cho dữ liệu của mình và sẽ sử dụng các chỉ số (nếu khả thi). Cách chính xác sau đó có dạng:
WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth
Cho rằng chỉ có một tháng, @startOfPreviousMonth
có thể dễ dàng thay thế cho / bắt nguồn bằng:
DATEADD(month, -1, @startOCurrentfMonth)
Nếu bạn cần lấy ngày bắt đầu của tháng hiện tại trong máy chủ, bạn có thể thực hiện theo cách sau:
DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
Một lời giải thích nhanh ở đây. Giá trị ban đầu DATEDIFF(...)
sẽ nhận được sự khác biệt giữa thời điểm bắt đầu kỷ nguyên hiện tại ( 0001-01-01
- AD, CE, bất cứ điều gì), về cơ bản trả về một số nguyên lớn. Đây là số tháng tính đến đầu tháng hiện tại . Sau đó, chúng tôi thêm số này vào đầu kỷ nguyên, tức là vào đầu tháng nhất định.
Vì vậy, tập lệnh đầy đủ của bạn có thể / phải trông giống như sau:
DECLARE @startOfCurrentMonth DATETIME
SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth)
AND date_created < @startOfCurrentMonth
Do đó, tất cả các hoạt động ngày tháng chỉ được thực hiện một lần, trên một giá trị; trình tối ưu hóa miễn phí sử dụng các chỉ số và không có dữ liệu sai nào được đưa vào.