Db2中"SELECT * FROM TABLE"时返回记录的顺序

有没有想过,发出"select * from table"命令的时候,返回记录的顺序是怎么样的?

不考虑索引,执行计划要走TABSCAN,问题转化为TABSCAN时扫描记录的顺序。 一个直观的想法是按照记录插入的顺序来扫描,然而这种想法是错误的。正确的答案是:和记录在表空间中的存储位置有关系,一个表的数据可能使用了多个数据页(page),编号为page 0, page 1, ... page n;而每个页中可能存放了多条记录,每条记录都占用一个Slot,Slot也是有编号的。TABSCAN扫描的顺序是按照page号从小到大、同一page中按照Slot编号从小到大,也是"SELECT * FROM TABLE"时返回记录的顺序。

先来看一个简单的例子,下面的脚本在数据库mydb中创建了一个4K大小的DMS类型的表空间userspace1和一张表TB1,往表TB1里插入6条记录,其中第2、3、5条记录较大,大小超过page的一半,这样可以确保插入时会分配新的数据页:

$ cat test1.sh 
#!/bin/sh

#prepare a string of length 2402, will be used to insert into TB1
str=`awk 'BEGIN { for(i = 1; i <= 2400; i++) x=x"a"; print "'\''"x"'\''"}'`

db2 "terminate"
db2 "connect to mydb"
db2 "drop tablespace userspace1"
db2 "create tablespace userspace1  pagesize 4K managed by automatic storage"
db2 "CREATE TABLE TB1(id int, name VARCHAR(3990)) in userspace1"

db2 "insert into tb1 values(1,'abc')"
db2 "insert into tb1 values(123, $str)"

db2 "insert into tb1 values(234, $str)"
db2 "insert into tb1 values(2,'abc')"

db2 "insert into tb1 values(345,$str)"
db2 "insert into tb1 values(3,'abc')"
db2 "select id from tb1"

运行脚本,最后的select输出如下,我在每条记录后面补充了db2dart的检查结果以显示其存储位置:

$ sh test1.sh


ID         
-----------
            1    -> Page 0, Slot 4
        123    -> Page 0, Slot 5
        234    -> Page 1, Slot 0
            2    -> Page 1, Slot 1
        345    -> Page 2, Slot 0
            3    -> Page 2, Slot 1

  6 record(s) selected.


==================================

test1中,TABSCAN的结果和Insert的顺序完全一致。现在再做另一个测试,test2.sh里面的SQL语句内容、顺序和test1.sh中完全一样,只不过在每次insert之前,要断开数据库的连接,并重连:

$ cat test2.sh
#!/bin/sh

#prepare a string of length 2402, will be used to insert into TB1
str=`awk 'BEGIN { for(i = 1; i <= 2400; i++) x=x"a"; print "'\''"x"'\''"}'`

db2 "terminate"
db2 "connect to mydb"
db2 "drop tablespace userspace1"
db2 "create tablespace userspace1  pagesize 4K managed by automatic storage"
db2 "CREATE TABLE TB1(id int, name VARCHAR(3990)) in userspace1"
db2 "insert into tb1 values(1,'abc')"

db2 "connect reset"
db2 "connect to mydb"
db2 "insert into tb1 values(123, $str)"

db2 "connect reset"
db2 "connect to mydb"
db2 "insert into tb1 values(234, $str)"

db2 "connect reset"
db2 "connect to mydb"
db2 "insert into tb1 values(2,'abc')"

db2 "connect reset"
db2 "connect to mydb"
db2 "insert into tb1 values(345,$str)"

db2 "connect reset"
db2 "connect to mydb"
db2 "insert into tb1 values(3,'abc')"
db2 "select id from tb1"

运行结果如下:可以看到,比较短的三条记录都放到了Page 0上

$ sh test2.sh

ID         
-----------
            1    -> Page 0, Slot 4
        123    -> Page 0, Slot 5
            2    -> Page 0, Slot 6
            3    -> Page 0, Slot 7
        234    -> Page 1, Slot 0
        345    -> Page 2, Slot 0

  6 record(s) selected.
  
========================

通过上面两个测试可以看到,TABSCAN时扫描记录的顺序和记录插入顺序没有必然联系,而是与记录在表空间中的存储顺序有关,而存储顺序与 INSERT 的内部算法相关,如果想了进一步了解,请参考下面Db2专家郝庆运写的两篇文章:

利用 db2dart 工具来理解 DB2 数据存储方式

深入理解 DB2 INSERT 内部机制以及表空间分配机制


注:本文之研究内容和结果,仅限于DMS表空间的情形并得到db2dart和db2trace工具的验证,对于SMS表空间未做研究!测试环境为linux, Db2 9.7 & Db2 10.5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值