--============================================
领导指点我去给某台数据库调优下,结果屁颠屁颠地干完,还自我感觉良好,刚刚别人博客时,才发现自己踩坑了!!
--============================================
有一很简单查询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<>'无效',有点画色添足的感觉)
吭只有踩过才知道啊!!!
--====================================================================================
妹子