来看看多列过滤是如何估计返回的行数
use AdventureWorks go --把毫秒全置为0,便于看到效果 update dbo.DatabaseLog set PostTime=cast(CONVERT(varchar,PostTime,120) as datetime) update statistics DatabaseLog with fullscan --创建event索引 create index idx_event on dbo.DatabaseLog(Event) with(online=on)
select * from dbo.DatabaseLog where PostTime='2006-04-26 11:44:31.000' and event='CREATE_TABLE' OPTION ( QUERYTRACEON 3604, QUERYTRACEON 9292, QUERYTRACEON 9204 )
如下的执行计划:
idx_postTime 估计返回的行数为56,来自于统计信息的直方图:
idx_event 估计返回行数为69,也是来自直方图:
那merge Join预估返回的行数10怎么算出来的?merge join 返回的结果应该是idx_postTime结果集,
idx_event结果集的交集。databaselog的行数为389行。
merge join 返回的行数: (56./389)*(69./389)*389=9.933052046574,优化器据此估算merge join
操作符返回的行数。
优化器在运行期间,确实是加载了idx_postTime/idx_event上的统计信息,如下图所示:
同时注意,key_Lookup操作符,预估返回的行数是一行,这个行数是执行一次返回的行数,而这个key_lookup操作执行了56次,所以实际
返回的行数为56行,预估行数=实际行数,如下图所示:
2.来看下面SQL返回的行数:
dbcc FreeProcCache select * from dbo.DatabaseLog where PostTime='2006-04-26 11:44:31.000' or event='CREATE_TABLE' OPTION ( QUERYTRACEON 3604, QUERYTRACEON 9292, QUERYTRACEON 9204 )
这个是全表扫描,如图所示:
这个预估的行数:postTime 返回的56+event 返回的69-交集的部分9.933052046574=115.067行,
其中,扫描全表时也加载了postTime/event上手动新建的统计信息,如图所示:
总结:对于单独的列上建立的索引,优化器根据每个列上的统计信息来预估返回的行数,无论后续执行时是访问索引还是访问基表获得数据!