问题描述:
今天在解决项目上面的一个问题是。遇到一个非常奇怪的问题:
如下的sql语句
SELECT COUNT
( * ) AS totalnum
FROM
requestbase r
WHERE
EXISTS (
SELECT
1
FROM
requestlog wl
WHERE
wl.requestid= r.id
AND wl.logtype NOT IN ( '402881e50c5b4646010c5b5afd170009', '402881e50c5b4646010c5b5afd17000e' )
AND wl.operator = 'HRMRESOURCEECOLOGYAAAA0000000009'
)
AND r.isdelete= '0'
只是wl.operator = ‘HRMRESOURCEECOLOGYAAAA0000000009’ 的条件不同,执行时间却相差超级多。
问题原因:
通过查阅资料,分析不同条件下的sql执行计划:
以下是执行时间较短的执行计划:
以下是执行时间较长的:
只是ID不一样,但是其执行计划却不一样。
而图二使用了Clustered Index Seek(聚集索引查找),理论上效率应该更高才对。但是此处估计是因为requestbase 表中的数据量比较多(有40多万条),直接使用其聚集索引查找反而效率不如第一个执行计划,第一个执行计划通过 requestlog 的logtype索引将其先限制住。
解决方法:
利用查询提示(Hint)引导语句执行,此处使用的是 OPTIMIZE FOR 提示,引导语句按照相应ID的执行计划执行。
但是个人觉得要慎用。
DECLARE @test NVARCHAR(50)
SET @test='8aa0a19e4c226cbc014c253544ce07cd'
SELECT COUNT
( * ) AS totalnum
FROM
requestbase r
WHERE
EXISTS (
SELECT
1
FROM
requestlog wl
WHERE
wl.requestid= r.id
AND wl.logtype NOT IN ( '402881e50c5b4646010c5b5afd170009', '402881e50c5b4646010c5b5afd17000e' )
AND wl.operator = '8aa0a19e4c226cbc014c253544ce07cd'--'8aa0a19e635e5560016367f40ac106b9'
)
AND r.isdelete= '0'
OPTION(OPTIMIZE FOR(@test='HRMRESOURCEECOLOGYAAAA0000000009'))
遗留问题:
1.requestlog这张表的数据量同样不少?为什么这样的执行计划执行效率高那么多?
2.有没有可能从语句执行上面进行优化?
本人试过使用如下的sql语句进行替换,本以为语句能有稍稍有些优化,但实际效果竟然比上述的语句还要慢200ms左右。
权且留作后续分析吧。
select count(*) from requestbase r , requestlog r1
where
r.id = r1.requestid
and r.ISDELETE = '0'
and r1.operator = 'HRMRESOURCEECOLOGYAAAA0000000004'
and r1.logtype <> '402881e50c5b4646010c5b5afd170009'
and r1.logtype <> '402881e50c5b4646010c5b5afd17000e'