I have a table with the following structure
CREATE TABLE tbl
(
id int NOT NULL,
field_ID int NULL,
field_VALUE float NULL,
field_TIMESTAMP datetime NULL,
field_QUALITY smallint NULL,
-- more <fields> columns, for each all of the four above will be repeated
CONSTRAINT pk_id PRIMARY KEY (id)
);
This table structure is the result of an external program and I cannot change it except for some minor changes. Currently the table has roughly 3 million rows.
Now I usually select data for a certain timerange and quality threshold:
SELECT *
FROM tbl
WHERE
field_TIMESTAMP >= '2023-04-01 00:00:00' AND
field_TIMESTAMP < '2023-04-08 00:00:00' AND
field_QUALITY >= 192
This query takes roughly 3 minutes to run. To solve this issue I created a nonclustered index on the timestamp column which should be my primary filter:
CREATE NONCLUSTERED INDEX tbl_idx ON tbl (field_TIMESTAMP);
Unfortunately the execution plan shows, that the optimiser does not use my index when executing the query and it still runs for ~3 minutes. However, when I manually force it to use the index the query succeeds in 0.3 seconds:
SELECT *
FROM tbl
WITH (INDEX(tbl_idx))
WHERE
field_TIMESTAMP >= '2023-04-01 00:00:00' AND
field_TIMESTAMP < '2023-04-08 00:00:00' AND
field_QUALITY >= 192
I do not like to force the query compiler on an index, since things might change and it would require manually modifying all queries.
Is there a reason, that SQL Server decides against using the index? I tried updating the table statistics (UPDATE STATISTICS tbl WITH FULLSCAN
), but nothing changed. Can I improve my SELECT
in some way?
Update
I now have the following indices created
CREATE NONCLUSTERED INDEX tbl_TIMESTAMP_IDX
ON tbl (field_TIMESTAMP ASC);
CREATE NONCLUSTERED INDEX tbl_VALUE_IDX
ON tbl (field_TIMESTAMP ASC)
INCLUDE (field_VALUE);
CREATE NONCLUSTERED INDEX tbl_quality_idx
ON tbl (field_QUALITY ASC);
CREATE NONCLUSTERED INDEX tbl_filter_timestamp_idx
ON tbl (field_TIMESTAMP ASC)
WHERE ([field_QUALITY] >= (192));
My observations (where clause simplified):
Query:
SELECT field_VALUE, field_TIMESTAMP
FROM tbl
WHERE field_TIMESTAMP > 'A'
AND field_TIMESTAMP < 'B'
Uses the INCLUDE
d Index, but would require to have every column that I need in the index.
These queries do still not use any index, independent whether I have field_QUALITY
in the WHERE
clause or not.