Tìm ra cách sử dụng GIỮA với bảng vì nó sẽ hoạt động, nhưng sẽ có hiệu suất kém hơn trong mọi trường hợp:
- Tốt nhất sẽ tiêu tốn nhiều CPU hơn để thực hiện một số phép tính trên các hàng thay vì làm việc với chúng dưới dạng ngày tháng.
- Điều tồi tệ nhất sẽ buộc phải quét bảng trên mọi hàng trong bảng, nhưng nếu các cột của bạn có chỉ mục, thì với truy vấn phù hợp, bạn có thể tìm kiếm. Đây có thể là một sự khác biệt về hiệu suất LỚN, vì việc buộc các ràng buộc vào một mệnh đề GIỮA sẽ vô hiệu hóa việc sử dụng chỉ mục.
Thay vào đó, tôi đề xuất những điều sau nếu bạn có chỉ mục trên các cột ngày của mình và quan tâm đến hiệu suất:
DECLARE
@FromDate date = '20111101',
@ToDate date = '20120201';
SELECT *
FROM dbo.YourTable T
WHERE
(
T.[Year] > Year(@FromDate)
OR (
T.[Year] = Year(@FromDate)
AND T.[Month] >= Month(@FromDate)
)
) AND (
T.[Year] < Year(@ToDate)
OR (
T.[Year] = Year(@ToDate)
AND T.[Month] <= Month(@ToDate)
)
);
Tuy nhiên, có thể hiểu rằng bạn không muốn sử dụng một công trình như vậy vì nó rất khó xử. Vì vậy, đây là một truy vấn thỏa hiệp, ít nhất sử dụng tính toán số và sẽ sử dụng ít CPU hơn so với tính toán chuyển đổi ngày thành chuỗi (mặc dù không đủ ít hơn để bù đắp cho quá trình quét bắt buộc, đây là vấn đề hiệu suất thực sự).
SELECT *
FROM dbo.YourTable T
WHERE
T.[Year] * 100 + T.[Month] BETWEEN 201111 AND 201202;
Nếu bạn có chỉ mục về Year
, bạn có thể nhận được một sự thúc đẩy lớn bằng cách gửi truy vấn như sau, truy vấn này có cơ hội tìm kiếm:
SELECT *
FROM dbo.YourTable T
WHERE
T.[Year] * 100 + T.[Month] BETWEEN 201111 AND 201202
AND T.[Year] BETWEEN 2011 AND 2012; -- allows use of an index on [Year]
Mặc dù điều này phá vỡ yêu cầu của bạn về việc sử dụng một BETWEEN
biểu hiện, nó không quá đau đớn và sẽ hoạt động rất tốt với Year
chỉ mục.
Bạn cũng có thể thay đổi bảng của mình. Thành thật mà nói, việc sử dụng các số riêng biệt cho các phần ngày của bạn thay vì một cột duy nhất với loại dữ liệu ngày là không tốt. Lý do nó không tốt là vì vấn đề chính xác mà bạn đang gặp phải hiện tại - rất khó để truy vấn.
Trong một số tình huống lưu trữ dữ liệu mà việc lưu byte quan trọng rất nhiều, tôi có thể hình dung các tình huống mà bạn có thể lưu trữ ngày tháng dưới dạng số (chẳng hạn như 201111
) nhưng điều đó không được khuyến khích. tốt nhất giải pháp là thay đổi bảng của bạn để sử dụng ngày thay vì tách ra giá trị số của tháng và năm. Chỉ cần lưu trữ ngày đầu tiên của tháng, nhận biết rằng ngày đó có giá trị trong cả tháng.
Nếu thay đổi cách bạn sử dụng các cột này không phải là một tùy chọn nhưng bạn vẫn có thể thay đổi bảng của mình, thì bạn có thể thêm một cột được tính toán liên tục:
ALTER Table dbo.YourTable
ADD ActualDate AS (DateAdd(year, [Year] - 1900, DateAdd(month, [Month], '18991201')))
PERSISTED;
Với điều này, bạn chỉ có thể làm:
SELECT *
FROM dbo.YourTable
WHERE
ActualDate BETWEEN '20111101' AND '20120201';
PERSISTED
từ khóa có nghĩa là trong khi bạn vẫn sẽ được quét, nó sẽ không phải thực hiện bất kỳ phép tính nào trên mỗi hàng vì biểu thức được tính trên mỗi CHÈN hoặc CẬP NHẬT và được lưu trữ trong hàng. Nhưng bạn có thể nhận được một tìm kiếm nếu bạn thêm một chỉ mục trên cột này, điều này sẽ làm cho nó hoạt động rất tốt (mặc dù nói chung, điều này vẫn không lý tưởng bằng việc thay đổi để sử dụng cột ngày thực tế, vì nó sẽ chiếm nhiều dung lượng hơn và sẽ ảnh hưởng đến CHÈN và CẬP NHẬT):
CREATE NONCLUSTERED INDEX IX_YourTable_ActualDate ON dbo.YourTable (ActualDate);
Tóm lại:nếu bạn thực sự không thể thay đổi bảng theo bất kỳ cách nào, thì bạn sẽ phải thỏa hiệp theo một cách nào đó. Sẽ không thể có được cú pháp đơn giản mà bạn muốn mà cũng sẽ hoạt động tốt, khi ngày tháng của bạn được lưu trữ chia thành các cột riêng biệt.