1.oracle优化器 优化目标分为4种: choose (选择性) rule (基于规则) first rows(第一行) all rows(所有行) Description:描述sql的执行计划 Object owner:对象模式 Object name:对象名 Cost:花费(的时间) Cardinality:基数,约等于行数 Bytes:空间(访问的存储空间)
2.table的访问方式 2.1全表扫描(table access full) 全表扫描就是顺序地访问表中每条记录。 oracle采用一次读入多个数据块(database block)的方式优化全表扫描。 举例: select * from emp;
2.2通过rowid访问表(table access by user/index rowid) 可以采用基于rowid的访问方式情况,提高访问表的效率。 rowid包含了表中记录的物理位置信息。 oracle采用索引(index)实现了数据和存放数据的物理位置(rowid)之间的联系。 通常索引提供了快速访问rowid的方法,因此那些基于索引列的查询就可以得到性能上的提高。 举例: select rowid,emp.* from emp where rowid=‘AAAR3sAAEAAAACXAAA‘; select * from emp where empno=7788;
--清除数据库内存缓冲区 alter system flush buffer_cache;
索引(index) 1.索引定义 索引是一种与表相关联的可选结构,有时可以提高数据访问速度。 通过在表中的一个或多个列上创建索引, 通常情况下能够(快速地)从随机分布的表行中检索一小部分行。 索引是减少磁盘 i/o 的许多手段之一。 如果一个表没有索引,数据库必须执行全表扫描来查找值。 测试: select * from all_objects; create table tab_all_objects as select * from all_objects; select * from tab_all_objects; 35s-->26s select * from tab_all_objects where object_name=‘STUDENT‘; 0.531s-->0.015s create index idx_object_name on tab_all_objects (object_name); 练习: select owner,view_name,text_length,editioning_view,read_only from all_views; create table tab_all_views as select owner,read_only from all_views; select * from tab_all_views; 0.515s-->0.498s select * from tab_all_views where view_name=‘VIEW_EMP‘; 0.499s-->0.062s create index idx_view_name on tab_all_views (view_name);
select * from emp,dept where emp.deptno=dept.deptno; 0.109s-->0.031s create index idx_emp_deptno on emp (deptno); 通常,在下列情况下可以考虑在某列上创建索引: 某个列经常被作为查询条件,并且查询结果只返回了表中的一小部分行。5% >20% 列或列集上存在引用完整性约束(是外键列)。
二、语法 2.1 创建索引 create [unique | bitmap] index 索引名 on 表名 { ([<expr>] <col> [asc | desc] [,…]) 举例: create index idx_emp_deptno on emp (deptno); 普通索引 create unique index idx_emp_ename on emp (ename); 唯一索引 create index idx_emp_job_sal on emp (job,sal); 复合索引 create index idx_emp_sal on emp (sal*12); 函数索引
select * from emp where deptno=20; select * from emp where ename=‘FORD‘; select * from emp where job=‘MANAGER‘ and sal>=2500; select * from emp where sal*12>=20000;
select * from tab_all_objects where object_id=74975; create index idx_object_id on tab_all_objects (object_id);
--select * from tab_all_objects where object_type=‘SYNONYM‘; --create index idx_object_type on tab_all_objects (object_type);
2.2 修改索引 alter index <ind> {enable | disable}; alter index <ind> rename to <new>; 举例: alter index IDX_EMP_SAL disable; alter index idx_emp_deptno disable; alter index IDX_EMP_SAL rename to IDX_EMP_SAL1; alter index IDX_EMP_SAL1 rename to IDX_EMP_SAL;
2.3 删除索引 drop index <ind>; 举例: --drop index IDX_EMP_SAL;
2.4 分析索引 analyze index <ind> validate structure online|offline; 举例: analyze index IDX_EMP_SAL validate structure online;
2.5 重建索引 alter index <ind> rebuild 举例: alter index IDX_EMP_SAL rebuild;
--授权 connect sys/123 as sysdba; grant create any index,drop any index,alter any index to scott;
三、索引特征 索引是一种模式对象,它在逻辑上和物理上都与其相关联表对象的数据保持独立。 因此,可以删除或创建索引而不会实际影响相关的表。 如果删除一个索引,应用程序将仍然可以工作。不过,访问之前通过索引访问的数据可能会变慢。 索引的存在与否,不需要改变任何sql语句的写法。 索引是到单一行数据的快速访问路径。它只影响执行的速度。 对于一个已被索引的给定的数据值,索引直接指向包含该值的行的位置。 在表上存在过多的索引,会降低dml性能,因为数据库还必须更新索引。 主键和唯一键会自动生成索引,但需要手动在外键上创建索引。 create index ind_emp_deptno on emp_test (deptno); select * from emp,dept where emp.deptno=dept.deptno;
四、复合索引 复合索引,也称为连接索引,是在某个表中的多个列上的索引。 复合索引中的列应该以在检索数据的查询中最有意义的顺序出现,但在表中不必是相邻的。 若 where 子句引用了复合索引中的所有列或前导列, 复合索引可以加快 select 语句的数据检索速度。 所以,在定义中所使用的列顺序很重要。一般地,最常被访问的列放在前面。
五、唯一索引和非唯一索引 索引可以是唯一的或非唯一的。 唯一索引保证在表的键列或键列集上没有具有重复的值的行。 在一个唯一索引中,对每个数据值都存在一个 rowid。叶块中的数据仅根据键排序。 非唯一索引允许在索引的列或列集中有重复的值。 对于非唯一索引,rowid 被包含在键中且已排序, 因此非唯一索引按索引键和 rowid (升序) 进行排序。
六、索引类型 索引类型分为:b-树索引、位图索引、基于函数的索引
6.1 b-树索引 这是索引的标准类型。对于主键和高选择性索引非常适合。 平衡树,简称b-树,是最常见的数据库索引类型。 一个 b-树索引是被划分为多个范围的已排序的值列表。 通过将键与一行或行范围关联起来 ,b-树可以对多种类型的查询提供优秀的检索性能, 包括精确匹配和范围搜索等。
二分查找算法是在有序数组中用到的较为频繁的一种算法。 在未接触二分查找算法时, 最通用的一种做法是,对数组进行遍历,跟每个元素进行比较,其时间为O(n). 但二分查找算法则更优,因为其查找时间为O(lgn)。 比如数组{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},查找元素6, 用二分查找的算法执行的话,其顺序为: 1.找中位数,用中位数和6比较,如果中位数比6大,则在中位数左侧数组中查找;如果中位数比6小,则在中位数右侧数组中查找; 2.循环步骤1,直到等于要查找的值,并返回;或者找不到要查找的值,则返回空。
select index_type,count(1) from dba_indexes where 1=1 group by index_type order by count(1) desc; 1 NORMAL 3681 2 LOB 901 BLOB、CLOB列产生的,非单独索引(view PLAN_TABLE$;) 3 IOT - TOP 158 索引组织表的主键索引(view SQLLOG$;) 4 FUNCTION-BASED NORMAL 40 基于函数的索引(view DBFS$_MOUNTS;) 5 BITMAP 16 位图索引 6 CLUSTER 10 7 FUNCTION-BASED DOMAIN 4 8 DOMAIN 1
create bitmap index SH.SALES_PROD_BIX on SH.SALES (PROD_ID);
6.2 位图索引 在位图索引中,索引条目使用位图来指向多个行。 create index idx_emp_deptno on emp (deptno); drop index idx_emp_deptno; create bitmap index idx_emp_deptno on emp (deptno);
6.3 基于函数的索引 这种类型的索引包括经过一个函数(如upper函数)转换过的列,或包括在表达式中的列。 create index idx_emp_ename_lower on emp (lower(ename));
七、索引扫描 在索引扫描中,数据库使用语句指定的索引列,通过遍历索引来检索行。 数据库扫描索引,将使用n个i/o就能找到其要查找的值,其中 n 即是b-树索引的高度。 这是数据库索引背后的基本原理。 如果 sql 语句仅访问被索引的列,那么数据库只需直接从索引中读取值,而不用读取表。 如果该语句同时还需要访问除索引列之外的列,那么数据库会使用 rowid 来查找表中的行。 通常,为检索表数据,数据库以交替方式先读取索引块,然后读取相应的表块。
7.1.完全索引扫描 INDEX FULL SCAN select emp.* from emp,dept where emp.deptno=dept.deptno; 在完全索引扫描中,数据库顺序读取整个索引。 如果在 sql 语句中的谓词 (where 子句) 引用了一个索引列, 或者在某些情况下未不指定任何谓词,此时可能使用完全索引扫描。 完全扫描可以消除排序,因为数据本身就是基于索引键排过序的。
7.2快速完全索引扫描 INDEX FAST FULL SCAN select view_name from tab_all_views; --all rows 快速完全索引扫描是一种完全索引扫描,数据库并不按特定的顺序读取索引块。 数据库仅访问索引本身中的数据,而无需访问表。 当索引包含了查询所需的所有列,且索引键中至少一列具有 not null 约束时,快速完全索引扫描可以替代全表扫描。
7.3 索引范围扫描 INDEX RANGE SCAN create index idx_emp_deptno on emp (deptno); select * from emp where deptno=10; 索引范围扫描是对索引的有序扫描,具有以下特点: 在条件中指定了一个或多个索引前导列。 条件指定一个或多个表达式和逻辑 (布尔) 运算符的组合,并返回一个值( true、 false,或unknown)。 一个索引键可能对应0个、1个或更多个值。 通常,数据库使用索引范围扫描来访问选择性的数据。 选择性是查询所选择的数据占总行数的百分比, 0 意味着没有任何行,1 表示所有行。 选择性与一个(或多个)查询谓词相关,比如where last_name like ‘a%‘。 值越接近 0的谓词越具有选择性,相反,越接近1的谓词则越不具有选择性。
7.4 唯一索引扫描 INDEX UNIQUE SCAN select * from emp where empno=7788;
相对于索引范围扫描,唯一索引扫描必须是 有0个 或 1个 rowid 与索引键相关联。 当一个谓词使用相等运算符引用了唯一索引键的所有列时,数据库将执行唯一扫描。 只要找到了第一个记录,唯一索引扫描就停止处理,因为不可能有第二个记录满足条件。
7.5 索引跳跃扫描 INDEX SKIP SCAN 如果在复合索引前导键列中有少量不同值,而在非前导键列中有大量不同值,此时使用跳跃扫描是有益的。 --建表 create table stu ( sex varchar2(1) not null, sid number(8) ); --建复合索引 create index idx_stu_sexandsid on stu(sex,sid); --插数据 declare begin for i in 1..1000 loop insert into stu values(‘M‘,i); end loop; for i in 1001..2000 loop insert into stu values(‘F‘,i); end loop; end; --分析表 analyze table stu compute statistics; --分析SQL执行计划 select * from stu where sid=100; 索引跳跃扫描使用复合索引的逻辑子索引。 数据库“跳跃地”通过单个索引,好像它在多个单独的索引中搜索一样。 当在查询谓词中未指定组合索引的前导列时,数据库可能选择索引跳跃扫描。
索引是根据指定的数据库表列建立起来的顺序。 它提供了快速访问数据的途径,并且可监督表的数据,使其索引所指向的列中的数据不重复。 分为单列索引和组合索引。 主键、唯一键系统自动创建索引,外键系统不会自动创建索引。 外键不创建索引时将导致父子表连接查询时出现子表的全表扫描。
伪列rowid 1.定义: oracle数据库的表中的每一行数据都有一个唯一的标识符,或者称为rowid, 在oracle内部通常就是使用它来访问数据的。 rowid需要 10个字节的存储空间,并用18个字符来显示。 该值表明了该行在oracle数据库中的物理具体位置。 可以在一个查询中使用rowid来表明查询结果中包含该值。 select rowid,emp.* from emp where rowid=‘AAAR3sAAEAAAACXAAA‘; 73196
2.存储 保存rowid需要10个字节或者是80个位二进制位。 这80个二进制位分别是: 1. 数据对象编号,表明此行所属的数据库对象的编号,每个数据对象在数据库建立的时候 都被唯一分配一个编号,并且此编号唯一。数据对象编号占用大约32位。 2. 对应文件编号,表明该行所在文件的编号,表空间的每一个文件标号都是唯一的。 文件编号所占用的位置是10位。 3. 块编号,表明改行所在文件的块的位置块编号需要22位。 4. 行编号,表明该行在行目录中的具体位置行编号需要16位。 这样加起来就是80位。
3.显示 Oracle的物理扩展ROWID有18位,每位采用64位编码,分别用A~Z、a~z、0~9、+、/共64个字符表示。 A表示0,B表示1,……Z表示25,a表示26,……z表示51,0表示52,……,9表示61,+表示62,/表示63。 64位编码表示的ROWID有18位,其中: 数据对象编号占6位; 文件编号占3位; 块编号占6位; 行编号占3位。 select log(2,64),log(2,64)*18 from dual;
4.举例: select rowid,empno,ename from emp; 将会得到结果: AAAR3sAAEAAAACXAAA 说明: AAAR3s是数据库对象编号,AAE是文件标号,AAAACX是块编号,最后三位AAA(SMITH)是行编号。
5.验证 5.1 验证行编号 SMITH --> AAA ALLEN --> AAB 不同人名 行号是递增的。 5.2 验证数文件标号 select FILE_ID as fid,FILE_NAME from dba_data_files where TABLESPACE_NAME=‘USERS‘ ; FID FILE_NAME ---------- --------------------------------------------- 4 D:APPWANGXUWEIORADATAORCLUSERS01.DBF FILE_ID=4,就是ROWID中AAE。 5.3 验证数据库对象编号 select * from dba_objects where object_name=‘EMP‘; objectid 73196 73196 = AAAR3s ??? select ascii(‘R‘)-ascii(‘A‘) from dual; R=17=17×64×64
3=26+26+3=55 select ascii(‘s‘)-ascii(‘a‘)+26 from dual; s=44 AAAR3s=17×64×64+55×64+44 select 17*64*64+55*64+44 from dual; 73196
5.4 验证块编号 select * from dba_extents where segment_name=‘EMP‘; extent_id =0 file_id =4 block_id =144 bytes =65536 blocks =8 144 = AAAACX ??? select ascii(‘X‘)-ascii(‘A‘) from dual; 23 AAAACX=2×64+23= select 2*64+23 from dual; 151 AAAACX=151<>144 ???
6.dbms_rowid包 通过dbms_rowid包,可以直接得到具体的rowid包含的信息: select dbms_rowid.rowid_object(rowid) object_id, dbms_rowid.rowid_relative_fno(rowid) file_id, dbms_rowid.rowid_block_number(rowid) block_id, dbms_rowid.rowid_row_number(rowid) row_number, rowid,emp.* from emp;
通过dbms_rowid包,还可以查询到表或记录所在的文件select file_id,file_name from dba_data_files where file_id in (select distinct dbms_rowid.rowid_relative_fno(rowid) from scott.emp);file_id file_name4 D:APPORADATAORCLUSERS01.DBF
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|