列顺序测试

大家在做表设计的时候通常对表中列的排列顺序没有过多注意,但是其实越常用的列,它的位置越靠前,则查询速度越快。

因为每个block里面存储了row directory (每行数据在块中的位移地址)而没有存放column的位移
所以只能根据column#通过扫描row header 以及 column data 来获取相应的列值
越靠后的列,需要计算的越多

建立测试表col_test

  1. declare
  2. v_sql varchar2(4000) ;
  3. begin
  4. v_sql := 'create table col_test (' ;
  5. for i in 1 .. 100 loop
  6. v_sql := v_sql || 'id'||i||' number ,' ;
  7. end loop ;
  8. v_sql := substr(v_sql,1,length(v_sql)-1) || ') ' ;
  9. execute immediate v_sql ;
  10. end ;
  11. /
  12. _dexter@DAVID> desc col_test ;
  13. Name                                                  Null?    Type
  14. ----------------------------------------------------- -------- --------------
  15. ID1                                                            NUMBER
  16. ID2                                                            NUMBER
  17. ID3                                                            NUMBER
  18. ID4                                                            NUMBER
  19. ID5                                                            NUMBER
  20. ....
  21. ID99                                                           NUMBER
  22. ID100                                                          NUMBER

复制代码

初始化数据100w

  1. declare
  2. v_sql varchar2(4000) ;
  3. begin
  4. v_sql := 'insert into  col_test select ' ;
  5. for i in 1 .. 100 loop
  6. v_sql := v_sql || ' 1 ,' ;
  7. end loop ;
  8. v_sql := substr(v_sql,1,length(v_sql)-1) || ' from dual connect by level <= 1000000 ' ;
  9. execute immediate v_sql ;
  10. commit ;
  11. end ;
  12. /

复制代码

测试耗时

  1. declare
  2. n       number ;
  3. begin_t pls_integer ;
  4. end_t   pls_integer ;
  5. v_Sql   varchar2(4000) ;
  6. begin
  7. for i in 1 .. 101 loop
  8. begin_t := dbms_utility.get_time ;
  9. if i = 1 then
  10. v_sql := 'select count(*) from col_test' ;
  11. else
  12. v_sql := 'select count(id'||(i-1)||') from col_test' ;
  13. end if ;
  14. execute immediate v_sql into n ;
  15. end_t   := dbms_utility.get_time ;
  16. dbms_output.put_line('Col'||(i-1)||' : '||(end_t-begin_t)*10);
  17. end loop ;
  18. end ;
  19. /
  20. --下面的单位为毫秒
  21. _dexter@DAVID> /
  22. Col0 : 150
  23. Col1 : 140
  24. Col2 : 110
  25. Col3 : 100
  26. Col4 : 100
  27. Col5 : 110
  28. Col6 : 110
  29. Col7 : 110
  30. Col8 : 110
  31. Col9 : 120
  32. Col10 : 130
  33. Col11 : 120
  34. Col12 : 110
  35. Col13 : 120
  36. Col14 : 120
  37. Col15 : 120
  38. Col16 : 130
  39. Col17 : 120
  40. Col18 : 160
  41. Col19 : 130
  42. Col20 : 140
  43. Col21 : 130
  44. Col22 : 140
  45. Col23 : 140
  46. Col24 : 140
  47. Col25 : 130
  48. Col26 : 160
  49. Col27 : 150
  50. Col28 : 140
  51. Col29 : 150
  52. Col30 : 150
  53. Col31 : 160
  54. Col32 : 180
  55. Col33 : 160
  56. Col34 : 160
  57. Col35 : 160
  58. Col36 : 160
  59. Col37 : 170
  60. Col38 : 180
  61. Col39 : 170
  62. Col40 : 170
  63. Col41 : 180
  64. Col42 : 180
  65. Col43 : 170
  66. Col44 : 210
  67. Col45 : 190
  68. Col46 : 180
  69. Col47 : 180
  70. Col48 : 190
  71. Col49 : 210
  72. Col50 : 190
  73. Col51 : 190
  74. Col52 : 200
  75. Col53 : 200
  76. Col54 : 230
  77. Col55 : 200
  78. Col56 : 210
  79. Col57 : 200
  80. Col58 : 210
  81. Col59 : 220
  82. Col60 : 210
  83. Col61 : 210
  84. Col62 : 220
  85. Col63 : 240
  86. Col64 : 220
  87. Col65 : 220
  88. Col66 : 220
  89. Col67 : 230
  90. Col68 : 270
  91. Col69 : 220
  92. Col70 : 230
  93. Col71 : 230
  94. Col72 : 270
  95. Col73 : 230
  96. Col74 : 240
  97. Col75 : 240
  98. Col76 : 250
  99. Col77 : 240
  100. Col78 : 260
  101. Col79 : 260
  102. Col80 : 280
  103. Col81 : 250
  104. Col82 : 250
  105. Col83 : 250
  106. Col84 : 250
  107. Col85 : 260
  108. Col86 : 260
  109. Col87 : 260
  110. Col88 : 290
  111. Col89 : 260
  112. Col90 : 270
  113. Col91 : 280
  114. Col92 : 280
  115. Col93 : 280
  116. Col94 : 270
  117. Col95 : 310
  118. Col96 : 270
  119. Col97 : 310
  120. Col98 : 290
  121. Col99 : 290
  122. Col100 : 280
  123. PL/SQL procedure successfully completed.

