在SQL 2008中,我尝试在查询中使用简单的用户定义函数,但SQL服务器不使用索引,并且查询执行时间很长。 有没有办法告诉SQL服务器函数的结果可以在查询中用作简单的数字/文字,它可以使用索引吗?
例如,有三种情况:
1)简单选择(使用索引):
SELECT * FROM [ORDERS] WHERE [CarId] = 5
2)选择变量(不使用索引):
DECLARE @five int = 5;
SELECT * FROM [ORDERS] WHERE [CarId] = @five
2.1)选择变量,(使用索引):
DECLARE @five int = 5;
SELECT * FROM [ORDERS] WHERE [CarId] = @five OPTION (RECOMPILE)
3)在查询中选择用户函数调用(不使用索引)
IF OBJECT_ID (N'dbo.five', N'FN') IS NOT NULL
DROP FUNCTION dbo.five;
CREATE FUNCTION dbo.five()
RETURNS int
WITH SCHEMABINDING
AS
BEGIN
RETURN 5;
END;
SELECT * FROM [ORDERS] WHERE [CarId] = dbo.five()
3.1)使用索引,但计划不是最优的
SELECT * FROM [ORDERS] with (index(IDX_CARID)) WHERE [CarId] = dbo.five()
表脚本:
CREATE TABLE [ORDERS](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Phone] [varchar](15) NULL,
[dtBegin] [datetime] NULL,
[dtEnd] [datetime] NULL,
[CarID] [int] NULL,
CONSTRAINT [PK_ORDERS] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = OFF,
FILLFACTOR = 90
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [ORDERS] WITH CHECK ADD CONSTRAINT [FK_CARS_ORDERS] FOREIGN KEY([CarID])
REFERENCES [CARS] ([ID])
ON DELETE SET NULL
GO
ALTER TABLE [ORDERS] CHECK CONSTRAINT [FK_CARS_ORDERS]
GO
指数代码:
CREATE NONCLUSTERED INDEX [IDX_CARID] ON [ORDERS]
(
[CarID] ASC
)WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
DROP_EXISTING = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = OFF,
FILLFACTOR = 90
) ON [PRIMARY]
答案 0 :(得分:0)
在选择所有字段时,非聚集索引在给定示例中仅为CarID,因此它将始终扫描而不是搜索, 检查在查询下执行的执行计划:
SELECT CarId FROM [ORDERS] WHERE [CarId] = dbo.five()
如果您希望所有其他值都必须包含在非聚簇索引中,则可以创建一个非聚集索引,该索引以所需的选定列为目标
答案 1 :(得分:0)
为什么您认为3.1执行计划不是查询最佳计划的最佳查询。
如果您正确观察到索引扫描已被搜索替换,则计划中唯一的问题是密钥查找。当您在查询中有*时,键查找会弹出计划中
Select * from table where conditions
如果您使用特定的列列表,那么性能将仅是最佳的,而不是选择*,但我仍然不会说密钥查找组件将被减少,但这一切都取决于您选择的要求。
由于