首页 > 开发 > 综合 > 正文

Index--过滤索引和参数化

2024-07-21 02:50:21
字体:
来源:转载
供稿:网友
Index--过滤索引和参数化

--============================================

领导指点我去给某台数据库调优下,结果屁颠屁颠地干完,还自我感觉良好,刚刚别人博客时,才发现自己踩坑了!!

--============================================

有一很简单查询SQL,类似:

SELECT * FROM TB1WHERE C1='C1'AND C2='C2'AND C3='C3'AND C4='C4'

发现该SQL执行很慢,一看是全表扫描,便考虑WHERE条件中每列的可选择行,表中有700W数据

查看C1的可选择性

SELECT COUNT(DISTINCT C1) FROM TB1 WITH(NOLOCK)

发现C1列去重后有140W,选择性比较高,优先作为索引的第一个键值列。

SELECT TOP(100) C1,COUNT(1) AS RcountFROM TB1GROUP BY C1ORDER BY Rcount

结果发现C1列中值为"无效"的行有几十万条,其余值最多也才300多条。这就让我纠结了,数据分布不均匀,很容易导致参数嗅探的问题,赶快讯询问开发,确认是否会使用“无效”来查询,得到明确答复不会使用(无用的数据没有删除而修改值为无效,好霸气的做法),于是乎,过滤索引瞬间冒出来

CREATE INDEX IDX_TB1_C1ON TB1(C1)WHERE C1<>'无效'WITH(MAXDOP=6)

多么完美的解决方案啊,自我感觉良好中。。。-------------------------------------------------------------------------------

过了两小时,加查索引使用情况

SELECT * FROM sys.dm_db_index_usage_statsWHERE database_id = DB_ID()AND object_id=OBJECT_ID('TB1')

发现索引完全没有被使用,不可能啊,再次检查SQL脚本

(@P0 NVARCHAR,@P1 int,@P2 int,@P3 int) SELECT * FROM TB1WHERE C1=@P0AND C2=@P1AND C3=@P2AND C4=@P3

以我多年的经验,我武断地判断隐式转换导致,因为这问题出现不是一次两次啦,C1列时VARCHAR类型的,于是乎,通知开发改程序,收工!!

--==================================================================================

真的收工了吗?当然没有,要不然我还啰嗦啥呢

在Amaranthus的大作中有这样一句话:

在没有recompile提示之下,过滤索引和过滤统计信息不会被应用到参数化的字段过滤。(In the absence of a RECOMPILE hint, filtered indexes and statistics will not be used in conjunction with parameterization that refers to the filter column.)

对于参数化的过滤条件,查询优化器无法确认未来传入的具体值满足过滤索引中的过滤条件,因此不会考虑使用过滤索引

解决办法:

1. 将索引过滤条件移除(由于查询不会使用“无效”,因此不会出现参数嗅探问题)

2. 在查询条件中显示加入过滤条件(SQL 中加入 AND C1<>'无效',有点画色添足的感觉)

吭只有踩过才知道啊!!!

--====================================================================================

妹子


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表