mysql索引扫描


一 闲聊

由于之前一直接触的都是mysql,从来没有接触过oracle数据库,新公司用的就是oracle,先像着分析mysql一样看一下oracle
强烈推荐大家看这么书:《高性能MySQL第三版》

二 理论

首先我们使用count(1)进行查询数据的总数:

	select count(1) from DATA_QC_IRREGULAR_DT

经过一段极其墨迹的时间,最终我们发现最终的执行时间达到了192秒,最终的数据总和是:38070178

在这里插入图片描述
因为count(1)并没有使用到对应表的主键进行检索,所以,我们再去分析一下该表中存在的索引是有哪些
由于oracle中的表的索引并不是像mysql那样,可以直接使用

show index from ‘table’

进行查询,oracle中的索引信息是存放在user_indexes和user_ind_columns两张表中,其中

在这里插入图片描述
oracle索引信息中user_ind_columns 表的字段解释可以参考官方网站:https://docs.oracle.com/cd/E11882_01/server.112/e40402/statviews_1103.htm#REFRN20084

由上图可知,该表是创建了一个NORMAL类型的索引,并且索引字JOB_QUEUE,DATA_TABLE_NAME,DATA_CONTENT_ID,RULE_ID
该库建立的是一个组合索引,组合索引的列表为(JOB_QUEUE,DATA_TABLE_NAME,DATA_CONTENTN_ID,RULE_ID)(由对应的COLUMN_POSITION可知)。

在mysql中,对于组合索引,是有一个最左前缀原则,即创建了(a,b,c)的组合索引,则已经对(a)(a,b)(a,b,c)(a,c)上建立索引
例如:

select tableColumn from 表名 where b = ’指定值‘ //不会走(a,b,c)这个组合索引
select tableColumn from 表名 where a = '指定值' and b = ’指定值‘ //会走(a,b,c)这个组合索引

在Oracle同样也对组合索引有一个原则,但是Oracle对于组合索引的执行和mysql稍微不同:对于Oracle的组合索引有一个:INDEX SKIP SCAN(这个新的优化是针对Oracle9i版本之后)
     即组合索引的前导列(索引包含的第一列)没有在查询语句中出现,oracle也会利用该复合索引,这个时候就使用的INDEX SKIP SCAN

Oracle的索引扫描总计五种:

  • INDEX SKIP SCAN(索引跳跃扫描)
  • INDEX UNIQUE SCAN(索引唯一扫描)
  • INDEX RAGEN SCAN(索引范围扫描)
  • INDEX FULL SCAN(索引全扫描)
  • INDEX FAST FULL SCAN(索引快速扫描)

INDEX RAGEN SCAN(索引范围扫描)
针对索引范围扫描,对于创建了组合索引的IND_IRREGULAR_DT(JOB_QUEUE,DATA_TABLE_NAME,DATA_CONTENTN_ID,RULE_ID)
执行:

select JOB_QUEUE from DATA_QC_IRREGULAR_DT where JOB_QUEUE = '12' and  DATA_TABLE_NAME = 'HT_CDM_VISITS'

即为索引范围扫描

INDEX UNIQUE SCAN索引唯一扫描
对于表 table1,如果创建了唯一索引id,执行以下sql语句

select id from test where id = 5000;

即为索引唯一扫描,该索引扫描模式下是速度最快的
INDEX FULL SCAN索引全扫描
对于表来说,有全表扫描。对于索引来说,也存在全索引扫描,与全表扫描非常类似。索引扫描只在CBO模式下起作用。

什么是CBO模式?这就不得不说Oracle的两种优化器:
RBO:Rule-Based Optimization,Oracle 10g版本后被弃用,RBO是基于预先设定好的语法优先级对语法进行执行计划的优化,所以开发者必须非常了解RBO的规则,这种方式非常呆板,因为其只认规则。
CBO:Cost-Based Optimization,Oracle 8引入,Oracle 10g取代了RBO,根据SQL执行情况的统计信息来对SQL的执行计划进行优化,这部分是Oracle公司保密的。问过Oracle公司的讲师说也不清楚具体细节。

这种方式有个特点,会自动对数据进行排序。省去了全表扫描后,再进行order by的操作。
因为B树索引本身就是排序好的,默认是ASC升序,可以在创建索引的时候进行指定。但是Oracle的执行计划会自动针对升序的降序查询进行优化,那么为什么要存在降序操作?答案是:在复合索引上,可以对(a desc,b asc),满足一定的业务场景。

