贴近SQL语句(记录数接近),在不同库中,查询速度一个快一个慢查,查询快的执行步骤返回的行数和实际行数不一致

相近SQL语句(记录数接近),在不同库中,查询速度一个快一个慢查,查询快的执行步骤返回的行数和实际行数不一致
环境:windows 2008 r2 +sqlserver 2008 sp2
问题:相近SQL语句(记录数接近),在同一服务器上的不同数据库中(两个库的表结构,索引均一致),均使用到了索引,(Index Seek),但查询速度一个快一个慢查,查询快的执行计划中的步骤返回的行数和实际行数不一致,
查询速度快执行步骤和索引信息的如下图:
贴近SQL语句(记录数接近),在不同库中,查询速度一个快一个慢查,查询快的执行步骤返回的行数和实际行数不一致
贴近SQL语句(记录数接近),在不同库中,查询速度一个快一个慢查,查询快的执行步骤返回的行数和实际行数不一致


查询速度慢的执行步骤和索引信息如下图:
贴近SQL语句(记录数接近),在不同库中,查询速度一个快一个慢查,查询快的执行步骤返回的行数和实际行数不一致
贴近SQL语句(记录数接近),在不同库中,查询速度一个快一个慢查,查询快的执行步骤返回的行数和实际行数不一致
帮忙分析一下SET STATISTICS PROFILE ON返回的ROW为何和查询条件下实际的行数不一致?
查询快和慢的原因是什么?需要如何优化?



------解决思路----------------------
查询快的执行计划中的步骤返回的行数和实际行数不一致

一个是估计的,一个是实际的,不同是正常的
------解决思路----------------------
两个库的索引统计信息更新时间不一致,上面那个索引统计信息是2-28号的,建议更新一下索引统计信息

update statistics tableName(indexname)
------解决思路----------------------
这个是EXISTS的短路功能,你快的那个查询,搜索到62行的数据,就找到了,EXISTS为真,条件不会继续执行

你慢的那个,EXISTS并没有搜索到相关数据,整个子查询会全表扫描

EXISTS不适合用于在匹配率低的大表作子查询
------解决思路----------------------
仔细看了一下,楼主说的“SET STATISTICS PROFILE ON返回的ROW为何和查询条件下实际的行数不一致”

查看资料显示SET STATISTICS PROFILE ON返回的ROWS 是执行计划的每一步返回的实际行数
对于执行快(第一个图片)的Rows=【62】,但和Count()统计出来的行数【940300】不一致,但是另外一个库(第三个图片)的却是一致的【835879】 


实际上楼主误解了,rows列确实是返回的列,
你的查询,一个是top 1 id,一个是count(1),最后返回的当然都是1行数据
之前返回的数据行数是聚合操作之前的行数,因为是并行执行的
最开始的索引seek因为是并行执行的,所以executes是12,返回的行数是835879,然后对12个并行的并行的结果集分别作做聚合运算,依旧是executes12次,返回12行(rows)数据(并行),然后对这个12行做聚合运算,返回的是1行(rows)数据
------解决思路----------------------
你这是一个TOP 1有值和一个TOP 1没有值的比对情况,我想借用你的数据,看一下,两个都为没有值的情况,看下执行计划又是怎么样一个情况。
------解决思路----------------------

第2步(即图片第四行)使用WHERE rr.CreateTime BETWEEN '2015-2-16' AND '2015-2-18' 查询 rr表时查找步骤返回的Rows=【62】行,但是实际上这个条件下的记录有【940300】行,那么问题来了,为何第四行查找步骤返回的Rows 不是等于【940300】行

你弄错了吧?


你七楼的截图,查询结果ID是71911940的执行计划是截图中的,940300的无名列是count(*)出来的结果吧
------解决思路----------------------
看你的截图,快的,慢的sql的执行计划都是一样的,数据量也是相差不大,甚至慢的那么数据量还小一点
我怀疑你说的快的是不是在测试环境或者是开发环境测出来的结果,而慢的是在生产环境测试出来的?
你说的快的,第一个截图,统计信息明显没有实时更新,而后一个截图,统计信息就是相对比较新的
要确认快慢是每次都有明显的差异,还是第一次执行差异比较明显,后面再执行快慢差异就不明显了
------解决思路----------------------
从你同表的情况就很明显可以看出,这个是EXISTS的原因了。

这就是EXISTS的短路功能,EXISTS作为相关子查询时,会一直扫描子表,直到为真,即有符合的行记录时。

你那个扫描了62行,就扫描出EXISTS为真,自然就不用继续扫描了,这时实际的扫描行数为62,
如果没有匹配的情况,EXISTS一直扫描子表,直到全表扫描完,才发现没有,这时的扫描行数就是全表记录数
假设,有一个查询,符合值在靠后,这时实际的扫描行数也会很大,就如你#11楼的情况。

而你普通的聚合查询,这个查询一定是扫描全表,或整个索引的

相同条件的查询,作为相关子查询放至EXISTS中和单独聚合查询,两个的扫描行数和数据有很大的关系。

因此,EXISTS不适合用于在匹配率低的大表作子查询,万一匹配很低,那你每个相关子查询都是全表扫描,那时间小伙伴会惊呆的。
------解决思路----------------------
我验证了,ky_min说的是对的

你那个扫描了62行,就扫描出EXISTS为真,自然就不用继续扫描了,这时实际的扫描行数为62,
如果没有匹配的情况,EXISTS一直扫描子表,直到全表扫描完,才发现没有,这时的扫描行数就是全表记录数

但是楼主的问题,一个大表(匹配率低),一个小表,如何连接?
好似乎inner join连接代价要比exists大,楼主可以写一下比较一下
------解决思路----------------------
关于,逻辑读的算法,有高人算在前面了,我就不再赘述了,你可以了解下
http://www.cnblogs.com/CareySon/archive/2011/12/23/2299127.html
其实也只能是算出个大概
你可以大概对比下你11楼两次的行数与逻辑读的比例是一样的。

另外,SQL优化分析语句,我想看下#15楼语句的执行计划。
------解决思路----------------------
从执行计划上,可以看出,这个查询和EXISTS的前两步执行的扫描方法是一样的,要提高效率,把EXISTS换成INNERJOIN 貌似是不可行的

你的截图中,从没挡住的条件上看,你是不是要查询一条userid有存在于ai表的rr表的id

如果有存在的情况,速度应该都不会太慢,
但是不存在的话,相当于要扫描了整个表后才知道,
这个时候,我想应该只有提高Nested Loops连接效率了