Oracle性能优化-1-索引
1.索引的基本概念
访问表的数据时,有两种方式,通过全表扫描找到这一行,或者通过ROWID找到该数据。当需要检索的数据所占表数据5%及一下的时候,考虑创建索引。使用索引要防止数据分散在多个块中。
不是创建索引越多越好,新建一个索引,将增加insert三倍的时间,update一倍的时间,DML操作都是先查找,再操作,索引减少的只是查找的时间。
索引查询SQL
select * from dba_indexes d where d.table_name='MTL_SYSTEM_ITEMS_B';
select * from dba_ind_columns d where d.INDEX_NAME='MTL_SYSTEM_ITEMS_B_U1';
2.隐藏索引
alter index INV.MTL_SYSTEM_ITEMS_B_U1 invisible;
alter index INV.MTL_SYSTEM_ITEMS_B_U1 visible;
隐藏索引相当于暂时失效该索引,但是索引仍旧正常维护。
隐藏了物料表的唯一性索引,再去查询,时间花费几百倍增加
3.复合索引
建立复合索引
create index emp_t1 on emp(ENAME,JOB,DEPTNO);
但是要想复合索引生效,必须在where子句中出现先导列ENAME。
可以自行查看下面两个SQL的执行计划,后者没有使用索引
select * from emp where ENAME='JAMES';
select * from emp where DEPTNO=30 and job='CLERK';
当然我们也可以强制使用索引(不知道对性能有没有效果,但是执行计划是使用到了索引)
select /*+index(S emp_t1)*/ * from emp s where DEPTNO=30 and job='CLERK';
4.索引抑制
虽然我们创建了索引,但是某些查询下索引失效了,比如
4.1不等于运算符<>=!
4.2is null is not null
位图索引(含有大量重复数据可以使用)会消除is null造成的索引抑制?
4.3like
like '123%',%在字符后面才会走索引
4.4函数
trunc to_char substr等
create index emp_t3 on emp(substr(empno));
测试的时候发现索引并没有生效,原因是empno是number类型,使用substr做了隐式转换
重新测试后发现,函数索引不支持嵌套函数,而测速varchar2类型的JOB字段是正常的
create index emp_t4 on emp(substr(job,1,4));
那么要截取数字怎么实现,可以使用trunc,取负数就可以截取前多少位整数
create index emp_t5 on emp(trunc(empno,-1)/10);
4.5隐式转换
在上述的函数索引中,number类型的empno遇到substr自动做了to_char转换
我们默认左边是字段名
1左边是数字,右边字符:索引有效
2左边字符,右边数字:索引失效
解决办法,将数字加上引号
5索引价值
用dbs_index表可以看到索引的好坏
查询mtl_system_items表的所有索引
select ui.index_name,ui.distinct_keys,ui.num_rows from DBA_indexes ui where ui.index_name like 'MTL_SYSTEM_ITEMS_B_%';
distinct_keys是有多少个不一样的非空值,num_rows是有多少个非空值
拿N3举例,不一样的非空值只有10个
而这个字段INVENTORY_ITEM_STATUS_CODE,非空值有26592个,也就是用status_code查询,将会返回大概10%的数据
distinc_keys值越少,则效果越差
实际返回值如下
用active值去检索,还不如全表扫描
除了隐藏索引,还有别的办法失效索引吗?这个问题先留着
这里使用NO_INDEX
select /*+ no_index (msi MTL_SYSTEM_ITEMS_B_N3 )*/ * from mtl_system_items_b msi where msi.inventory_item_status_code='Active'
我们查询dba_index表,看看有哪些选择性不好的索引
select TABLE_NAME,ui.index_name,ui.distinct_keys,ui.num_rows,trunc(ui.distinct_keys / ui.num_rows, 10)from DBA_indexes uiwhere ui.num_rows / distinct_keys > 10000and ui.num_rows > 10000order by ui.num_rows desc
第十三行明显是我们要找的目标
隐藏该索引,查询时间反而变快了
alter index wsh.WSH_DD_TXNS_N2 invisible
ALTER SYSTEM FLUSH SHARED_POOL alter system flush buffer_cache ALTER SYSTEM FLUSH GLOBAL CONTEXT 清除缓存,然后分别测试失效或者生效该索引总共花费的时间
隐藏索引:0.18S
显示索引:0.5S
区别好像不是很大,各位可以自行测试。
6.聚簇
select ui.index_name, ui.distinct_keys, ui.num_rows, ui.clustering_factorfrom DBA_indexes ui
逐行扫描索引,如果下一个索引指向的块和上一个索引指向的块不一样,则clustering_factor+1
clustering_factor越大,则索引需要扫描的块越多,性能越差。
7.索引树
数据库索引分为B*索引和位图索引。
7.1B*索引
7.1.1B-树
在讲B*索引前,我们先看看B树。所谓B树,实际上是B-TREE,B-树,-是连字符。
看下面一张图,B树有几个参数
阶数M:所有非叶子节点最大的子树个数,节点23-30有三个分支,且是该树最大的分支数,则该树阶数为3
关键字:value作为关键词,存放在节点中,比如18,33关键字存放在根节点中,每个节点最大的关键字个数不能超过M-1,所以下图找不到关键词大于2的节点
树高H:除开非叶子节点的节点层数。该树有三层,树高为3
但是上图很让人迷惑,18和33,中间怎么指向了节点23和30?我们展开来看
上图给出了红圈中的节点分布情况
比如18-33关键词,存放在数组或者链表中,假设为数组A,则A[0]指向存放关键词12的数组,A[2]存放指向关键词23-30的数组中。
对于B树,可以发现,假设每一个红圈指数组,则
1.每一个数组的关键词都是升序排列
2.节点左子树小于该节点所有的关键词
3.节点中间子树处于关键词之间
4.节点右子树大于该节点所有关键词
B树的增删改节点我们不提,讲一下查找节点,比如查找节点21
从根节点18-33出发,因为18<21<33,因此指向中间节点23-30
21<23<30,因此指向左节点20-21
21=21,因此找到最终的节点21
7.1.2B+树
我们把
改成B+树,如下图
B+树有这样几个特点
1.根节点中的最大关键词是整个树的最大关键词
2.父节点的关键词将作为子节点的最大关键词存在
3.子节点小于父节点
4.每一个节点关键词数量对应子树的个数
5.叶子节点存有所有关键词,每一个叶子节点用链表顺序排列
贴上百度给出的B+树概念
B+树范围查找性能比B树更高,比如查找18-30,先找到叶子节点18,然后按链表顺序查找到30
B+树叶子节点含有所有关键词,查找速度稳定
B+树中间节点不含卫星数据,IO性能更好(这个不太理解)
7.1.3B*树
参考B*-Trees implementation in C++ - GeeksforGeeks
https://www.quora.com/What-are-B*trees
B*-tree of order m is a search tree that is either empty or that satisfies three properties:
- The root node has minimum two and maximum 2 floor ((2m-2)/3) +1 children
- Other internal nodes have the minimum floor ((2m-1)/3) and maximum m children
- All external nodes are on the same level.
The advantage of using B* trees over B-trees is a unique feature called the ‘two-to-three’ split. By this, the minimum number of keys in each node is not half the maximum number, but two-thirds of it, making data far more compact. However, the disadvantage of this is a complex deletion operation.
The difficulties in practically implementing a B-star algorithm contribute to why it’s not as regularly used as its B and B+ counterparts.
Below is a basic implementation of the B-star insertion function – just to demonstrate its contrast from B (full implementation would be far more lengthy and complex).
看不太懂,略过
ORACLE的常见索引之一是B*索引,是B+树的变体
7.1.4树高
三层树高对B*树而言,已可以存放千万级的数据量了,也就是三次IO,一次内存中的读取。
7.2位图索引
7.2.1使用条件
前面提到了“索引价值”,也就是某列中不同的非空值得个数,占非空总行数得多少。假如一个表有10000条数据,一半男,一半女。那么为性别建立B*索引,性能将会很差,也就是“索引价值”低。
B*索引适合选出5%以下的数据,或者使用索引快速全扫描,计算count(*)数量。而对这种性别数据建立索引,适合位图索引。也就是
1.“索引价值”(相异基数)低的数据。
2.适合频繁读而不是频繁写的表,使用位图索引会降低并发效率。
7.2.2使用位图索引
我们先测试一下dbms_random.value函数
select dbms_random.value(1, 2) from dual connect by level < 10000
效果是产生1到2之间的10000条数据
我们可以使用这种方式创建我们需要的数据
create table test_bitmap(sex , age , score ) as
select decode(round(dbms_random.value(1, 2)),1,'F',2,'M'), round(dbms_random.value(18, 35)),round(dbms_random.value(0, 100))from dual connect by level <= 1000000
我们插入了100万条数据,然后分别测试B*索引和位图索引的性能
select /*+ no_index(tb test_bitmap_b1) no_index(tb test_bitmap_b2) index(tb test_bitmap_n1)*/count(*)from test_bitmap tbwhere 1 = 1and age between 18 and 22and sex = 'M'
select /*+ no_index(tb test_bitmap_n1 )*/
count(*)from test_bitmap tbwhere 1 = 1and age between 18 and 22and sex = 'M'
运行时间上两者没有区别,如何判断执行效率,我们弄清执行计划后,再回来解决这个问题。
7.2.3位图索引原理
oracle 位图索引
比如我有一个表有两个字段,部门和职位。部门有10 20 30 40 四个值。职位有salesman销售员,manager管理员,janitor清洁工,clerk记账员
如果我要查询20部门的所有记账员,就可以使用位图索引。
假如我有5个人ABCDE,他们的部门和职位情况如下
图中我们可以看到,A是20部门,30部门没有人
如果我们吧ABCDE排个队,A永远是第一位,B是第二位……
如下
那么有人的位置我们用1代表,0代表没有人,上图变成这样:
于是我们可以用四条5位二进制数,表示各个职位是哪些人
同理,将职位也做成上面这种图
我们要找部门20,职位是S,则将两个数取出来,做逻辑与操作
10010
and
10000
=
10000
也就是第一位的A,是20部门的销售员。
当然只找出部门为20的所有人,就不用作逻辑与操作了。上面每一个格子都对应这条数据的rowid
01 02 03 三条记录的start 和end rowid都是一样的,相当于内存的起止地址
这就是位图索引的原理
7.3哈希索引
略
7.4索引组织表
当我们需要用主键频繁update和delete操作时,可以采用索引组织表,索引组织表会把表的存储结构改成B树结构,以表的主键进行排序
create table Iot_test(
id number primary key,
name varchar2(240)) organization index;
insert into Iot_test(id, name ) values(1,'a');
select * from Iot_test
7.5反向键索引
如果我们的表的主键插入值是靠一个序列或者日期产生,那么该主键就是严格有序的,每当我们插入修改数据,都会修改当前索引右侧的块,会造成IO瓶颈和实例缓冲区忙等待。
比如我们插入1234,1235,1236。先将值反转4321.5321.6321这三个值将分布在索引的各个块上,减少块占用。
create table reverse_test(
id number ,
name varchar2(240));
create index reverse_test_r1 on reverse_test(id) reverse;
insert into reverse_test(id, name ) values(1,'a');
select * from Iot_test
反向键索引不支持范围查询
7.6函数索引
在4.4节我们讲到了函数索引,但是使用的是系统自带的函数,我们也可以使用自定义函数
在7.2.2我们创建了表test_bitmap。
我们创建一个获取字符串长度的函数
create or replace package public_pkg isfunction get_char_long(p_item in varchar2) return number deterministic;end public_pkg;
create or replace package body public_pkg isfunction get_char_long(p_item in varchar2) return number deterministic isl_len number;beginselect LENGTH(p_item) into l_len from dual;return l_len;end;end public_pkg;
注意看到,get_char_long函数用了“deterministic“关键词修饰(否则创建自定义函数索引的时候会报错ORA-30553: The function is not deterministic)
我们先直接查询一下
需要16秒的时间
然后创建函数索引(我这里没有加owner,索引也会创建在apps下,各位请加上空间名)
create index test_bitmap_n2 on test_bitmap(apps.public_pkg.get_char_long(score));
再次查询
速度快了200倍
使用函数索引需设置参数query_rewrite_enabled设置为true,
deterministic相关用法
如果某个函数对于特定的输入值始终返回相同的结果,则认为该函数是确定性的。Oracle文档声称,通过使用DETERMINISTIC子句将流水线表函数定义为确定性的,允许Oracle缓冲其行,从而防止多次执行。但是我找不到证据支持这一说法。
创建函数索引需要权限
GRANT CREATE ANY INDEX TO APPS;
撤回权限
REVOKE GRANT CREATE ANY INDEX FROM APPS;
创建函数索引,return null 则不会为此条目创建索引,大大减小了索引的节点数
7.6分区索引
略
7.7位图连接索引
比如我们需要查某个部门有多少人,我们会写出以下查询
select count(*)from emp, deptwhere emp.deptno = dept.deptnoand dept.dname = 'SALES'
为提升性能,我们需要创建emp的deptno索引,dept的deptno索引。
不过我们可以创建位图连接索引,使得只需要访问表emp
需要注意的是表dept的deptno必须有唯一性索引
create bitmap index emp_bm_idx on emp(d.dname) from emp e,dept d where e.DEPTNO=d.DEPTNO
select /*+ no_index ( dept SYS_C00876080) no_index ( emp emp_t1) */count(*)from emp, deptwhere emp.deptno = dept.deptnoand dept.dname = 'SALES'
执行计划
只访问到了一张表
不过对性能的影响不直观
7.8重建索引
当表被频繁的更新或者删除时,索引某些页块将会空缺,这是重建索引将会使得索引更加紧凑,但是用什么判断是否需要重建,这个问题先留下来。
语法:
ALTER INDEX REBUILD
测试一个在线重建索引吧
拿我们的表test_bitmap测试
alter index TEST_BITMAP_N2 rebuild online;--parallel为快速重建,online为在线重建
8.直方图
当数据的distinct_keys较小的时候,也就是一次查询会返回大部分表的数据,构造直方图,使得成本优化器不采取索引。
create table histogram (
id number,
seq number
);
drop index histogram_n1;
create index histogram_n1 on histogram(id);
beginfor i in 1 .. 100000 loopinsert into histogram (id, seq) values (1, i);commit;end loop;insert into histogram (id, seq) values (2, 0);commit;
end;
然后在command界面执行下面代码
SQL> execute dbms_stats.gather_table_stats('apps','histogram',method_opt => 'FOR COLUMNS SIZE 10 ID')
PL/SQL procedure successfully completed
正常来说表空间和索引空间不应该是同一个,我这里为了测试简化了
发现这个直方图构造没有效果,各位可以尝试下
9.快速全扫描
我们在第三节学到了索引全扫描index full scan,这里我们使用index fast full scan
select /*+index_ffs(S emp_t1)*/ ENAME, JOB, DEPTNO from emp s where DEPTNO=30 and job='CLERK'
对比
索引快速全扫描的要求是,select from 之间出现的字段是索引中出现的,且where条件只含索引字段
索引全扫描的要求是,select from 之间出现的字段没有要求,且where条件有索引字段
Oracle中的全索引扫描和快速全索引扫描之间有什么区别?
10.索引跳跃式扫描SS
select /*+index_ss(S emp_t1)*/ ENAME, JOB, DEPTNO from emp s where 1=1 and JOB='1' and mgr=1
用法等同于索引全扫描。
当先导列的唯一值越少,跳跃扫描效果越好
11.删除效果不好的索引
当分别为两个字段建立索引,同时查询条件含有这两个字段,如下:
create table cux_students(score number,sex varchar2(1));
create index cux_students_n1 on cux_students(score);
create index cux_students_n2 on cux_students(sex);
DECLAREl_score NUMBER;
BEGINFOR i IN 1 .. 10000000LOOPl_score := trunc(dbms_random.value(0,100));INSERT INTO cux_students(score,sex)VALUES(l_score,'M');COMMIT;END LOOP;
END;
往表cux_students插入了1百万条数据,分数随机产生,但是性别全是M
SELECT *FROM cux_students cWHERE 1 = 1AND c.score = 90AND c.sex = 'M'
发现优化器自动否决了索引N2,最好情况是删除索引价值低的索引,或者建立复合索引
Oracle性能优化-1-索引相关推荐
- oracle性能优化总结
Oracle性能优化 一.数据库优化的方向 1.程序设计(这点最重要,如果程序本身设计有问题,再怎么进行下面的优化都是徒劳的.) 2.操作系统优化 3.硬件优化 4.数据库优化 5.SQL语句优化 二 ...
- oracle性能优化之awr分析
oracle性能优化之awr分析 作者:bingjava 最近某证券公司系统在业务期间系统运行缓慢,初步排查怀疑是数据库存在性能问题,因此导出了oracle的awr报告进行分析,在此进行记录. 导致系 ...
- 如何“暴力破解”Oracle性能优化的极端问题(附精彩案例解读)
云和恩墨大咖系列报道 2019数据技术嘉年华于11月16日在京落下了帷幕.大会历时两天,来自全国各地上千名学术精英.数据库领袖人物.数据库专家.技术爱好者在这里汇聚一堂,围绕"开源 • 智能 ...
- Oracle性能优化 以及 库缓存命中率及等待事件
http://www.cnblogs.com/hyddd/archive/2009/08/30/1556939.html 前言 最近hyddd一直看Oracle的资料,今天特地总结一下这段时间了解到的 ...
- Oracle性能优化专题
Oracle优化是开发人员必须掌握的技能,与其说是技能不如是开发基本.而且在面试过程中这个话题也常常被问到,有一两年工作经验的童鞋面试这个问题是肯定要被问到的,如果知识简单的CRUD实现功能,则是没有 ...
- oracle 优化建议,oracle 性能优化建议小结
原则一:注意WHERE子句中的连接顺序:ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子 ...
- 简单介绍oracle执行计划,Oracle性能优化之oracle中常见的执行计划及其简单解释
一.访问表执行计划 1.table access full:全表扫描.它会访问表中的每一条记录(读取高水位线以内的每一个数据块). 2.table access by user rowid:输入源ro ...
- ppst 技术视频——oracle 性能优化
ppst 技术视频--oracle 性能优化:请访问ppst 技术视频分享平台 , www.ppst.cc,上面有最新的技术视频 在过去的十年中,Oracle已经成为世界上最专业的数据库之一.对于IT ...
- Oracle执行exists优化,PHP_解决Oracle性能优化中的问题, 在Oracle性能优化时,用exists - phpStudy...
在Oracle性能优化时,用exists替代in,用表链接替代exists,关于前者,一般效果比较明显,exists效率明显比in高,但是如果要想表连接的效率比exists高,必须在from子句中,将 ...
- SQL Server 查询性能优化——覆盖索引(二)
在SQL Server 查询性能优化--覆盖索引(一) 中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索 ...
最新文章
- RDKit | 基于RDKit的SMILES转canonical SMILES
- webpack的build的时候时间长处理方案
- matlab怎么画一箭穿心,MATLAB学习与使用:如何绘制三维心形图 经验告诉你该这样...
- pycharm快捷键_春节快结束了回单位途中总结下pycharm快捷键
- 解决hibernate双向关系造成的一方重复执行SQl,或者死循环的问题
- matlab 指定区域随机游走_了解随机游走模型和移动平均过程(Python)
- ir指令、立即数的作用_ARM指令中使用立即数详解
- Machine Learning - XVII. Large Scale Machine Learning大规模机器学习 (Week 10)
- linux系统一键安装php运行环境apache,mysql等
- 数据分析实战项目练习——餐厅订单数据
- java 获取本机ip地址吗_java 获取本机ip地址
- 插值算法(数学建模学习)
- 样式和多级编号的关系
- 留学生如何搞定Extended Essay?
- 学编程以来第一次遇到的灵异事件
- 烂泥:关于安装LiveZilla,MySql数据库的问题
- 移动开发中的基础知识总结
- fastlane 项目管理_在fastlane上获取您的android项目
- SpringBoot + Vue 结合支付宝支付(3)--调用api
- 好听的敕勒川天苍苍野茫茫风吹草低见牛羊
热门文章
- 充电五分钟即可充满手机 石墨烯电池会是未来吗?
- 毕胜揭密零售业加价体系 首家C2M电商“必要”亮相
- 3到6年的.NETer应该掌握哪些知识?
- 大众点评点餐小程序开发经验 - 发布与推广
- 雪城大学计算机科学专业,雪城大学计算机科学专业概论.pdf
- 【跟我学apache-commons】【四】commons-io的使用
- 成都真的挺好的,但是求求你们别来了
- [网络安全自学篇] 三十八.hack the box渗透之BurpSuite和Hydra密码爆破及Python加密Post请求(二)
- Java线程池ThreadPool详解
- 黄聪:搜索引擎原理系列视频教程1.0