暂无图片
组合索引问题
我来答
分享
lu9up的数据库笔记
2023-09-19
组合索引问题

oracle中,为什么order by的字段要放在联合索引的最后?

我来答
添加附件
收藏
分享
问题补充
6条回答
默认
最新
广州_老虎刘

严格来说没有放到最后的说法. 有几种情况:

1.如果经过where条件过滤后返回的结果集比较小, 索引不包含order by字段, 做个排序也没关系; 

2.如果过滤条件都是等值条件,而且返回的结果集有点大, 为了避免排序, order by字段确实是放到最后; 

3.如果过滤条件含有非等值条件, 比如>,< , like , <> 等, 这个时候order by 字段就不是最后,而是非等值条件放到最后(减少回表) , 这种组合索引的创建原理叫ESR(equal,sort,range)理论. 

4. 如果返回列较少,可以再把返回列加上,,成ESRR,那就是在组合索引的最后增加返回列.  形成覆盖索引, 能进一步减少回表.    

具体使用什么样的索引, 归根结底还是要根据表上各字段的数据分布决定.

暂无图片 评论
暂无图片 有用 1
暂无图片
lu9up的数据库笔记
题主
2023-09-19
大佬,能解释一下原理吗?
lnn

提高查询性能,减少排序操作开销

暂无图片 评论
暂无图片 有用 4
张sir

由于索引是有序的,对于一个组合索引(a,b,c),首先是按a排序,在a相同的情况下,按b排序,在a,b都相同的情况下,按c排序。再一个查询中where a=1and b=2 order by c。这个时候记录是按c排序的,可以利用索引的有序性,直接返回记录,无需再进行排序。

暂无图片 评论
暂无图片 有用 3
Rocky

首先联合索引中的各列都是排序的,前导列和后面的where中的过虑掉数据,过滤后留下的数据就是需要的数据,因为order by已经在索引中排序,这样就利用索引消除了排序。有时为了减少回表,会将select后的列放在索引最后。

暂无图片 评论
暂无图片 有用 2
Thomas

对此我有点疑惑:

create table t (c1 varchar2(10),c2 varchar2(10),c3 varchar2(10));

insert into t values ('a','b','h');
insert into t values ('x','y','a');
insert into t values ('a','b','c');
commit;
create index idx_t on t(c1,c2,c3);
那么idx_t索引内容应该如下
a b c 第三行rowid
a b h 第一行rowid
x y a 第二行rowid

select * from t where c1='a' and c2='b' order by c3;
那么filter时走索引idx_t,因为c3是联合索引的后部列,所以filter后的次序就是按c3排序的,无须再排序。

drop index idx_t;
create index idx_r on t(c3,c1,c2);
那么idx_r索引内容应该如下
x y a 第二行rowid
a b c 第三行rowid
a b h 第一行rowid

select * from t where c1='a' and c2='b' order by c3;
那么filter时仍走索引idx_r, 因为c3是联合索引的前导列,所以filter后的次序就是按c3排序的,也无须再排序。

既然两种情况都可以省略掉排序这步,为什么说c3列必须在联合索引的后部?

暂无图片 评论
暂无图片 有用 1
lu9up的数据库笔记
题主
2023-09-19
第一种c3列在组合索引后面情况,我试了一下是不用回表做filter的: -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 42 | 1 (0)| 00:00:01 | |* 1 | INDEX RANGE SCAN| IDX_T | 2 | 42 | 1 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("C1"='a' AND "C2"='b') 第二种c3列为引导列,有回表: -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 42 | 1 (0)| 00:00:01 | |* 1 | INDEX FULL SCAN | IDX_R | 2 | 42 | 1 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("C1"='a' AND "C2"='b') filter("C1"='a' AND "C2"='b')
Thomas

第二种有回表?我没看出来啊。如果有,应该有access table by rowid字样,可是第二种的执行计划里并没有啊。

暂无图片 评论
暂无图片 有用 0
Rocky
2023-09-21
第二个是走index full scan 你可以再这个表多加几列并且设置成char类型 将表数据加到百万以上,实际上就是创造一个大表 再观察下结果 是不是变成TABLE ACCESS FULL + SORT ORDER BY 但是如果返回数据量较少的情况下,还是可以走第一个索引的
回答交流
提交
问题信息
请登录之后查看
邀请回答
暂无人订阅该标签,敬请期待~~
暂无图片墨值悬赏