本文的目的:
1、说一说Oracle的Optimizer及其相关的一些知识。
2、回答一下为什么有时一个表的某个字段明明有索引,当观察一些SQL的执行计划时,发现确不走索引的问题。
3、如果你对 FIRST_ROWS、 ALL_ROWS这两种模式有疑惑时也可以看一下这篇文章。
开始吧:
Oracle在执行一个SQL之前,首先要分析一下语句的执行计划,然后再按执行计划去执行。分析语句的执行计划的工作是由优化器(Optimizer)来完成的。不同的情况,一条SQL可能有多种执行计划,但在某一时点,一定只有一种执行计划是最优的,花费时间是最少的。相信你一定会用Pl/sql Developer、Toad等工具去看一个语句的执行计划,不过你可能对Rule、Choose、First rows、All rows这几项有疑问,因为我当初也是这样的,那时我也疑惑为什么选了以上的不同的项,执行计划就变了?
1、优化器的优化方式
Oracle的优化器共有两种的优化方式,即基于规则的优化方式(Rule-Based Optimization,简称为RBO)和基于代价的优化方式(Cost-Based Optimization,简称为CBO)。
A、RBO方式:优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则。比如我们常见的,当一个where子句中的一列有索引时去走索引。
B、CBO方式:依词义可知,它是看语句的代价(Cost)了,这里的代价主要指Cpu和内存。优化器在判断是否用这种方式时,主要参照的是表及索引的统计信息。统计信息给出表的大小 、有少行、每行的长度等信息。这些统计信息起初在库内是没有的,是你在做analyze后才出现的,很多的时侯过期统计信息会令优化器做出一个错误的执行计划,因些我们应及时更新这些信息。在Oracle8及以后的版本,Oracle列推荐用CBO的方式。
我们要明了,不一定走索引就是优的 ,比如一个表只有两行数据,一次IO就可以完成全表的检索,而此时走索引时则需要两次IO,这时对这个表做全表扫描(full table scan)是最好的。
2、优化器的优化模式(Optermizer Mode)
优化模式包括Rule,Choose,First rows,All rows这四种方式,也就是我们以上所提及的。如下我解释一下:
Rule:不用多说,即走基于规则的方式。
Choolse:这是我们应观注的,默认的情况下Oracle用的便是这种方式。指的是当一个表或或索引有统计信息,则走CBO的方式,如果表或索引没统计信息,表又不是特别的小,而且相应的列有索引时,那么就走索引,走RBO的方式。
First Rows:它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快的方式返回查询的最先的几行,从总体上减少了响应时间。
All Rows:也就是我们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返回表的所有的行,从总体上提高查询的吞吐量。没有统计信息则走基于规则的方式。
3、如何设定选用哪种优化模式
a、Instance级别
我们可以通过在init.ora文件中设定OPTIMIZER_MODE=RULE、OPTIMIZER_MODE=CHOOSE、OPTIMIZER_MODE=FIRST_ROWS、OPTIMIZER_MODE=ALL_ROWS去选用3所提的四种方式,如果你没设定OPTIMIZER_MODE参数则默认用的是Choose这种方式。
B、Sessions级别
通过SQL> ALTER SESSION SET OPTIMIZER_MODE=;来设定。
C、语句级别
这些需要用到Hint,比如:
SQL> SELECT /*+ RULE */ a.userid,
2 b.name,
3 b.depart_name
4 FROM tf_f_yhda a,
5 tf_f_depart b
6 WHERE a.userid=b.userid;
4、为什么有时一个表的某个字段明明有索引,当观察一些语的执行计划确不走索引呢?如何解决呢 ?
A、不走索引大体有以下几个原因
♀你在Instance级别所用的是all_rows的方式
♀你的表的统计信息(最可能的原因)
♀你的表很小,上文提到过的,Oracle的优化器认为不值得走索引。
B、解决方法
♀可以修改init.ora中的OPTIMIZER_MODE这个参数,把它改为Rule或Choose,重起数据库。也可以使用4中所提的Hint.
♀删除统计信息
SQL>analyze table table_name delete statistics;
♀表小不走索引是对的,不用调的。
5、其它相关
A、如何看一个表或索引是否是统计信息
SQL>SELECT * FROM user_tables
2 WHERE table_name=
3 AND num_rows is not null;
SQL>SELECT * FROM user_indexes
2 WHERE table_name=
3 AND num_rows is not null;
b、如果我们先用CBO的方式,我们应及时去更新表和索引的统计信息,以免生形不切合实的执行计划。
SQL> ANALYZE TABLE table_name COMPUTE STATISTICS;
SQL> ANALYZE INDEX index_name ESTIMATE STATISTICS;
具体的ANALYZE语句请参照Oracle8i/9i 的refrence文档。
12:42 PM | Add a comment | Permalink | Blog it | Oracle
oracle大数据量的导入和导出
在oracle中批量数据的导出是借助sqlplus的spool来实现的。批量数据的导入是通过sqlload来实现的。
大量数据的导出部分如下:
/***************************
* sql脚本部分 demo.sql begin
**************************/
/**************************
* @author meconsea
* @date 20050413
* @msn meconsea@hotmail.com
* @Email meconsea@163.com
**************************/
//##--markup html:html格式输出,缺省为off
//##--autocommit:自动提交insert、update、delete带来的记录改变,缺省为off
//##--define:识别命令中的变量前缀符,缺省为on,也就是'&',碰到变量前缀符,后面的字符串作为变量处理.
set colsep''; //##--域输出分隔符
set echo off; //##--显示start启动的脚本中的每个sql命令,缺省为on
set feedback off; //##--回显本次sql命令处理的记录条数,缺省为on
set heading off; //##--输出域标题,缺省为on
set pagesize 0; //##--输出每页行数,缺省为24,为了避免分页,可设定为0。
set linesize 80; //##--输出一行字符个数,缺省为80
set numwidth 12; //##--输出number类型域长度,缺省为10
set termout off; //##--显示脚本中的命令的执行结果,缺省为on
set timing off; //##--显示每条sql命令的耗时,缺省为off
set trimout on; //##--去除标准输出每行的拖尾空格,缺省为off
set trimspool on; //##--去除重定向(spool)输出每行的拖尾空格,缺省为off
spool C:datadmczry.txt;
select trim(czry_dm),trim(swjg_dm),trim(czry_mc) from dm_czry;
spool off;
EOF
/***********************
* demo.sql end
***********************/
在数据导入的时候采用sqlload来调用,在该部分调用的时候用java来调用sqlload。
sqlload包括ctl控制文件。例如:
/*********************
* meconsea ctl
********************/
load data
infile 'C:datadmczry.txt'
replace into table DM_CZRY
fields terminated by X'09'
(CZRY_DM,SWJG_DM,CZRY_MC)
/********************
* end
* 注释:里面的replace可以改为append
*******************/
java程序如下:
在java程序用可以根据需求写成一个bat文件。 把数据库的配置和文件的路径写到一个properties
文件。
/*************************
* ide properties
************************/
Dserver=test/test@SJJZ
sqlldr=D:\oracle\ora92\bin\SQLLDR.EXE
ctldmczry=C:\data\ctl\dmczry.ctl
txtdmczry=C:\data\dmczry.txt
写个PropertyBean.java来操作properties文件。(偷懒不写了!)
用DmCzry.java来把记录导入db中。部分代码如下:
/****************************
* 代码摘要
*
***************************/
..............
sqlldr = pb.getSqlldr();
txt = pb.getTxtdmczry();
ctl = pb.getCtldmczry();
Dserver= pb.getDserver();
Process processCmd = Runtime.getRuntime().exec(sqlldr+" "+cmdStr);
.............
12:42 PM | Add a comment | Permalink | Blog it | Oracle
在Oracle中查看各个表、表空间占用空间的大小
查看当前用户每个表占用空间的大小:
Select Segment_Name,Sum(bytes)/1024/1024 From User_Extents Group By Segment_Name
查看每个表空间占用空间的大小:
Select Tablespace_Name,Sum(bytes)/1024/1024 From Dba_Segments Group By Tablespace_Name
12:36 PM | Add a comment | Permalink | Blog it | Oracle
July 22
Oracle 数据类型
Oracle 数据类型
数据类型
描述
VARCHAR2(size)
NVARCHAR2(size)
可变长度的字符串,其最大长度为 size 个字节。size 的最大值是 4000,而最小值是 1。您必须指定一个 VARCHAR2 的 size。
可变长度的字符串,依据所选的国家字符集,其最大长度为 size 个字符或字节。size 的最大值取决于存储每个字符所需要的字节数,其上限为 4000 个字节。您必须为 NVARCHAR2 指定一个 size。
NUMBER(p,s)
精度为 p 并且数值范围为 s 的数值。精度 p 的范围是从 1 到 38。数值范围 s 的范围是从 -84 到 127。
LONG
可变长度的字符数据,其最大长度可达 2G 或 231 –1 个字节。
DATE
有效日期范围从公元前 4712 年 1 月 1 日到公元后 4712 年 12 月 31 日。
RAW(size)
长度为 size 字节的原始二进制数据。size 的最大值为 2000 字节。您必须为 RAW 值指定一个 size。
LONG RAW
可变长度的原始二进制数据,其最大长度可达 2G 字节。
CHAR(size)
NCHAR(size)
固定长度的字符数据,其长度为 size 字节。size 的最大值为 2000 字节。默认或最小的 size 是一个字节。
固定长度的字符数据,其长度依据国家字符集的选择为 size 个字符或字节。size 的最大值取决于存储每个字符所需要的字节数,其上限为 2000 个字节。默认或最小的 size 是一个字符或字节,这取决于字符集。
CLOB
NCLOB
一个字符大型对象,可容纳单字节的字符。不支持宽度不等的字符集。最大大小为 4G 字节。
一个字符大型对象,可容纳固定宽度的多字节字符。不支持宽度不等的字符集。最大大小为 4G 字节。储存国家字符集数据。
BLOB
一个二进制大对象。最大大小为 4G 字节。
BFILE
包含一个大型二进制文件的定位器,其存储在数据库的外面。使得可以以字节流 I/O 访问存在数据库服务器上的外部 LOB。最大大小为 4G 字节。