分析表无索引为什么sp_spaceused 中的index_size不为0
2009-10-18 22:25
246 查看
源于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
如有错误,欢迎指正。
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
如有错误,欢迎指正。
相关文章推荐
- 表无索引为什么sp_spaceused 中的index_size不为0
- 重新生成索引存储过程 sp_rebuild_index
- 扩展 sp_helpindex, 增加 INCLUDE 和筛选索引的筛选条件
- 空间索引网格大小无效的解决方法The spatial index grid size is invalid
- How to reduce Index size on disk?减少ES索引大小的一些小手段
- 为什么通过sp & ~(THREAD_SIZE - 1) 可以获取到 task_struct
- 空间索引网格大小无效的解决方法The spatial index grid size is invalid
- 关于重新组织和重新生成索引sp_RefreshIndex的介绍
- Oracle中的index学习 ---理解索引为何物,为什么会使查询变快
- SQL2012 重新组织和新生成索引sp_RefreshIndex
- 关于重新组织和重新生成索引sp_RefreshIndex的介绍
- SQL Server 性能调优3 之索引(Index)的维护
- Shell 命令行,生成当前文件夹目录索引 index.html 文件
- vue项目根目录下index.html中的id="app",与src目录下的App.vue中的id="app"为什么不会冲突
- 什么是索引?为什么要建立索引?并举例说明.(以某一具体的DBMS为例)
- 为什么技术书籍应该有索引?技术书籍怎样做索引
- in 操作为什么不走索引呢
- Sqlserver 2005+:查看索引【index】的【使用情况】:无效的索引、高成本索引
- Oracle 唯一 约束(unique constraint) 与 索引(index) 关系说明
- Git本地库中的索引(Index)及文件状态概述