ORACLE回表(一)

要写出高效的SQL,那么必须必须得清楚SQL执行路径,介绍如何提高SQL性能的文章很多,这里不再赘述,本人来谈谈如何从 减少SQL回表次数 来提高查询性能,因为回表将导致扫描更多的数据块。

我们大家都知道,数据库表中数据存储都是以块为单位,称为数据块;表中每行数据都有唯一的地址标志ROWID。

举个例子:

select a from test_db where b=5

A、假设b上没有索引

1、那么该条SQL将进行表扫描,扫描所有该表的数据块

2、从数据块中找到记录,并且进行过滤

可想而知,没有索引将会导致扫描该表所有数据块,性能低下

B、 假设b上有索引

1、那么该条SQL将进行索引扫描,在索引中找到b=5的位置,一般只需要扫描3个块左右就找到了

2、获得所有b=5的行的rowid

3、根据rowid再查询数据(这就是回表),如果数据量少,那么回表次数就少,如果需要的数据全部在索引中,那么就不会再回表了,例如a也在索引中,如果a不在索引中,那么仍然要回表一次查出a。

经验:如果有可能的话,尽量只在索引上查询,不用回表或者只少量回表。

例如分页需要回表,一般尽量在索引上分页,然后返回rowid,再通过rowid进行回表查询。

下面是一个常用的分页语句:

Select * from (select row_number over(order by a) rn,t.* from table t where b=? And c=?) where rn>=1 and rn <=20   
Select * from (select row_number over(order by a) rn,t.* from table t where b=? And c=?) where rn>=1 and rn <=20

我们分析一下(假设索引是b,c,a):

1、先查询内层语句 select * from table t where b=? and c=?,假设返回1000行数据

2、通过索引找到这1000行数据的rowid,因为索引是连续的,假设这1000行数据的索引分布在5个块中,则差不多为8块读

3、再根据rowid取回表查询数据,最坏的情况是这1000行数据分布在1000个块中,则需要读取1000块。那么算上上面的8块总共尧都区1000+8=1008块

我们换一种写法:

Select * from table t,   
(select rid from (select rowid rid,row_number over(order by a) rn from table where b=? And c=?)   
 where rn>=1 and rn<=20) tmp   
Where tmp.rid=t.rowid   
Select * from table t,
(select rid from (select rowid rid,row_number over(order by a) rn from table where b=? And c=?)
 where rn>=1 and rn<=20) tmp
Where tmp.rid=t.rowid

再来分析一下:

1、最里层的sql select rid from (select rowid rid,row_number over(order by a) rn from table where b=? And c=?) where rn>=1 and rn<=20 可以全部从索引中获得数据,由于索引有序,差不多也是8块读

2、分页之后,只有20行数据,再根据这20行的rowid回表查询数据,最坏情况是20行都在20个不同块中,那么总共20+8=28

从以上分析可以看出,有效的利用索引,减少回表次数,可以大大提高SQL性能,值得大家去花功夫了解一下。

时间: 2024-10-01 04:11:32

ORACLE回表(一)的相关文章

Oracle 闪回表实验

作业:闪回表实验 1.构造测试表flb_test,数据不小于10000行: [email protected]>create table flb_test(id number,dd date); Table created. [email protected]>begin 2  for i in 1..10000 3  loop 4  insert into flb_test values (i,sysdate+i); 5  end loop; 6  end; 7  / PL/SQL proc

oracle开发系列(三)TABLE ACCESS BY INDEX ROWID 你不知道的索引回表

1 引言 最近系统经常提示一个sql查询时间过长的问题,看了一下就是一个每天按照时间戳统计前一天量的sql. 表总的数据量为53483065. 语句如下: select count(x.serial_id) as countnum from iodso.qos_cnst_busilog_td x where x.oper_time between trunc(sysdate- 1) and trunc(sysdate); 执行时间情况如下:(执行要49s) 看了下执行计划 是这样的: 从上面的执

oracle闪回表详解