select * from test order by id;

因为排序的条件只有id,并且id已经建立索引,所以执行计划会被优化成INDEX FULL SCAN。
条件:表和表进行连接查询,查询语句中有order by,group by并且子句所有列都在索引中(联合索引)

INDEX FAST FULL SCAN快速全表扫描
快速全表扫描是扫描索引中的所有数据块,与全表扫描比,区别就是其不进行排序,即在这种方式下,返回的数据不是以排序的形式。可以多块读、并行读。所以叫FAST。
对于表test,如果创建了(a,b)组合索引

select a,b from test where b<1000;

这个语句有两个特点,第一:返回值a和b都在索引上,第二:查询条件也在索引上。这条语句通过B树索引查询到rowid后,不需要额外在去原来的表里查数据了。为什么呢?回忆一下,符合索引包括根、枝、叶,叶子上存储的是索引值,包括:rowid、键值、键值长度、所属标号。如果所取的值都在索引上,就可以直接返回了,如果是

select a,b,c from test where b<1000;

这样返回值多了一个c,并不在复合索引上,所以还会用查到的rowid,去原表中取c的值,这样就不会走INDEX FAST FULL SCAN了。

INDEX SKIP SCAN(索引跳跃扫描)
索引跳跃如面说的,如果对于一个表test,创建了(a,b)的组合索引,如果针对于a表,存在只取0或者1的情况下,oracle的优化器oracle的优化器会将其优化成两个索引,分别是当a=0,a=1时的索引。
那么我们在a,b上建联合索引,仿佛有些问题。理论上不会在这样的一个没有多大区分度的a值上建索引的,所以一般看到INDEX SKIP SCAN,其一般开销都很大。

三 示例

user_info表:

在这里插入图片描述
索引信息:
在这里插入图片描述

users表:

在这里插入图片描述
索引信息:
在这里插入图片描述

索引扫描:
1,单表

当查询结果存在于对应的组合索引字段中时(无论顺序)
在这里插入图片描述
当查询结果不存在于对应的组合索引字段中时
在这里插入图片描述
当查询条件(where)存在对应的组合索引字段(最左前缀原则
在这里插入图片描述
在这里插入图片描述
组合索引
id_combin(userName,password,school)–>(userName), (userName,password),(userName,school),(userName,password,school)

在这里插入图片描述
在这里插入图片描述
其中 where 条件没有对应的顺序(where school = ‘12’ and userName = ‘1’)和(where userName = ‘1’ and school= ‘12’) 没有影响

2,排序

对于排序,如果你建立的组合索引 id_combin(userName,password,school),使用如下sql:

explain select * from user_info order by userName

这种是不会走索引:
在这里插入图片描述
这个问题可以参考官方给的这个extra中:Using filesort 参考:https://blog.csdn.net/qq_14869093/article/details/85694897

解决的方法,你需要把对应的查询列包含进去:(这里是不存在左原则)
在这里插入图片描述

3,join
EXPLAIN select * from user_info a LEFT JOIN users b on  a.PASSWORD = b.PASSWORD and a. userName = b.userName where a.userName = '1'

在这里插入图片描述

-- 只走对应的a表索引
EXPLAIN select * from user_info a LEFT JOIN users b on  a.userName = b.userName where a.userName = '1'

b表的组合索引id(password,userName),根据最左原则,因此没有走b表的组合索引,where条件中含有对应a表的组合索引左userName,因此走了a表的索引
在这里插入图片描述

-- order by 不走a索引的问题(需要对应的查询列中含有对应的)
-- 走b索引 
EXPLAIN select * from user_info a LEFT JOIN users b on  a.userName = b.PASSWORD order by a.school

在这里插入图片描述

-- 走a索引
-- 走b索引 
EXPLAIN select a.school from user_info a LEFT JOIN users b on  a.userName = b.PASSWORD order by a.school desc

在这里插入图片描述

-- 不走a索引,因为address并不在组合索引中
-- 走b索引 
EXPLAIN select a.school,a.address from user_info a LEFT JOIN users b on  a.userName = b.PASSWORD order by a.school desc

在这里插入图片描述

发布了55 篇原创文章 · 获赞 14 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/zcswl7961/article/details/102602348