Menemukan cara untuk menggunakan ANTARA dengan tabel sebagaimana adanya akan berhasil, tetapi kinerjanya akan lebih buruk dalam setiap kasus:
- Ini akan menghabiskan lebih banyak CPU untuk melakukan semacam perhitungan pada baris daripada bekerja dengan mereka sebagai tanggal.
- Paling buruk ini akan memaksa pemindaian tabel pada setiap baris dalam tabel, tetapi jika kolom Anda memiliki indeks, maka dengan kueri yang tepat pencarian dimungkinkan. Ini bisa menjadi perbedaan performa yang BESAR, karena memaksakan batasan ke dalam klausa BETWEEN akan menonaktifkan menggunakan indeks.
Saya menyarankan yang berikut ini jika Anda memiliki indeks di kolom tanggal dan sama sekali peduli dengan kinerja:
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)
)
);
Namun, dapat dimengerti bahwa Anda tidak ingin menggunakan konstruksi seperti itu karena sangat canggung. Jadi, inilah kueri kompromi, yang setidaknya menggunakan komputasi numerik dan akan menggunakan lebih sedikit CPU daripada komputasi konversi tanggal-ke-string (meskipun tidak cukup untuk menebus pemindaian paksa yang merupakan masalah kinerja sebenarnya).
SELECT *
FROM dbo.YourTable T
WHERE
T.[Year] * 100 + T.[Month] BETWEEN 201111 AND 201202;
Jika Anda memiliki indeks pada Year
, Anda bisa mendapatkan dorongan besar dengan mengirimkan kueri sebagai berikut, yang memiliki peluang untuk mencari:
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]
Meskipun ini melanggar persyaratan Anda untuk menggunakan satu BETWEEN
ekspresi, itu tidak terlalu menyakitkan dan akan tampil sangat baik dengan Year
indeks.
Anda juga dapat mengubah tabel Anda. Terus terang, menggunakan nomor terpisah untuk bagian tanggal Anda alih-alih satu kolom dengan tipe data tanggal tidak baik. Alasan mengapa ini tidak baik adalah karena masalah persis yang Anda hadapi saat ini--sangat sulit untuk ditanyakan.
Dalam beberapa skenario pergudangan data di mana penghematan byte sangat penting, saya dapat membayangkan situasi di mana Anda mungkin menyimpan tanggal sebagai angka (seperti 201111
) tetapi itu tidak disarankan. terbaik solusinya adalah mengubah tabel Anda untuk menggunakan tanggal alih-alih membagi nilai numerik bulan dan tahun. Cukup simpan hari pertama setiap bulan, dengan mengetahui bahwa hari itu berlaku sepanjang bulan.
Jika mengubah cara Anda menggunakan kolom ini bukanlah pilihan tetapi Anda masih dapat mengubah tabel Anda, maka Anda dapat menambahkan kolom terhitung yang bertahan:
ALTER Table dbo.YourTable
ADD ActualDate AS (DateAdd(year, [Year] - 1900, DateAdd(month, [Month], '18991201')))
PERSISTED;
Dengan ini Anda hanya dapat melakukan:
SELECT *
FROM dbo.YourTable
WHERE
ActualDate BETWEEN '20111101' AND '20120201';
PERSISTED
kata kunci berarti bahwa saat Anda masih akan mendapatkan pemindaian, itu tidak perlu melakukan perhitungan apa pun pada setiap baris karena ekspresi dihitung pada setiap INSERT atau UPDATE dan disimpan di baris. Tapi Anda bisa dapatkan pencarian jika Anda menambahkan indeks pada kolom ini, yang akan membuatnya berkinerja sangat baik (meskipun secara keseluruhan, ini masih tidak seideal mengubah menggunakan kolom tanggal yang sebenarnya, karena akan memakan lebih banyak ruang dan akan memengaruhi INSERT dan PEMBARUAN):
CREATE NONCLUSTERED INDEX IX_YourTable_ActualDate ON dbo.YourTable (ActualDate);
Ringkasan:jika Anda benar-benar tidak dapat mengubah tabel dengan cara apa pun, maka Anda harus membuat kompromi dalam beberapa cara. Tidak mungkin mendapatkan sintaks sederhana yang Anda inginkan yang juga akan berkinerja baik, bila tanggal Anda disimpan dibagi menjadi kolom terpisah.