SQL Sever数据库中,我们一般使用OPTION(RECOMPILE)查询提示(Query Hints)来解决SQL语句或存储过程的参数嗅探问题或某些SQL性能问题,它强制优化器重新编译查询语句,生成新的执行计划。最近在帮同事优化一个复杂视图时,发现这个视图的执行计划一直在变化,有时候生成的一个糟糕执行计划,导致SQL语句性能非常差,现在的问题是系统的Support人员不想修改视图(例如,使用存储过程替换视图),那么在视图View中是否可以使用OPTION(RECOMPILE)来改善偶尔使用了错误的执行计划,导致性能很慢的问题呢?

测试发现,视图内部定义不能使用OPTION(RECOMPILE)查询提示,

create view v_test
as
select * from dbo.test option(recompile) ;
GO
  • 1.
  • 2.
  • 3.
  • 4.

创建上面视图时会报下面错误: Msg 156, Level 15, State 1, Procedure v_test, Line 3 关键字 'option' 附近有语法错误。

其实官方文档[1]中有明确的限制说明,如下所示,只是很多知识点随着时间流逝,慢慢变得模糊不清,需要重拾起来。

视图定义中的 SELECT 子句不能包括下列内容:
• ORDER BY 子句,除非在 SELECT 语句的选择列表中也有一个 TOP 子句。
重要
• ORDER BY 子句仅用于确定视图定义中的 TOP 或 OFFSET 子句返回的行。 ORDER BY 不保证在查询视图时得到有序结果,除非在查询本身中也指定了 ORDER BY。
• INTO 关键字
• OPTION 子句
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

但是我们可以像表一样,在查询语句中使用提示option(recompile)

select * from v_test option(recompile);
  • 1.

另外一种编译视图的方式,就是使用sp_recompile,但是这种方法有一种缺陷,因为查询视图的SQL语句的查询条件中会使用变量,最好在执行阶段重新编译,以便它能获取一个较优或正确的执行计划,而sp_recompile只能手工触发视图重编译,所以不太适合这种场景。

sp_recompile v_test;
  • 1.

参考资料

[1]

1:  https://learn.microsoft.com/zh-cn/sql/t-sql/statements/create-view-transact-sql?view=sql-server-ver16