分析表无索引为什么sp_spaceused 中的index_size不为0

源于csdn论坛的一个提问:

CREATE   TABLE  TUser ( FName  CHAR ( 8000 ), FAge  INT , FSex  bit  )
INSERT   INTO  TUser
SELECT   ' 张三 ' , 18 , 1   UNION   ALL
SELECT   ' 李四 ' , 20 , 1   UNION   ALL
SELECT   ' 王五 ' , 32 , 1   UNION   ALL
SELECT   ' 麻子 ' , 23 , 1

 
通过一个查询看下扫描的数据页:

SET   STATISTICS  IO  ON
SELECT   *   FROM  TUser
/*
(4 行受影响)
表 'TUser'。扫描计数 1,逻辑读取 4 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
*/

可以看到,该查询全部数据是扫了四个数据页,也就是说插入的四行数据,一行为一个page.

 但是我们执行下面的sql,发现index_size为8k:

EXEC  sp_spaceused N ' TUser '
/*
name    rows        reserved    data    index_size    unused
TUser    4              40 KB        32 KB    8 KB        0 KB
*/

 这是为什么,为什么没有建索引,这里却有一个index_size 8k ?

 

下面来看看index_size是怎么来的?
首先想到是的

sp_helptext sp_spaceused

通过查看sp_spaceused的代码,我们找到对于我们这个查询有用的信息代码:

  /*   
 ** Now calculate the summary data.   
 *  Note that LOB Data and Row-overflow Data are counted as Data Pages.  
 
*/
  
 
SELECT    
  
@reservedpages   =   SUM  (reserved_page_count),  
  
@usedpages   =   SUM  (used_page_count),  
  
@pages   =   SUM  (  
   
CASE   
    
WHEN  (index_id  <   2 THEN  (in_row_data_page_count  +  lob_used_page_count  +  row_overflow_used_page_count)  
    
ELSE  lob_used_page_count  +  row_overflow_used_page_count  
   
END   
   ),  
  
@rowCount   =   SUM  (  
   
CASE   
    
WHEN  (index_id  <   2 THEN  row_count  
    
ELSE   0   
   
END   
   )  
 
FROM  sys.dm_db_partition_stats  
 
WHERE   object_id   =   @id ;  
  
 
/*   
 ** Check if table has XML Indexes or Fulltext Indexes which use internal tables tied to this table  
 
*/
  
 
IF  ( SELECT   count ( * FROM  sys.internal_tables  WHERE  parent_id  =   @id   AND  internal_type  IN  ( 202 , 204 ))  >   0    
 
BEGIN   
  
/*   
  **  Now calculate the summary data. Row counts in these internal tables don't   
  **  contribute towards row count of original table.    
  
*/
  
  
SELECT    
   
@reservedpages   =   @reservedpages   +   sum (reserved_page_count),  
   
@usedpages   =   @usedpages   +   sum (used_page_count)  
  
FROM  sys.dm_db_partition_stats p, sys.internal_tables it  
  
WHERE  it.parent_id  =   @id   AND  it.internal_type  IN  ( 202 , 204 AND  p. object_id   =  it. object_id ;  
 
END   
  
 
SELECT    
  name 
=   OBJECT_NAME  ( @id ),  
  rows 
=   convert  ( char ( 11 ),  @rowCount ),  
  reserved 
=   LTRIM  ( STR  ( @reservedpages   *   8 15 0 +   '  KB ' ),  
  data 
=   LTRIM  ( STR  ( @pages   *   8 15 0 +   '  KB ' ),  
  index_size 
=   LTRIM  ( STR  (( CASE   WHEN   @usedpages   >   @pages   THEN  ( @usedpages   -   @pages ELSE   0   END *   8 15 0 +   '  KB ' ),  
  unused 
=   LTRIM  ( STR  (( CASE   WHEN   @reservedpages   >   @usedpages   THEN  ( @reservedpages   -   @usedpages ELSE   0   END *   8 15 0 +   '  KB '

通过上面的代码,我们可以基于我们目前的这个情况(堆表,不含有xml和fulltext,所以上面的202/204那段不用管了)提练出index的page如下算法:

select  index_pagecount = sum (used_page_count) -
sum (in_row_data_page_count  +  lob_used_page_count  +  row_overflow_used_page_count)
from  sys.dm_db_partition_stats  
where   object_id   =   object_id ( ' TUser ' ); 

这个结果是1.再套上index_size的公式:

select  index_size  =   LTRIM  ( STR  (( 1 *   8 15 0 +   '  KB ' )
/*
8k
*/

这就是8k的算法,从下面联机文档上关于sys.dm_db_partition_stats 的解释,可以分析出这个8k是个IAM page.
used_page_count  bigint
用于分区的总页数。计算方法为 in_row_used_page_count + lob_used_page_count + row_overflow_used_page_count

上面我们算index_page时公式为:
sum (used_page_count) -
sum (in_row_data_page_count  +  lob_used_page_count  +  row_overflow_used_page_count)
也就是in_row_used_page_count -in_row_data_page_count
对于这两列,联机文档解释是:

in_row_used_page_count

用于存储和管理分区中的行内数据的总页数。该计数包括非叶 B 树页、IAM 页以及 in_row_data_page_count 列包含的全部页。

in_row_data_page_count

分区中存储行内数据所用的页数。如果分区是堆的一部分,则该值为堆中的数据页数。如果分区是索引的一部分,则该值为叶级别中的页数。(未计入 B 树中非叶页的数目。)以上两种情况都未计入 IAM(索引分配映射)页。
针对我们目前该表的情况,仅是一个堆表,那么可知前者是包含了IAM页,而后者不含有IAM页,那么sp_spaceused中的index_size在这里就是一个IAM(索引分配映射)页。

 

其实这个也可以通过DBCC IND看到:Pagetype=10为IAM PAGE

如有错误,欢迎指正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值