IMO the anti practice is to use scalar functions in the WHERE clause of a query, without any other filters which would give SQL good selectivity.
e.g.
SELECT columns
FROM [table]
WHERE dbo.myFunc(col1) = 55
Will usually result in a table scan, irrespective of the indexing on col1
.
As the others have pointed out, there are exceptions, e.g. it is possible to use deterministic, schema bound functions in an indexed computed column.
As an example, consider the following deterministic function:
CREATE FUNCTION dbo.myFunc(@id int)
returns int
WITH SCHEMABINDING
AS
BEGIN
return (@id + 1)
END
Given the table (with the MSSQL default PK = Clustered Index)
CREATE TABLE MyTable
(
ID INT Identity (1,1),
SomeOtherColumn VARCHAR(50),
CONSTRAINT PK_MyTable PRIMARY KEY(ID)
)
Populated with ~100k records
select * from MyTable where ID < 100 -- Index Seek :)
However, running the scalar function doesn't get the benefit of the Clustered Index
select * from MyTable where dbo.MyFunc(Id) < 100 -- Index Scan :(
Using the scalar func as a basis for a computed column
alter table MyTable add Computed as dbo.MyFunc(ID)
select * from MyTable where Computed < 100 -- Still Index Scan :(
-- However, because the Computed column is deterministic and schema bound, it can be indexed:
CREATE INDEX IX1_MyTable on MyTable(Computed)
select * from MyTable where Computed < 100 -- Index Seek :)
Interestingly enough, applying the function now results in an index seek (SQL 2008R2)
select * from MyTable where dbo.MyFunc(ID) < 100 -- Index Seek :)