--- 说明闪回数据库 --- 使用闪回表将表内容还原到过去的特定时间点 --- 从删除表中进行恢复 --- 使用闪回查询查看截止到任一时间点的数据库内容 --- 使用闪回版本查询查看某一行在一段时间内的各个版本 --- 使用闪回事务查询查看事务处理历史记录或行 会还原表及其关联对象(如索引.约束条件.触发器等)中的数据. 所谓闪回表,就是将表里的数据回退到历史的某个时间点,比如回退到用户误删除数据之前的时间点,从而将误删除的数据恢复回来,在这个操作过程中,数据库仍然可用而且不需要额外的空间.

oracle回滚误删并且commit的表

1.恢复到某个时刻 insert into qual_temp_detail select * from qual_temp_detail as of timestamp to_date('2014-12-29 08:30:22', 'yyyy-mm-dd hh24:mi:ss') 其中qual_temp_detail是要回滚的数据表名称. to_date函数的第一个参数是要回滚到的时间点.妈妈再也不怕我手滑了! 2. 恢复到15分钟以前 --闪回到15分钟前 select * from ord

Oracle闪回技术之一Oracle 11g 利用FlashTable (闪回表)恢复(用delete)误删的数据

闪回表,实际上就是将表中的数据快速恢复到过去的一个时间点或者系统改变号SCN上.实现表的闪回,需要用到撤销表空间相关的UNDO信息,通过SHOW PARAMETER UNDO命令就可以了解这些信息.用户对表的数据的修改操作,都记录在撤销表空间中,这为表的闪回提供的数据恢复的基础. 修改记录被提交到undo表空间中的默认保留时间为900秒,用户可以在这900秒的时间内对表的进行闪回操作,从而将表中的数据恢复的修改前的状态. 如上图显示的默认900秒,我们通过sql来修改这个默认时间为1200: f

闪回之闪回表(flashback table)

背景知识 设置闪回数据库参数设置数据库闪回的三个参数:db_recovery_file_dest_size  闪回恢复区大小db_recovery_file_dest  闪回恢复区路径,该参数可以任意指定,闪回日志记录了数据库的前影像,该日志不会进行归档,一但停用数据库的闪回功能,该目录下的日志会自动清除db_flashback_retention_target  保留恢复最近多长时间的数据,单位为分钟.SQL> alter system set db_recovery_file_dest_si

oracle回滚机制深入研究

这篇文章主要描述oracle的回滚机制,篇幅可能较长,因为对于oracle的回滚机制来说,要讨论和描述的实在太多,只能刷选自己认为最有意义的一部分进行深入研究和分享 一.我们来看一个DML语句的处理过程描述 update undotest set object_type='VIEW' where object_type='PROCEDURE'; 检查shared pool中是否存在相同的语句,如果存在,重用执行计划,执行扫描运算,如果不存在,执行硬解析生成执行计划 根据执行计划中的扫描运算,检查

oracle之表空间(tablespace)、方案(schema)、段(segment)、区(extent)、块(block)

数据文件和日志文件是数据库中最重要的文件.它们是数据存储的地方.每个数据库至少有一个与之相关的数据文件,通常情况下不只一个,有很多.数据在数据文件中是如何组织的?要了解这些内容我们首先必须理解什么是表空间(tablespace).段(segment).区(extent).块(block),这些都是oracle数据库在数据文件中组织数据的基本单元.现在我们来理解这些概念. 块是数据存储的物理单位,也是数据文件中最基础的单位,数据直接存储在块上.是oracle空间分配的最小单位.oracle中的块大

Oracle单表去重复(一)

去重有两层含义,一:是记录完全一样:二:是符合一定条件的认为是重复. 根据表的数量,去重可划分为:单表去重和多表关联去重. 对于去重,一般最容易想到的是用distinct,而distinct只能对记录完全重复的记录保留一条. distinct使用的是二重循环的方式来去重的,如果数据量非常大的时候,会导致性能急剧下降. 例如:select distinct 字段名 from 原表; 此应用案例,主要有删除表中的完全重复的记录: insert into 临时表 select distinct 字段名