复制代码

可以看到耗时是线性增加的,所以在做表设计的时候,应该注意建表时的列的排列顺序,将常用的列放在靠前的位置

null值测试

关于null值的存储,可以查看我的另外一篇帖子http://www.itpub.net/thread-1718328-1-1.html
因为基于它的存储原理,一个rowpiece中,如果列后面的值都为空,则不再占用存储空间,并且 rowheader cc(Column Count) 也不会将其记录到上面,
,但是这一行的rowpiece中第二列不为空,第三、四、五列为空
cc会记为2
个字节的存储空间
null
值在表中的位置除了影响存储空间,还会影响查询,因为在扫描数据的时候
可以根据cc的个数来确定是否需要扫描column data的数据
感兴趣的可以做一下测试
100
列为有值,其他都为null

下面是测试内容:

建立测试表null_test

  1. declare
  2. v_sql varchar2(4000) ;
  3. begin
  4. v_sql := 'create table null_test (' ;
  5. for i in 1 .. 100 loop
  6. v_sql := v_sql || 'id'||i||' number ,' ;
  7. end loop ;
  8. v_sql := substr(v_sql,1,length(v_sql)-1) || ') ' ;
  9. execute immediate v_sql ;
  10. end ;
  11. /

复制代码

初始化数据100w

  1. insert into null_test(id50) select 100 from dual connect by level <= 1000000 ; commit ;

复制代码

测试

  1. declare
  2. n       number ;
  3. begin_t pls_integer ;
  4. end_t   pls_integer ;
  5. v_Sql   varchar2(4000) ;
  6. begin
  7. for i in 1 .. 101 loop
  8. begin_t := dbms_utility.get_time ;
  9. if i = 1 then
  10. v_sql := 'select count(*) from null_test' ;
  11. else
  12. v_sql := 'select count(id'||(i-1)||') from null_test' ;
  13. end if ;
  14. execute immediate v_sql into n ;
  15. end_t   := dbms_utility.get_time ;
  16. dbms_output.put_line('Col'||(i-1)||' : '||(end_t-begin_t)*10);
  17. end loop ;
  18. end ;
  19. /
  20. --测试结果
  21. dexter@FAKE> /
  22. Col0 : 60
  23. Col1 : 80
  24. Col2 : 80
  25. Col3 : 90
  26. Col4 : 90
  27. Col5 : 100
  28. Col6 : 100
  29. Col7 : 100
  30. Col8 : 120
  31. Col9 : 110
  32. Col10 : 120
  33. Col11 : 130
  34. Col12 : 130
  35. Col13 : 140
  36. Col14 : 150
  37. Col15 : 160
  38. Col16 : 160
  39. Col17 : 160
  40. Col18 : 170
  41. Col19 : 170
  42. Col20 : 170
  43. Col21 : 180
  44. Col22 : 180
  45. Col23 : 180
  46. Col24 : 190
  47. Col25 : 190
  48. Col26 : 200
  49. Col27 : 200
  50. Col28 : 200
  51. Col29 : 200
  52. Col30 : 200
  53. Col31 : 210
  54. Col32 : 210
  55. Col33 : 220
  56. Col34 : 220
  57. Col35 : 230
  58. Col36 : 220
  59. Col37 : 220
  60. Col38 : 230
  61. Col39 : 240
  62. Col40 : 240
  63. Col41 : 230
  64. Col42 : 240
  65. Col43 : 250
  66. Col44 : 250
  67. Col45 : 250
  68. Col46 : 260
  69. Col47 : 260
  70. Col48 : 270
  71. Col49 : 260
  72. Col50 : 270
  73. Col51 : 70
  74. Col52 : 80
  75. Col53 : 70
  76. Col54 : 70
  77. Col55 : 80
  78. Col56 : 70
  79. Col57 : 70
  80. Col58 : 80
  81. Col59 : 70
  82. Col60 : 70
  83. Col61 : 70
  84. Col62 : 70
  85. Col63 : 80
  86. Col64 : 80
  87. Col65 : 70
  88. Col66 : 70
  89. Col67 : 70
  90. Col68 : 80
  91. Col69 : 70
  92. Col70 : 70
  93. Col71 : 70
  94. Col72 : 80
  95. Col73 : 70
  96. Col74 : 70
  97. Col75 : 70
  98. Col76 : 80
  99. Col77 : 70
  100. Col78 : 70
  101. Col79 : 70
  102. Col80 : 80
  103. Col81 : 70
  104. Col82 : 70
  105. Col83 : 80
  106. Col84 : 70
  107. Col85 : 70
  108. Col86 : 70
  109. Col87 : 80
  110. Col88 : 70
  111. Col89 : 70
  112. Col90 : 80
  113. Col91 : 70
  114. Col92 : 70
  115. Col93 : 70
  116. Col94 : 80
  117. Col95 : 70
  118. Col96 : 70
  119. Col97 : 70
  120. Col98 : 70
  121. Col99 : 70
  122. Col100 : 80
  123. PL/SQL procedure successfully completed.

