I\'m joining to a table dozens of different times, and every time, I join (or filter) based on the results of a SUBSTRING of one of the columns (it\'s a string, but left-pad
Change the column to two columns - the data you join on and the extra 4 characters. Using parts of a column slows things down as you hve seen
Assuming you have your fields in this format:
00Data0007
000000Data0011
0000Data0015
, you can do the following:
Create a computed column: ndata AS RIGHT(REVERSE(data), LEN(data) - 4)
This will transform your columns into the following:
ataD00
ataD000000
ataD0000
Create an index on that column
Issue this query to search for the string Data
:
SELECT *
FROM mytable
WHERE ndata LIKE N'ataD%'
AND SUBSTRING(ndata, LEN(N'ataD') + 1, LEN(ndata)) = REPLICATE('0', LEN(ndata) - LEN('ataD'))
The first condition will use an index for coarse filtering.
The second will make sure that all leading characters (that became the trailing characters in the computed column) are nothing but zeros.
See this entry in my blog for performance detail:
Update
If you just want an index on SUBSTRING
without changing your schema, creating a view is an option.
CREATE VIEW v_substring75
WITH SCHEMABINDING
AS
SELECT s.id, s.data, SUBSTRING(data, 7, 5) AS substring75
FROM mytable
CREATE UNIQUE CLUSTERED INDEX UX_substring75_substring_id ON (substring75, id)
SELECT id, data
FROM v_substring75
WHERE substring75 = '12345'
Can you re-phrase your filter criteria in terms of a LIKE 'something%' statement? (This is applicable to an index)
Add a calculated column to your table and create an index on this column.
ALTER TABLE MyTable
Add Column CodeHead As LEFT(Code,Len(Code)-4)
Then create an index on this.
CREATE INDEX CodeHeadIdx ON MyTable.CodeHead