convert 和 cast 在 where 条件中对索引列进行类型转换会导致索引失效,引发 table scan 或 index scan;应避免在列上转换,改为在参数侧转换或使用范围查询。

SQL Server 中 CONVERT 和 CAST 导致索引失效的典型表现
视图查询突然变慢,执行计划里出现 Table Scan 或 Index Scan 而不是预期的 Index Seek,尤其在 WHERE 条件里对字段做了 CONVERT 或 CAST —— 这基本就是隐式/显式类型转换拦住了索引下推。
常见诱因:WHERE CONVERT(VARCHAR(10), create_time, 120) = '2024-01-01',哪怕 create_time 是 DATETIME 且有索引,SQL Server 也无法用索引快速定位;同理,WHERE id = CONVERT(INT, @input)(@input 是 VARCHAR)也会让 id 列索引失效。
- 优先把转换移到参数侧:用
WHERE create_time >= '2024-01-01' AND create_time 替代字符串截取比较 - 避免在索引列上做任何函数操作,包括
LEFT()、SUBSTRING()、UPPER()—— 视图定义里尤其容易忽略这点 - 检查视图底层 SELECT 中是否用了计算列或表达式作为 JOIN 或 FILTER 字段,它们会直接破坏 SARGability
在视图中安全使用 WITH (INDEX=...) 提示的限制条件
INDEX 提示不能直接写在视图定义里,只能在查询视图时加。但强行指定索引未必生效,甚至可能被优化器忽略 —— 特别当提示的索引不覆盖查询所需列(导致需要 Key Lookup)、或统计信息严重过期时。
更现实的用法是配合 FORCESEEK 或 FORCESCAN,它们比具体索引名更稳定:
-
SELECT * FROM my_view WITH (FORCESEEK)比WITH (INDEX=IX_date)更可能触发 Seek,尤其当存在多个索引时 - 如果视图含多个表 JOIN,提示只对单个表生效:
SELECT * FROM my_view t1 WITH (FORCESEEK) INNER JOIN other_table t2 ON ... - SQL Server 2016+ 支持
USE HINT('DISABLE_OPTIMIZER_ROWGOAL')等全局 Hint,但视图场景下慎用——它会影响整个查询树,可能让其他分支退化
视图嵌套 + 参数化查询时,OPTION(RECOMPILE) 的实际效果
当视图被用于存储过程或带参数的查询(如 SELECT * FROM my_view WHERE status = @status),而 @status 取值差异极大(99% 是 'A',1% 是 'Z'),默认计划复用会导致次优执行路径。此时在外部查询加 OPTION(RECOMPILE) 往往比改视图本身更有效。
- 它让每次执行都生成新计划,能真正感知参数值分布,从而选择是否走索引、是否并行
- 代价是编译开销,高频小查询(毫秒级)可能得不偿失;建议先用
sys.dm_exec_query_stats查看该语句的plan_generation_num是否频繁变化 - 注意:视图定义里不能写
OPTION,必须加在外层查询末尾,且不能和WITH (NOLOCK)等表提示混用在同一语句级别
为什么 SCHEMABINDING 对视图执行计划有实质性影响
没加 SCHEMABINDING 的视图,SQL Server 无法确认底层表结构是否稳定,会禁用很多优化机会 —— 比如跳过某些 JOIN 消除、延迟聚合下推,甚至拒绝为视图列生成统计信息。
- 加了之后,视图所依赖的列不能被删或改类型,但换来的是更激进的优化:执行计划里可能出现
Compute Scalar提前折叠、Filter下推到扫描节点内部 - 必须同时满足:所有引用对象用两段名(
dbo.table)、函数只能用确定性函数(GETDATE()不行,ISNULL()可以) - 如果你的视图里用了
SELECT *或未限定 schema 的对象,CREATE VIEW ... WITH SCHEMABINDING会直接报错:The view's definition contains an invalid reference to object 'xxx'
复杂点在于:一旦加了 SCHEMABINDING,后续改底层表就受约束,而很多人只在性能出问题时才回头补这个选项,结果发现改不了表结构 —— 这个绑定关系,从第一天建视图就得想清楚。