复制代码

列开始到最后都维持到一个稳定的值
线性增加是因为Oracle 数据库会不断扫描row header 以及 column data 计算要查找的列的位移值
列开始,则可以直接扫描row header CC 个数即可拿到要查找的列的值(null),所以节省了大量扫描column data部分的时间,也证实了上面提出的观点
所以设计表的时候,尽量把会存储null值的列放在表的末尾

为了加深印象,我们使用bbed抽出一条数据来看一下它在block中到底是怎样存储的,加深一下印象

  1. dexter@FAKE> select dbms_rowid.rowid_relative_fno(t.rowid) as "FNO#",
  2. 2         dbms_rowid.rowid_block_number(t.rowid) as "BLK#",
  3. 3         dbms_rowid.rowid_row_number(t.rowid) as "ROW#"
  4. 4    from dexter.null_test t
  5. 5   where rownum<2 ;
  6. FNO#       BLK#       ROW#
  7. ---------- ---------- ----------
  8. 6        284          0
  9. BBED> set dba 6,284
  10. DBA             0x0180011c (25166108 6,284)
  11. BBED> p *kdbr[0]
  12. rowdata[4675]
  13. -------------
  14. ub1 rowdata[4675]                           @5878     0x2c
  15. BBED> set offset 5878
  16. OFFSET          5878
  17. BBED> dump /v offset 5878 count 58
  18. File: /u01/apps/oracle/oradata/fake/gg_trans201.dbf (6)
  19. Block: 284     Offsets: 5878 to 5935  Dba:0x0180011c
  20. -------------------------------------------------------
  21. 2c0032ff ffffffff ffffffff ffffffff l ,.2.............
  22. ffffffff ffffffff ffffffff ffffffff l ................
  23. ffffffff ffffffff ffffffff ffffffff l ................
  24. ffffffff 02c2022c 0032              l .....Â.,.2
  25. <16 bytes per line>

复制代码

大家一定对count 58 产生疑问,请继续看下去

row header 2c0032
它包括:
2c=flag=00101100=--H-FL--=header+first+last
00=lb itl slot 0x00
32=cc column count = 16x3+2=50
和列值c202

  1. dexter@FAKE> select dump(100,16) from dual ;
  2. DUMP(100,16)
  3. -----------------
  4. Typ=2 Len=2: c2,2

复制代码

so 3+49+1+2=55
个字节是下一行的row header : 2c 0032

LB

ITL

CC

COL#1 value

COL#2-49 value

COL#50 length

COL#50 value

COL#51 value

COL#52-100 value

2C

00

32

FF

FF

02

C202

FF

FF

附录:

rowpiece构成

可以参考官方文档中的说明
图12-7

row piece header的时候),cluster key (cluster table)
个字节(状态、itl槽位、column个数)

cluster table的存储情况会在其他章节中介绍
列的存储

http://www.itpub.net/thread-1719026-1-1.html

LB说明

KCHDFLPN
K=Cluster key                    (用来表示cluster key)
C=Cluster table member    (当表中拥有cluster时使用此标识)
H=Head of row piece         (含有Rowpiece header)
D=Delete row                   (表示已经删除)
F=First data piece             (Rowpiece 的第一个piece)
L=Last data piece              (Rowpiece 的最后一个piece,Rowchain或者列个数大于253时候会出现)
P=First column continues from previous piece  (没有重现过)
N=Last column continues in next piece            (没有重现过)

