Reputation: 1
I have a table similar to this:
CREATE TABLE dbo.SomeTable (Work_ID VARCHAR(9));
I need to be able to run the following query and unfortunately can not change the data type of the Work_ID column:
SELECT Work_ID
FROM dbo.SomeTable
WHERE WorkID >= 100 AND WorkID <=200
This of course will give me an implicite conversion and cause a table scan (several million rows).
My thought was to put the following indexed view on it.
CREATE VIEW [dbo].[vw_Work_ID]
WITH SCHEMABINDING AS
SELECT CAST(q.Work_ID as INT) as Work_ID
FROM dbo.SomeTable q
GO
CREATE UNIQUE CLUSTERED INDEX [cl_vw_Work_ID] ON [dbo].[vw_Work_ID]
(
[Work_ID] ASC
)
GO
When I now run
SELECT Work_ID FROM dbo.vw_Work_ID WHERE WorkID >= 100 AND WorkID <=200
``
I still get IMPLICIT CONVERSION and a table scan. Any solutions?
Upvotes: 0
Views: 144
Reputation:
We can index on the column using the same WHERE conditions as we want to use in the query. When we check with XML Stastics on we see that the query has been run on the index and has not done a table scan. Please see the dbFiddle link for confirmation of the query plan.
SET STATISTICS XML ON;
CREATE TABLE dbo.SomeTable (Work_ID VARCHAR(9));
SELECT * FROM dbo.SomeTable WHERE Work_ID >= '100' AND Work_ID <='200';
create index [cl_vw_Work_ID] on [dbo].[SomeTable](Work_ID) WHERE Work_ID >= '100' AND Work_ID <='200';
SELECT * FROM dbo.SomeTable WHERE Work_ID >= '100' AND Work_ID <='200';
db<>fiddle here
ALTER TABLE dbo.SomeTable ADD num_work_id AS CAST(Work_ID AS INT) ;
create index [cl_vw_Work_ID] on [dbo].[SomeTable](num_work_id) ;
SELECT * FROM dbo.SomeTable WHERE num_work_id >= '100' AND num_work_id <='200';
Work_ID | num_work_id :------ | ----------:
db<>fiddle here
with 4000 rows db<>fiddle here
Upvotes: 0
Reputation: 46203
Use TRY_CAST
instead of CAST
to avoid conversion errors. The resultant value will be NULL
for invalid integer values. Also, add a NOEXPAND
hint so to use the view index:
CREATE TABLE dbo.SomeTable (Work_ID VARCHAR(9));
GO
CREATE VIEW [dbo].[vw_Work_ID]
WITH SCHEMABINDING AS
SELECT TRY_CAST(q.Work_ID as INT) as Work_ID
FROM dbo.SomeTable q;
GO
CREATE UNIQUE CLUSTERED INDEX [cl_vw_Work_ID] ON [dbo].[vw_Work_ID]
(
[Work_ID] ASC
);
GO
INSERT INTO dbo.SomeTable VALUES('111');
INSERT INTO dbo.SomeTable VALUES('xxx');
GO
SELECT *
FROM [dbo].[vw_Work_ID] WITH(NOEXPAND)
WHERE Work_ID = 0;
GO
Upvotes: 0