https://www.cnblogs.com/onsuccessway/p/3355550.html
在SQLSERVER查询分析器中,当我们用Set Statistics on 语句来统计SQL语句或者存储过程I/O的时候,
SQLSERVER会显示几个概念去词语:逻辑读取,物理读取,预读。
如下:
(1 行受影响)
表 't2'。扫描计数 1,逻辑读取 3282 次,物理读取 44 次,预读 3282 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
那么,这几个词语代表什么意思呢?我们怎么根据这些来了解SQL语句或者存储过程的I/O过程呢?
预读:用于估计信息,去硬盘读取数据到缓存。
物理读:查询计划生成以后,如果发现缓存缺少所需要的数据,让缓存再次去读硬盘数据。如果内存里没有缓存数据或者执行计划(如果SQL语句发生了改变,
那么执行计划将不能重用,需要重新生成新的执行计划),那么SQLSERVER就要去硬盘读取这些数据,这个时候就是物理读取,我们大家都知道,硬盘速度
与内存速度根本不在一个数量级上,所以物理读是比较慢的。
逻辑读:SQLSERVER去内存里的缓存取数据或者执行计划,所以逻辑读是比较快的。
SQLSERVER存储的最小单位是页,每一页大小为8K,即8*1024=8192字节,SQLSERVER对页的读取是原子性的,即要么读完一页,要么完全不读。即使
仅仅要获得一条数据,也要读完该页,而页之间的数据组织结构为B树结构。所以SQLSERVER对于逻辑读,物理读,预读的单位是页。
先来看一个查询:
DBCC DROPCLEANBUFFERS --清空缓存
SET STATISTICS IO ON --开启IO统计
SELECT * FROM SAMPLE --查询
显示消息如下:
(147517 行受影响)
表'SAMPLE'。扫描计数 1,逻辑读取2237次,物理读取6次,预读2226次,lob读取0次
上表的大小事17.406M。
每一页存储的数据是8K=8192字节-96字节(页头)-36字节(行偏移)=8060字节。
17.406*1024*1024/8060约等于2264.
另外表中还有一些非数据占用的空间,因此上式的结果约等于逻辑读次数。
基本上,逻辑读,物理读,预读都等于是扫描了多少个页。
SQLSERVER的查询从理解各种读的步骤来看,可以理解为下图
通过上图来解释下各种读的方式:
SQLSERVER执行一个查询语句的时候,SQLSERVER会执行第一个步骤,即生成查询计划,同时用估计的数据去磁盘读取数据(预读)
,这两个都是第一步,是并行的。SQLSERVER通过这种方式来提高查询性能。
当查询计划生成好以后,开始去缓存读取数据,当发现缓存缺少所需要的数据的时候,让缓存再次去硬盘读取数据(物理读),然后从缓存
中取出所有数据(逻辑读)。
估计的页数可以通过DMV来看到
select pagecount from sys.dm_db_index_physical_stats
(DB_ID('TESTDATACENTER'),OBJECT_ID('SAMPLE'),null,null,'sampled')
显示结果如下:
SQLSERVER就是根据这个数值进行预读的。
如果我们此时再执行上面的查询语句
select * from sample --查询
看到消息如下:
(147517 行受影响)
表'SAMPLE'。扫描计数1,逻辑读取2237次,物理读取0次,预读0次,lob逻辑读取0次。
读者也许不明白了,为什么这次全部都是逻辑读取呢?
答案是因为刚才执行过这样一个查询,执行计划与数据都在缓存当中,所以只需要从缓存中读取就可以了,
不需要再读取硬盘。
本文系自己消化并转载
地址:http://www.studyofnet.com/news/94.html。