Oracle Table Access, Index & Join
来源:
http://www.toutiao.com/i6354118019538485762/?tt_from=email&utm_campaign=client_share&app=news_article&utm_source=email&iid=5777815289&utm_medium=toutiao_ios
表访问的几种方式:(非全部)
(1)TABLE ACCESS FULL(全表扫描): Oracle会读取表中所有的行,并检查每一行是否满足SQL语句中的 Where 限制条件; 全表扫描时可以使用多块读(即一次I/O读取多块数据块)操作,提升吞吐量; 使用建议:数据量太大的表不建议使用全表扫描,除非本身需要取出的数据较多,占到表数据总量的 5% ~ 10% 或以上 (2)TABLE ACCESS BY ROWID(通过ROWID的表存取): 先说一下什么是ROWID? ROWID是由Oracle自动加在表中每行最后的一列伪列,既然是伪列,就说明表中并不会物理存储ROWID的值; 你可以像使用其它列一样使用它,只是不能对该列的值进行增、删、改操作; 一旦一行数据插入后,则其对应的ROWID在该行的生命周期内是唯一的,即使发生行迁移,该行的ROWID值也不变。 让我们再回到 TABLE ACCESS BY ROWID 来: 行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置,所以通过ROWID可以快速定位到目标数据上,这也是Oracle中存取单行数据最快的方法; (3)TABLE ACCESS BY INDEX SCAN(索引扫描): 在索引块中,既存储每个索引的键值,也存储具有该键值的行的ROWID。 一个数字列上建索引后该索引可能的概念结构如下图: 所以索引扫描其实分为两步: Ⅰ:扫描索引得到对应的ROWID Ⅱ:通过ROWID定位到具体的行读取数据 ----------------索引扫描延伸------------------- 索引扫描又分五种:
a)INDEX UNIQUE SCAN(索引唯一扫描): 针对唯一性索引(UNIQUE INDEX)的扫描,每次至多只返回一条记录; 表中某字段存在 UNIQUE、PRIMARY KEY 约束时,Oracle常实现唯一性扫描; b)INDEX RANGE SCAN(索引范围扫描): 使用一个索引存取多行数据; 发生索引范围扫描的三种情况:
c)INDEX FULL SCAN(索引全扫描): 进行全索引扫描时,查询出的数据都必须从索引中可以直接得到(注意全索引扫描只有在CBO模式下才有效) ----------------------- 延伸阅读:Oracle优化器简述 ----------------------- Oracle中的优化器是SQL分析和执行的优化工具,它负责生成、制定SQL的执行计划。 Oracle的优化器有两种:
RBO: RBO有严格的使用规则,只要按照这套规则去写SQL语句,无论数据表中的内容怎样,也不会影响到你的执行计划; 换句话说,RBO对数据“不敏感”,它要求SQL编写人员必须要了解各项细则; RBO一直沿用至ORACLE 9i,从ORACLE 10g开始,RBO已经彻底被抛弃。 CBO: CBO是一种比RBO更加合理、可靠的优化器,在ORACLE 10g中完全取代RBO; CBO通过计算各种可能的执行计划的“代价”,即COST,从中选用COST最低的执行方案作为实际运行方案; 它依赖数据库对象的统计信息,统计信息的准确与否会影响CBO做出最优的选择,也就是对数据“敏感”。 --------------------------------------------------------------------- d)INDEX FAST FULL SCAN(索引快速扫描): 扫描索引中的所有的数据块,与 INDEX FULL SCAN 类似,但是一个显著的区别是它不对查询出的数据进行排序(即数据不是以排序顺序被返回) e)INDEX SKIP SCAN(索引跳跃扫描): Oracle 9i后提供,有时候复合索引的前导列(索引包含的第一列)没有在查询语句中出现,oralce也会使用该复合索引,这时候就使用的INDEX SKIP SCAN; 什么时候会触发 INDEX SKIP SCAN 呢? 前提条件:表有一个复合索引,且在查询时有除了前导列(索引中第一列)外的其他列作为条件,并且优化器模式为CBO时 当Oracle发现前导列的唯一值个数很少时,会将每个唯一值都作为常规扫描的入口,在此基础上做一次查找,最后合并这些查询; 例如: 假设表emp有ename(雇员名称)、job(职位名)、sex(性别)三个字段,并且建立了如 create index idx_emp on emp (sex,ename,job) 的复合索引; 因为性别只有 '男' 和 '女' 两个值,所以为了提高索引的利用率,Oracle可将这个复合索引拆成 ('男',job),('女',job) 这两个复合索引; 当查询 select * from emp where job = 'Programmer' 时,该查询发出后: Oracle先进入sex为'男'的入口,这时候使用到了 ('男',job) 这条复合索引,查找 job = 'Programmer' 的条目; 再进入sex为'女'的入口,这时候使用到了 ('女',job) 这条复合索引,查找 job = 'Programmer' 的条目; 最后合并查询到的来自两个入口的结果集。 ---------------------------------------------- 2. 上图中的 NESTED LOOPS … 描述的是表连接方式; JOIN关键字用于将两张表作连接,一次只能连接两张表,JOIN 操作的各步骤一般是串行的(在读取做连接的两张表的数据时可以并行读取); 表(row source)之间的连接顺序对于查询效率有很大的影响,对首先存取的表(驱动表)先应用某些限制条件(Where过滤条件)以得到一个较小的row source,可以使得连接效率提高。 -------------------------延伸阅读:驱动表(Driving Table)与匹配表(Probed Table)------------------------- 驱动表(Driving Table): 表连接时首先存取的表,又称外层表(Outer Table),这个概念用于 NESTED LOOPS(嵌套循环) 与 HASH JOIN(哈希连接)中; 如果驱动表返回较多的行数据,则对所有的后续操作有负面影响,故一般选择小表(应用Where限制条件后返回较少行数的表)作为驱动表。 匹配表(Probed Table): 又称为内层表(Inner Table),从驱动表获取一行具体数据后,会到该表中寻找符合连接条件的行。故该表一般为大表(应用Where限制条件后返回较多行数的表)。 --------------------------------------------------------------------------------------------------------- 表连接的几种方式:
注:这里将首先存取的表称作 row source 1,将之后参与连接的表称作 row source 2; (1)SORT MERGE JOIN(排序-合并连接): 假设有查询:select a.name,b.name from table_A a join table_B b on (a.id = b.id) 内部连接过程: a) 生成 row source 1 需要的数据,按照连接操作关联列(如示例中的a.id)对这些数据进行排序 b) 生成 row source 2 需要的数据,按照与 a) 中对应的连接操作关联列(b.id)对数据进行排序 c) 两边已排序的行放在一起执行合并操作(对两边的数据集进行扫描并判断是否连接) 延伸: 如果示例中的连接操作关联列 a.id,b.id 之前就已经被排过序了的话,连接速度便可大大提高,因为排序是很费时间和资源的操作,尤其对于有大量数据的表。 故可以考虑在 a.id,b.id 上建立索引让其能预先排好序。不过遗憾的是,由于返回的结果集中包括所有字段,所以通常的执行计划中,即使连接列存在索引,也不会进入到执行计划中,除非进行一些特定列处理(如仅仅只查询有索引的列等)。 排序-合并连接的表无驱动顺序,谁在前面都可以; 排序-合并连接适用的连接条件有:< <= = > >= ,不适用的连接条件有:<> like (2)NESTED LOOPS(嵌套循环): 内部连接过程: a) 取出 row source 1 的 row 1(第一行数据),遍历 row source 2 的所有行并检查是否有匹配的,取出匹配的行放入结果集中 b) 取出 row source 1 的 row 2(第二行数据),遍历 row source 2 的所有行并检查是否有匹配的,取出匹配的行放入结果集中 c) …… 若 row source 1 (即驱动表)中返回了 N 行数据,则 row source 2 也相应的会被全表遍历 N 次。 因为 row source 1 的每一行都会去匹配 row source 2 的所有行,所以当 row source 1 返回的行数尽可能少并且能高效访问 row source 2(如建立适当的索引)时,效率较高。 延伸: 嵌套循环的表有驱动顺序,注意选择合适的驱动表。 嵌套循环连接有一个其他连接方式没有的好处是:可以先返回已经连接的行,而不必等所有的连接操作处理完才返回数据,这样可以实现快速相应。 应尽可能使用限制条件(Where过滤条件)使驱动表(row source 1)返回的行数尽可能少,同时在匹配表(row source 2)的连接操作关联列上建立唯一索引(UNIQUE INDEX)或是选择性较好的非唯一索引,此时嵌套循环连接的执行效率会变得很高。若驱动表返回的行数较多,即使匹配表连接操作关联列上存在索引,连接效率也不会很高。 (3)HASH JOIN(哈希连接): 哈希连接只适用于等值连接(即连接条件为 = ) HASH JOIN对两个表做连接时并不一定是都进行全表扫描,其并不限制表访问方式; 内部连接过程简述: a) 取出 row source 1(驱动表,在HASH JOIN中又称为Build Table) 的数据集,然后将其构建成内存中的一个 Hash Table(Hash函数的Hash KEY就是连接操作关联列),创建Hash位图(bitmap) b) 取出 row source 2(匹配表)的数据集,对其中的每一条数据的连接操作关联列使用相同的Hash函数并找到对应的 a) 里的数据在 Hash Table 中的位置,在该位置上检查能否找到匹配的数据 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby – Emacs OSX中的Bash没有找到通过terminal.app安装的
- c – boost :: shared_ptr循环依赖
- laravel ajax POST请求 错误 TokenMismatchException in Ve
- NSDateFormatter中dateFormat --- 日期格式含义。
- 用PHP连mysql和oracle数据库性能比较
- Flex布局实现圣杯布局和网格布局
- c – 限制不同计算机上的游戏速度
- 组合/聚合复用原则(Composition/Aggregation Principle)
- flex 正則表達式
- ruby-on-rails – Capistrano 3之前和之后的钩子