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-索引相关推荐

  1. oracle性能优化总结

    Oracle性能优化 一.数据库优化的方向 1.程序设计(这点最重要,如果程序本身设计有问题,再怎么进行下面的优化都是徒劳的.) 2.操作系统优化 3.硬件优化 4.数据库优化 5.SQL语句优化 二 ...

  2. oracle性能优化之awr分析

    oracle性能优化之awr分析 作者:bingjava 最近某证券公司系统在业务期间系统运行缓慢,初步排查怀疑是数据库存在性能问题,因此导出了oracle的awr报告进行分析,在此进行记录. 导致系 ...

  3. 如何“暴力破解”Oracle性能优化的极端问题(附精彩案例解读)

    云和恩墨大咖系列报道 2019数据技术嘉年华于11月16日在京落下了帷幕.大会历时两天,来自全国各地上千名学术精英.数据库领袖人物.数据库专家.技术爱好者在这里汇聚一堂,围绕"开源 • 智能 ...

  4. Oracle性能优化 以及 库缓存命中率及等待事件

    http://www.cnblogs.com/hyddd/archive/2009/08/30/1556939.html 前言 最近hyddd一直看Oracle的资料,今天特地总结一下这段时间了解到的 ...

  5. Oracle性能优化专题

    Oracle优化是开发人员必须掌握的技能,与其说是技能不如是开发基本.而且在面试过程中这个话题也常常被问到,有一两年工作经验的童鞋面试这个问题是肯定要被问到的,如果知识简单的CRUD实现功能,则是没有 ...

  6. oracle 优化建议,oracle 性能优化建议小结

    原则一:注意WHERE子句中的连接顺序:ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子 ...

  7. 简单介绍oracle执行计划,Oracle性能优化之oracle中常见的执行计划及其简单解释

    一.访问表执行计划 1.table access full:全表扫描.它会访问表中的每一条记录(读取高水位线以内的每一个数据块). 2.table access by user rowid:输入源ro ...

  8. ppst 技术视频——oracle 性能优化

    ppst 技术视频--oracle 性能优化:请访问ppst 技术视频分享平台 , www.ppst.cc,上面有最新的技术视频 在过去的十年中,Oracle已经成为世界上最专业的数据库之一.对于IT ...

  9. Oracle执行exists优化,PHP_解决Oracle性能优化中的问题, 在Oracle性能优化时,用exists - phpStudy...

    在Oracle性能优化时,用exists替代in,用表链接替代exists,关于前者,一般效果比较明显,exists效率明显比in高,但是如果要想表连接的效率比exists高,必须在from子句中,将 ...

  10. SQL Server 查询性能优化——覆盖索引(二)

    在SQL Server 查询性能优化--覆盖索引(一)  中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索 ...

最新文章

  1. RDKit | 基于RDKit的SMILES转canonical SMILES
  2. webpack的build的时候时间长处理方案
  3. matlab怎么画一箭穿心,MATLAB学习与使用:如何绘制三维心形图 经验告诉你该这样...
  4. pycharm快捷键_春节快结束了回单位途中总结下pycharm快捷键
  5. 解决hibernate双向关系造成的一方重复执行SQl,或者死循环的问题
  6. matlab 指定区域随机游走_了解随机游走模型和移动平均过程(Python)
  7. ir指令、立即数的作用_ARM指令中使用立即数详解
  8. Machine Learning - XVII. Large Scale Machine Learning大规模机器学习 (Week 10)
  9. linux系统一键安装php运行环境apache,mysql等
  10. 数据分析实战项目练习——餐厅订单数据
  11. java 获取本机ip地址吗_java 获取本机ip地址
  12. 插值算法(数学建模学习)
  13. 样式和多级编号的关系
  14. 留学生如何搞定Extended Essay?
  15. 学编程以来第一次遇到的灵异事件
  16. 烂泥:关于安装LiveZilla,MySql数据库的问题
  17. 移动开发中的基础知识总结
  18. fastlane 项目管理_在fastlane上获取您的android项目
  19. SpringBoot + Vue 结合支付宝支付(3)--调用api
  20. 好听的敕勒川天苍苍野茫茫风吹草低见牛羊

热门文章

  1. 充电五分钟即可充满手机 石墨烯电池会是未来吗?
  2. 毕胜揭密零售业加价体系 首家C2M电商“必要”亮相
  3. 3到6年的.NETer应该掌握哪些知识?
  4. 大众点评点餐小程序开发经验 - 发布与推广
  5. 雪城大学计算机科学专业,雪城大学计算机科学专业概论.pdf
  6. 【跟我学apache-commons】【四】commons-io的使用
  7. 成都真的挺好的,但是求求你们别来了
  8. [网络安全自学篇] 三十八.hack the box渗透之BurpSuite和Hydra密码爆破及Python加密Post请求(二)
  9. Java线程池ThreadPool详解
  10. 黄聪:搜索引擎原理系列视频教程1.0