Oracle 列顺序测试的更多相关文章

  1. ORACLE中查询语句的执行顺及where部分条件执行顺序测试

    Oracle中的一些查询语句及其执行顺序 原文地址:https://www.cnblogs.com/likeju/p/5039115.html 查询条件: 1)LIKE:模糊查询,需要借助两个通配符, ...

  2. oracle调整表中列顺序

    有一个哥们提出一个问题: 有个表,创建时候的列顺序是a,b,c 如何使用select * 的时候,让列的显示顺序是a,c,b 而且任性地必须使用select *来查询,且不能重建表. 假设有个表tes ...

  3. SQL Server 执行计划利用统计信息对数据行的预估原理二(为什么复合索引列顺序会影响到执行计划对数据行的预估)

    本文出处:http://www.cnblogs.com/wy123/p/6008477.html 关于统计信息对数据行数做预估,之前写过对非相关列(单独或者单独的索引列)进行预估时候的算法,参考这里. ...

  4. SQL Server创建复合索引时,复合索引列顺序对查询的性能影响

    说说复合索引 写索引的博客太多了,一直不想动手写,有一下两个原因:一是觉得有炒剩饭的嫌疑,有兄弟曾说:索引吗,只要在查询条件上建索引就行了,真的可以这么暴力吗?二来觉得,索引是个非常大的话题,很难概括 ...

  5. Oracle列自增-12c

    在ORACLE 12C以前的版本中,如果要实现列自增长,需要通过序列+触发器实现,到了12C ORACLE 引进了Identity Columns新特性,从而实现了列自增长功能. 一.Identity ...

  6. Oracle列自增实现(2)-Identity Columns in Oracle Database 12c Release 1 (12.1)

    Oracle列自增-Identity Columns in Oracle Database 12c Release 1 (12.1) 在ORACLE 12C以前的版本中,如果要实现列自增长,需要通过序 ...

  7. oracle列自增实现(1)-Sequence+Trigger实现Oracle列自增

    Sequence+Trigger实现Oracle列自增 序列的语法格式为: CREATE SEQUENCE 序列名 [INCREMENT BY n] [START WITH n] [{MAXVALUE ...

  8. mysql索引之七:组合索引中选择合适的索引列顺序

    组合索引(concatenated index):由多个列构成的索引,如create index idx_emp on emp(col1, col2, col3, ……),则我们称idx_emp索引为 ...

  9. Oracle Flushback 学习测试

    Oracle Flushback 学习测试:三思笔记 Flashback恢复 从9i开始,利用oracle查询的多版本一致的特点,实现从回滚段中读取一定时间内在表中操作的数据,被称为 flashbac ...

随机推荐

  1. 修改SSH端口为21

    在交流群里面有一位兄弟问到能否将ssh端口号修改为21端口,后来经过测试可以设置,具体步骤如下: 一.修改ssh配置文件的默认端口 #vim /etc/ssh/sshd_config 找到#port ...

  2. 使用rapid-framework自动生成struct2

    在JavaWeb的开发中,对数据对象的操作不外乎增删改查,不同的数据对象,其action.service.model.jsp等都比较类似,如果手动去写这些代码,工作量大且非常繁琐.一个心高气傲的程序员 ...

  3. ajax分页效果实现

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. Winform 异步更新listbox

    public partial class Form1 : Form { private BackgroundWorker bw; public Form1() { InitializeComponen ...

  5. 当前标识(NT AUTHORITY\NETWORK SERVICE)没有对“C:\WINDOWS2\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files”的写访问权限。

    卸载了域控制器之后,IIS出现“当前标识(NT AUTHORITY\NETWORK SERVICE)没有对“C:\WINDOWS2\Microsoft.NET\Framework\v4.0.30319 ...

  6. shopnc 商城源码阅读笔记--开篇概述

    关于shopnc 以下是摘抄自百度百科的关于shopnc的介绍: ShopNC商城系统,是天津市网城天创科技有限责任公司开发的一套多店模式的商城系统. 本系统具有商城系统非常完整和专业的功能与流程,系 ...

  7. WordPress 后台禁用Google Open Sans字体,加速网站

    解决方法很简单,安装启用 Disable Google Fonts 或者 Remove Open Sans font Link from WP core 其中之一即可.或者如果你没有使用WP自带的官方 ...

  8. 以a为变量名,给出下列描述的定义

    a)一个整型数(An integer) b) 一个指向整型数的指针(A pointer to an integer) c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to ...

  9. execution 表达式

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) th ...

  10. NOSQL Mongo入门学习笔记 - MongoDB的安装(一)

    手上的工作不是很忙,所以来学习学习很久就像接触的MongoDb,无奈前段时间工作时间都比较多.记录在这里供以后参考 环境: Centos 7 64位 开始: 1. 在官网下载Mongo : wget  ...