引言:oracle数据库性能调优最需要重视的也最常遇到的就是SQL执行效率,而反映SQL效率最直观的工具就是CBO生成的执行计划,那么如何让CBO生成最精准的效率最高的执行计划成为我们当前需要研究的课题。同一条语句,好的执行计划能带来飞一样的速度,坏的执行计划让我们痛苦不堪,下面我们从原理到实践来把如何产生高效计划的方法教给大家。
一 CBO介绍
CBO全称叫Cost Based optimization基于代价优化器,它是一个数学模型,同一个SQL语句在不同的oracle版本中计算出来的代价结果也是不一样的,因为每个版本CBO优化器的设计结构有很大不同,现在还不是很完善很智能很通人性,因此我们不能完全依赖它,只能辅助我们。
如何生成精确的执行计划:公式数据+CBO=执行计划,传入CBO的数据越精确得到结果越精确,我们能做的保证输入数据更准确,通过精确数据计算出精确执行计划
二演示一个表分析后执行计划比动态采样更准确的例子
动态采样:顾名思义就是oracle自动为你进行的初步数据分析,由于是随机在表上取一些数据,因此并不能保证得出的执行计划很准确,只能作为一种辅助分析手段,在不得已的情况下来分析数据,有一定的局限性。
场景:当表没有分析信息时,oracle会使用动态采样技术,而且动态采样是在SQL硬解析的时候发生的,传入->CBO参数->生成执行计划。
级别:oracle 10g oracle 11g默认动态采样级别是2,它有level1-10,设置的级别越高采集的数据块越多,结果越精确,运行时间越长,level10对所有数据进行采样分析。
实验
LEO1@LEO1> drop table leo1 purge;清理环境
Table dropped.
LEO1@LEO1> drop table leo2 purge;
Table dropped.
LEO1@LEO1> create table leo1 as select * from dba_objects;创建leo1表
Table created.
LEO1@LEO1> create table leo2 as select * from leo1;创建leo2表,采用leo1一样数据和结构
Table created.
LEO1@LEO1> col segment_name for a10
LEO1@LEO1> select segment_name,extents,blocks from dba_segments where segment_name in ('LEO1','LEO2');
SEGMENT_NA EXTENTS BLOCKS
---------- ---------- -------------- -------------- ----
LEO1 24 1152
LEO2 24 1152
查询leo1和leo2表这两个段对象存储参数,都是占用24个区,1152个块,2个表一模一样嘛
LEO1@LEO1> col table_name for a10
LEO1@LEO1> select table_name,num_rows,blocks,status from dba_tables wheretable_name in ('LEO1','LEO2');
TABLE_NAME NUM_ROWS BLOCKS STATUS
---------- ---------- ---------- ------------ ---------- ------------
LEO1 VALID
LEO2 VALID
在这个数据字典里只显示表名和当前状态(有效),没有行信息和块信息,这是为神马呢,嗯从上面的操作可以看出,我们只是建立了表,但没有分析表统计信息,现在我们分析一下后看看效果
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO1');对LEO1表进行统计分析
PL/SQL procedure successfully completed.
LEO1@LEO1> select table_name,num_rows,blocks,status from dba_tables wheretable_name in ('LEO1','LEO2');
TABLE_NAME NUM_ROWS BLOCKS STATUS
---------- ---------- ---------- ------------ ---------- ------------
LEO1 71968 1051 VALID
LEO2 VALID
现在leo1表已经有行信息和块信息了,leo2由于没有进行表分析现在还什么都没有
LEO1@LEO1> set autotrace trace exp
LEO1@LEO1> select * from leo1 where object_id=10000;
Execution Plan
----------------------------------------------------------
Plan hash value: 2716644435
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 97 | 287 (1)| 00:00:04 |
|* 1 | TABLE ACCESS FULL| LEO1 | 1| 97 | 287 (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=10000)
Leo1表进行了统计分析,执行计划显示Rows=1,嗯由于object_id字段是不重复的,我们都知道object_id=10000只有一条记录,这和执行计划的判断结果是一致,所以表分析可以让oracle收集表数据的信息,让CBO了解表数据分布情况,有多少条,占用多少空间等。
总之“分析”就是让oracle理解我们的数据是怎么样一个情况,以便更好的去处理它
LEO1@LEO1> select * from leo2 where object_id=10000;
Execution Plan
----------------------------------------------------------
Plan hash value: 2258638698
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 12 | 2484 | 287 (1)| 00:00:04 |
|* 1 | TABLE ACCESS FULL| LEO2 | 12| 2484 | 287 (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=10000)
Note
-----
-dynamic sampling used for this statement (level=2)
Leo2表没有进行统计分析,oracle采用了动态采样技术(红色字显示),执行计划显示Rows=12,由于动态采样只是随机在表上取一些数据来评估,没有进行全表完整分析,固然得出的执行计划没有leo1表更精确更好。所以说“动态采样”只是一个补救措施。
三演示在缺乏直方图(柱状图)时,CBO计算出错误的执行计划的例子,并给出最后正确的执行计划
直方图(柱状图):oracle对列上的数据分布情况进行统计,得出的图示。
场合:常用于查看数据倾斜情况(一个值在整个字段中所占比例),了解某个键值所拥有的记录数
如果是数字1这个键值在整个字段中占用的比例
如果是字符leonarding这个键值在整个字段中占用的比例
如果是日期 2012-12-21这个日期在整个字段中占用的比例
直方图类型:
(1)Frequency-频率直方图:用于基数少,记录多,重复率高的字段
(2)Height Balanced-高度平衡直方图:用于基数多,唯一值多,重复率低的字段,这个就是等分相同数据量的桶(bucket),值可能不同,来显示桶中记录数的比例
实验
LEO1@LEO1> drop table leo3 purge;清除环境
Table dropped.
LEO1@LEO1> drop table leo4 purge;
Table dropped.
LEO1@LEO1> create table leo3 as select * from dba_objects;创建leo3表
Table created.
LEO1@LEO1> create table leo4 as select * from dba_objects;创建leo4表
Table created.
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO3',method_opt=>'for all columns size 1');
PL/SQL procedure successfully completed.
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO4',method_opt=>'for all columns size 254');
PL/SQL procedure successfully completed.
对leo3表做信息收集但没有做直方图分析(for all columns size 1)1代表不做直方图
对leo4表做信息收集但又做了直方图分析(for all columns size 254)254代表最精确直方图对所有列都做分析,在分析表时把更多数据告诉CBO,得出最精确的执行计划。
注:删除表上分析信息语句
LEO1@LEO1> execute dbms_stats.delete_table_stats('LEO1','LEO3');
PL/SQL procedure successfully completed.
LEO1@LEO1> select table_name,column_name,num_distinct,num_buckets,histogram from dba_tab_col_statistics where table_name in ('LEO3','LEO4');
TABLE_NAME COLUMN_NAME NUM_DISTINCT NUM_BUCKETS HISTOGRAM
---------- ------------------------------ ------------ ----------- ---------------
LEO3 EDITION_NAME 0 0 NONE
LEO3 NAMESPACE 20 1 NONE
LEO3 SECONDARY 2 1 NONE
LEO3 GENERATED 2 1 NONE
LEO3 TEMPORARY 2 1 NONE
LEO3 STATUS 2 1 NONE
LEO3 TIMESTAMP 1227 1 NONE
LEO3 LAST_DDL_TIME 1170 1 NONE
LEO3 CREATED 1097 1 NONE
LEO3 OBJECT_TYPE 43 1 NONE
LEO3 DATA_OBJECT_ID 7262 1 NONE
LEO3 OBJECT_ID 71966 1 NONE
LEO3 SUBOBJECT_NAME 58 1 NONE
LEO3 OBJECT_NAME 43424 1 NONE
LEO3 OWNER 24 1 NONE
LEO4 EDITION_NAME 0 0 NONE
LEO4 NAMESPACE 20 14 FREQUENCY
LEO4 SECONDARY 2 2 FREQUENCY
LEO4 GENERATED 2 2 FREQUENCY
LEO4 TEMPORARY 2 2 FREQUENCY
LEO4 STATUS 2 1 FREQUENCY
LEO4 TIMESTAMP 1228 254 HEIGHT BALANCED
LEO4 LAST_DDL_TIME 1171 254 HEIGHT BALANCED
LEO4 CREATED 1098 254 HEIGHT BALANCED
LEO4 OBJECT_TYPE 43 30 FREQUENCY
LEO4 DATA_OBJECT_ID 7263 254 HEIGHT BALANCED
LEO4 OBJECT_ID 71967 254 HEIGHT BALANCED
LEO4 SUBOBJECT_NAME 58 58 FREQUENCY
LEO4 OBJECT_NAME 43424 254 HEIGHT BALANCED
LEO4 OWNER 24 19 FREQUENCY
30 rows selected.
参数说明:
TABLE_NAME:表名 leo3我们没有做直方图分析显示NONE 而leo4做了
COLUMN_NAME:列名
NUM_DISTINCT:列中不同键值数(就是我们所说基数)
NUM_BUCKETS:直方图的桶数,用几个桶来装数据
HISTOGRAM:直方图类型,FREQUENCY and HEIGHT BALANCED
例对于status列由于基数少重复率很高则使用frequency直方图
对于object_id由于都是唯一值没有重复率则使用height balance直方图
与我们上面写的情况一致
LEO1@LEO1> select count(*) from leo3 where object_type='TABLE';标准记录数2816
COUNT(*)
-----------------
2816
LEO1@LEO1> select count(*) from leo3 where object_type='TABLE';
Execution Plan
----------------------------------------------------------
Plan hash value: 3505406240
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 287 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| LEO3 |1674| 15066 | 287 (1)| 00:00:04 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='TABLE')
由于leo3我们没有做直方图分析,CBO就不知道object_type='TABLE'在整个字段中所占比例,导致Rows=1674与标准2816偏差太大,这就是没有足够分析数据的结果
LEO1@LEO1> select count(*) from leo4 where object_type='TABLE';
Execution Plan
----------------------------------------------------------
Plan hash value: 3210696650
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 287 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| LEO4 |2697| 24273 | 287 (1)| 00:00:04 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_TYPE"='TABLE')
由于leo4做了全表整体直方图分析,生成254个桶来装数据,oracle必然了解object_type='TABLE'在整个字段中所占比例,Rows=2697和标准2816已经非常接近了,相对比较精确,这就是有足够分析数据的结果。
四演示在分区表上,全局信息和分区信息是如何影响执行计划的,给出演示过程
全局统计信息:如果跨分区CBO使用全局统计信息
分区统计信息:如果不跨分区CBO使用分区统计信息
全局信息和分区信息是2个独立信息源,某些情况下会有联系
实验
LEO1@LEO1> drop table leo5 purge;清除环境
Table dropped.
LEO1@LEO1> drop table leo6 purge;
Table dropped.
LEO1@LEO1> create table leo5建立一个分区表
partition by range (object_id)
(
partition p1 values less than(10000),
partition p2 values less than(20000),
partition p3 values less than(30000),
partition p4 values less than(40000),
partition p5 values less than(50000),
partition p6 values less than(60000),
partition pm values less than(maxvalue)
) as select * from dba_objects; 2 3 4 5 6 7 8 9 10 11
Table created.
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO5');默认对全局和分区都做分析
PL/SQL procedure successfully completed.
LEO1@LEO1> select table_name,num_rows,blocks,global_stats from dba_tables where table_name in ('LEO5');
TABLE_NAME NUM_ROWS BLOCKS GLO
---------- ---------- ---------- ----- ---------- ---------- ------------ ------
LEO5 71979 1111 YES
从全局上看,Leo5表有71979行记录占用1111个块
LEO1@LEO1> select table_name,partition_name,num_rows,blocks,global_stats from dba_tab_partitionswhere table_name='LEO5';
TABLE_NAME PARTITION_NAME NUM_ROWS BLOCKS GLO
---------- ------------------------------ ---------- ---------- ---
LEO5 P1 9708 137 YES
LEO5 P2 9806 152 YES
LEO5 P3 10000 158 YES
LEO5 P4 10000 159 YES
LEO5 P5 10000 159 YES
LEO5 P6 9606 150 YES
LEO5 PM 12859 196 YES
从分区上看,每个分区有多少行记录占用了多少个数据块,总和应该与全局信息一致
NUM_ROWS:是一个估算值
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO5',granularity=>'partition');
PL/SQL procedure successfully completed.
Granularity参数:针对分区表来说的,在哪个粒度上做分析
Global:全局级别分析
Partition:分区级别分析
Subpartition:子分区级别分析
我们这条命令单独对分区做分析,更新分区统计信息,不更新全局统计信息
LEO1@LEO1> select table_name,num_rows,blocks,global_stats from dba_tables where table_name in ('LEO5');
TABLE_NAME NUM_ROWS BLOCKS GLO
---------- ---------- ---------- ------------ ---------- ---------------
LEO5 71979 1111 YES
全局统计信息没有变化,与实际数据信息不相符了
LEO1@LEO1> select table_name,partition_name,num_rows,blocks,global_stats from dba_tab_partitions where table_name='LEO5';
TABLE_NAME PARTITION_NAME NUM_ROWS BLOCKS GLO
---------- ------------------------------ ---------- ---------- ---
LEO5 P1 19416 382 YES
LEO5 P2 19612 382 YES
LEO5 P3 20000 382 YES
LEO5 P4 20000 382 YES
LEO5 P5 20000 382 YES
LEO5 P6 19212 382 YES
LEO5 PM 25718 382 YES
分区统计信息已经被更新了
现在看一下统计信息是如何被使用的
LEO1@LEO1> select count(*) from leo5 where object_id<8000;符合条件有15668行
COUNT(*)
------------------
15668
LEO1@LEO1> select count(*) from leo5 where object_id<8000;
Execution Plan
----------------------------------------------------------
Plan hash value: 546738359
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 4 |105 (0)| 00:00:02 | | |
| 1 | SORT AGGREGATE | | 1| 4 | | | | |
| 2 | PARTITION RANGE SINGLE| | 15534 | 62136 | 105 (0)| 00:00:02 | 1 | 1 |
|* 3 | TABLE ACCESS FULL | LEO5 |15534| 62136 | 105 (0)| 00:00:02 | 1 | 1 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("OBJECT_ID"<8000)
由于我们在分区级别重新进行了分析,分区统计信息是最新版,CBO使用了最新分区统计信息后Rows=15534与实际15668已经相差无疑,基本上得出的是正确结果。
原理:我们说过如果不跨分区CBO使用分区统计信息,针对某个分区oracle获取信息
Pstart| Pstop起始分区和结束分区都是1,说明结果集都落在了第一个分区只需扫描第一个分区即可
LEO1@LEO1> select count(*) from leo5 where object_id<30001;符合条件有59030行
COUNT(*)
----------------
59030
LEO1@LEO1> select count(*) from leo5 where object_id<30001;
Execution Plan
----------------------------------------------------------
Plan hash value: 3650668575
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 416 (1)| 00:00:05 | | |
| 1 | SORT AGGREGATE | | 1 | 5 | | | | |
| 2 | PARTITION RANGE ITERATOR| | 29209 | 142K| 416 (1)| 00:00:05 | 1 | 4 |
|* 3 | TABLE ACCESS FULL | LEO5 |29209| 142K| 416 (1)| 00:00:05 | 1 | 4 |
--------------------------------------------------------------------------------------------------
跨4个分区扫描
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("OBJECT_ID"<30001)
LEO1@LEO1> select count(*) from leo5 where object_id<30000;
Execution Plan
----------------------------------------------------------
Plan hash value: 3650668575
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 313 (1)| 00:00:04 | | |
| 1 | SORT AGGREGATE | | 1 | 5 | | | | |
| 2 | PARTITION RANGE ITERATOR| | 29208 | 142K| 313 (1)| 00:00:04 | 1 | 3 |
| 3 | TABLE ACCESS FULL | LEO5 |29208| 142K| 313 (1)| 00:00:04 | 1 | 3 |
--------------------------------------------------------------------------------------------------
跨3个分区扫描
小结:只要跨分区CBO就使用全局统计信息,由于全局信息过旧,不管扫描3个分区还是4个分区Rows=29209这与实际值59030都相差甚远,这就是为什么分区里数据是准的,而全局里数据是不准的。
我们再一次对全局级别分析一次看看全局统计信息是不是更新了,执行计划是不是精准了
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO5',granularity=>'global');
PL/SQL procedure successfully completed.
LEO1@LEO1> select table_name,num_rows,blocks,global_stats from dba_tables where table_name in ('LEO5');
TABLE_NAME NUM_ROWS BLOCKS GLO
---------- ---------- ---------- ------ ---------- ---------- --------
LEO5 143958 2674 YES
这次全局统计信息更新了
LEO1@LEO1> select count(*) from leo5 where object_id<30001;
Execution Plan
----------------------------------------------------------
Plan hash value: 3650668575
--------------------------------------------------------------------------------------------------
|Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 416 (1)| 00:00:05 | | |
| 1 | SORT AGGREGATE | | 1 | 5 | | | | |
| 2 | PARTITION RANGE ITERATOR| | 58418 | 285K| 416 (1)| 00:00:05 | 1 | 4 |
|* 3 | TABLE ACCESS FULL | LEO5 |58418| 285K| 416 (1)| 00:00:05 | 1 | 4 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("OBJECT_ID"<30001)
小结:我们使用更新后的全局统计信息得出Rows=58418与实际值59030差不多了,说明单独对分区分析,不会更新全局统计信息。
五演示用extended statistics解决列相关性的例子,给出演示过程
列的相关性:就是where子句中同时存在2个列以上条件时,CBO不做列与列之间相关性分析,这会导致CBO计算执行计划出现一种偏差
实验
由于oracle11g之前CBO不做列与列之间相关性分析,我的实验环境是11g的没有10g环境,我们就用其他方式模拟一下吧。
LEO1@LEO1> select count(*) from leo6 where object_type='TABLE' and wner='LEO1';
COUNT(*)
------------------
20符合条件有20行
LEO1@LEO1> select count(*) from leo6 where object_type='TABLE' and wner='LEO1';
Execution Plan
----------------------------------------------------------
Plan hash value: 3995977415
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 28 | 287 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 28 | | |
|* 2 | TABLE ACCESS FULL| LEO6 | 8| 224 | 287 (1)| 00:00:04 |
---------------------------------------------------------------------------
CBO不做列与列之间相关性分析前提下,Rows=8显然CBO计算错误,应该有20行的
LEO1@LEO1>
executedbms_stats.gather_table_stats('LEO1','LEO6',method_opt=>'for columns (object_type,owner) size skewonly');
PL/SQL procedure successfully completed.
我们对leo6表做列相关性分析,看看CBO计算是否准确
LEO1@LEO1> select count(*) from leo6 where object_type='TABLE' and wner='SYS';
COUNT(*)
----------------
969符合条件有969行
LEO1@LEO1> select count(*) from leo6 where object_type='TABLE' and wner='SYS';
Execution Plan
----------------------------------------------------------
Plan hash value: 3995977415
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 28 | 287 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 28 | | |
|* 2 | TABLE ACCESS FULL| LEO6 | 819| 22932 | 287 (1)| 00:00:04 |
---------------------------------------------------------------------------
小结:这次CBO的Rows=819与实际值969非常接近了,可以看出作完列与列相关性分析后,CBO知道2个列的数据分布情况是一个什么样子了,从而在计算执行计划上有更多数据参考得出结果更准确。
六对一张表进行导出/导入,看它的统计信息是否发生改变,给出演示过程。
LEO1@LEO1> drop table leo7 purge;清除环境
Table dropped.
LEO1@LEO1> create table leo7 as select * from dba_objects;创建leo7表
Table created.
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO7');进行表分析
PL/SQL procedure successfully completed.
LEO1@LEO1> select count(*) from leo7;现在我们表里有71979行记录
COUNT(*)
-----------------
71979
LEO1@LEO1> select table_name,num_rows,blocks,global_stats from dba_tables where table_name in ('LEO7');
TABLE_NAME NUM_ROWS BLOCKS GLO
---------- ---------- ---------- ---- ---------- ----------- -----
LEO7 71979 1051 YES
做完表分析后,统计信息已经有了,有71979行,1051个块,只包括数据段
LEO1@LEO1> select segment_name,extents,blocks from dba_segmentswhere segment_name in ('LEO7');
SEGMENT_NA EXTENTS BLOCKS
---------- ---------- ----------- ---------- -----------
LEO7 24 1152
这是leo7段对象的存储参数,占用24个区1152个数据块,段对象里面的块数包括数据段+表头段的信息
[oracle@leonarding1 ~]$ expuserid=leo1/leo1@leo1 file=/home/oracle/leo7_dump_file1.dmp tables=leo7 rows=y
Export: Release 11.2.0.1.0 - Production on Sun Jan 20 14:16:45 2013
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in US7ASCII character set and AL16UTF16 NCHAR character set
server uses ZHS16GBK character set (possible charset conversion)
About to export specified tables via Conventional Path ...
. . exporting table LEO7 71979 rows exported
EXP-00091: Exporting questionable statistics.
Export terminated successfully with warnings.
导出leo7表进行导出
[oracle@leonarding1 ~]$ ll
total 8208
drwxrwxrwx 8 oracle oinstall 4096 Aug 21 2009 database
drwxr-xr-x 2 oracle oinstall 4096 Nov 17 14:48 Desktop
-rw-r--r-- 1 oracle oinstall 7 Nov 17 15:43 em
-rw-r--r-- 1 oracle oinstall 8314880 Jan 20 14:16leo7_dump_file1.dmp
-rw-r--r-- 1 oracle oinstall 42201 Dec 16 21:25 orahdfs-1.0.0.0.0.zip
-rwxrwxrwx 1 oracle oinstall 795 Dec 16 23:53 test1.txt
-rwxrwxrwx 1 oracle oinstall 13325 Dec 27 23:13 test.txt
看一下统计信息,现在没有变化,也就是说导出不会更新表统计信息
LEO1@LEO1> select table_name,num_rows,blocks,global_stats from dba_tables where table_name in ('LEO7');
TABLE_NAME NUM_ROWS BLOCKS GLO
---------- ---------- ---------- ---
LEO7 71979 1051 YES
我们把leo7_dump_file1.dmp在导入到leo7表中
[oracle@leonarding1 ~]$ imp userid=leo1/leo1@leo1 file=/home/oracle/leo7_dump_file1.dmp full=y ignore=y
Import: Release 11.2.0.1.0 - Production on Sun Jan 20 14:31:12 2013
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export file created by EXPORT:V11.02.00 via conventional path
import done in US7ASCII character set and AL16UTF16 NCHAR character set
import server uses ZHS16GBK character set (possible charset conversion)
. importing LEO1's objects into LEO1
. importing LEO1's objects into LEO1
. . importing table "LEO7" 71979 rows imported
Import terminated successfully without warnings.
LEO1@LEO1> select count(*) from leo7;
COUNT(*)
----------------
143958
默认追加方式导入数据,原来71979行,导入后143958行
LEO1@LEO1> select table_name,num_rows,blocks,global_stats from dba_tables where table_name in ('LEO7');
TABLE_NAME NUM_ROWS BLOCKS GLO
---------- ---------- ---------- ---------- ---------- ----------
LEO7 71979 1051 YES
我们对leo7表进行了追加导入,但是它的统计信息还是原来收集的统计信息,也就是说导入也不会更新表统计信息
LEO1@LEO1> execute dbms_stats.gather_table_stats('LEO1','LEO7');
PL/SQL procedure successfully completed.
LEO1@LEO1> select table_name,num_rows,blocks,global_stats from dba_tables where table_name in ('LEO7');
TABLE_NAME NUM_ROWS BLOCKS GLO
---------- ---------- ---------- ---
LEO7 143958 2160 YES
小结:只有重新进行表分析才能更新表统计信息
动态采样 直方图 CBO gather granularity extendedstatisticsexp imp 列相关性
oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html