Reputation: 246
I have a table with the following structure:
CREATE TABLE MyTable (
ID int identity,
Whatever varchar(100),
MyTime time(2) NOT NULL,
MyDate date NOT NULL,
MyDateTime AS (DATEADD(DAY, DATEDIFF(DAY, '19000101', [MyDate]),
CAST([MyDate] AS DATETIME2(2))))
)
The computed column adds date and time into a single datetime2 field.
Most queries against the table have one or more of the following clauses:
... WHERE MyDate < @filter1 and MyDate > @filter2
... ORDER BY MyDate, MyTime
... ORDER BY MyDateTime
In a nutshell, date
is usually used for filtering, and full datetime
is used for sorting.
Now for questions:
What is the best way to set indices on those 3 date-time columns? 2 separate on date
and time
or maybe 1 on date
and 1 on composite datetime
, or something else? Quite a lot of inserts and updates occur on this table, and I'd like to avoid over-indexing.
As I wrote this question, I noticed the long and kind of ugly computed column definition. I picked it up from somewhere a while ago and forgot to investigate if there's a simpler way of doing it. Is there any easier way of combining a date
and time2
into a datetime2
? Simple addition does not work, and I'm not sure if I should avoid casting to varchar
, combining and casting back.
Upvotes: 4
Views: 18982
Reputation: 35373
The answer isn't in your indexing, it's in your querying.
A single DateTime
field should be used, or even SmallDateTime
if that provides the range of dates and time resolution required by your application.
Index that column, then use queries like this:
SELECT * FROM MyTable WHERE
MyDate >= @startfilterdate
AND MyDate < DATEADD(d, 1, @endfilterdate);
By using <
on the end filter, it only includes results from sometime before midnight of that date, which is the day after the user-selected "end date". This is simpler and more accurate than adding 23:59:59, especially since stored times can include microseconds between 23:59:59 and 00:00:00.
Using persisted columns and indexes on them is a waste of server resources.
Upvotes: 1
Reputation: 115530
Having date and time in two separate columns may seem peculiar but if you have queries that use only the date (and/or especially only the time part), I think it's a valid decision. You can create an index on date only or on time or on (date, whatever), etc.
What I don't understand is why you also have the computed datetime column as well. There s no reason to store this value, too. It can easily be calculated when needed.
And if you need to order by datetime, you can use ORDER BY MyDate, MyTime
. With an index on (MyDate, MyTime)
this should be ok. Range datetime queries would also be using that index.
Upvotes: 2
Reputation: 754408
Unfortunately, you didn't mention what version of SQL Server you're using ....
But if you're on SQL Server 2008 or newer, you should turn this around:
your table should have
MyDateTime DATETIME
and then define the "only date" column as
MyDate AS CAST(MyDateTime AS DATE) PERSISTED
Since you make it persisted, it's stored along side the table data (and now calculated every time you query it), and you can easily index it now.
Same applies to the MyTime
column.
Upvotes: 4