数据库
首页 > 数据库> > Oracle组合索引中列顺序的选择

Oracle组合索引中列顺序的选择

作者:互联网

> 这是一篇介绍关于Oracle数据库组合索引中列顺序的选择,对于SQL效率执行的影响。 ## 什么是组合索引 在Oracle数据库中创建索引时,可以把多个列创建到同一个索引中。这样就组成了组合索引。创建语句 create index idx_tab on tab_name (col1,col2,...); ## 组合索引适用场景 1. 适用在单独查询返回记录很多,组合查询后忽然返回记录很少的情况 比如where 学历=硕士以上 返回不少的记录 比如where 职业=收银员 同样返回不少的记录 于是无论哪个条件查询做索引,都不合适。 可是,如果学历为硕士以上,同时职业又是收银员的,返回的就少之又少了。 于是联合索引就可以这么开始建了。 2. 组合查询的组合顺序,要考虑单独的前缀查询情况(否则单独前缀查询的索引不能生效或者只能用到跳跃索引) 比如你在建id,object_type的联合索引时,要看考虑是单独where id=xxx查询的多,还是单独where object_type查询的多。 ## 组合索引创建原则 1. where条件都是等值查询的情况,列顺序对性能无影响 如:where 职业=收银员 and 学历=硕士以上,职业和学历无顺序影响 2. where条件存在不等值查询情况,等值查询的列在前 如:where 职业=收银员 and 入职时间 > to_date('2020-01-01','yyyy-mm-dd'),则列职业要在组合索引第一位 ## 模拟实验,验证创建原则 ### 环境准备 ``` --创建测试表 create table test_abc ( id number, create_time date, name varchar2(20) ); --插入临时数据 BEGIN FOR i IN 1 .. 100 LOOP FOR j IN 1 .. 100 LOOP insert into test_abc values(i,sysdate+j,to_char(i)); END LOOP; commit; END LOOP; commit; END; / ``` ### 验证1:都是等值查询 1. 索引顺序为id,create_time ``` --创建索引 create index idx_abc_id_time on test_abc (id,create_time); --收集统计信息 execute dbms_stats.gather_table_stats(ownname => 'VIEWDB',tabname => 'TEST_ABC' ,estimate_percent => 10 ,degree=>4,method_opt => 'for all indexed columns' ,cascade => true); set autotrace traceonly SELECT count(*) FROM TEST_ABC WHERE id=80 and create_time = to_date('20210708 03:29:20','yyyymmdd hh24:mi:ss'); ``` ![图片 3.png](http://www.icode9.com/i/li/?n=2&i=images/20210702/1625209910849762.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) 2. 索引顺序为create_time,id ``` --创建索引 create index idx_abc_time_id on test_abc (create_time,id); --收集统计信息 execute dbms_stats.gather_table_stats(ownname => 'VIEWDB',tabname => 'TEST_ABC' ,estimate_percent => 10 ,degree=>4,method_opt => 'for all indexed columns' ,cascade => true); set autotrace traceonly SELECT count(*) FROM TEST_ABC WHERE id=80 and create_time = to_date('20210708 03:29:20','yyyymmdd hh24:mi:ss'); ``` ![图片 4.png](http://www.icode9.com/i/li/?n=2&i=images/20210702/1625209920874557.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) **结论:通过测试截图,可以看出,索引列顺序不同,对应的执行计划的cost和consistant gets值是相同。说明使用两个索引的效率和消耗相同。** ### 验证2:一个等值查询,一个不等值查询 1. 索引顺序为id,create_time ``` --创建索引 create index idx_abc_id_time on test_abc (id,create_time); --收集统计信息 execute dbms_stats.gather_table_stats(ownname => 'VIEWDB',tabname => 'TEST_ABC' ,estimate_percent => 10 ,degree=>4,method_opt => 'for all indexed columns' ,cascade => true); set autotrace traceonly SELECT count(*) FROM TEST_ABC WHERE id=50 and create_time > sysdate+80; ``` ![图片 1.png](http://www.icode9.com/i/li/?n=2&i=images/20210702/1625210361541212.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) 2. 索引顺序为create_time,id ``` --创建索引 create index idx_abc_time_id on test_abc (create_time,id); --收集统计信息 execute dbms_stats.gather_table_stats(ownname => 'VIEWDB',tabname => 'TEST_ABC' ,estimate_percent => 10 ,degree=>4,method_opt => 'for all indexed columns' ,cascade => true); set autotrace traceonly SELECT count(*) FROM TEST_ABC WHERE id=50 and create_time > sysdate+80; ``` ![图片 2.png](http://www.icode9.com/i/li/?n=2&i=images/20210702/1625210378780839.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) **结论:从实验截图看,索引顺序为id,create_time,执行计划cost为2,constraint gets为2,索引顺序为create_time,id,执行计划cost为9,constraint gets为10。说明不等值列在索引前的效率更低,消耗更高** ## 原理说明 要解释为什么顺序不同,消耗也不同直接画出索引的示意图就很好理解了。 模拟场景:where id=80 and create_time >= to_date('2021-01-02','yyyy-mm-dd) and create_time < to_date('2021-01-04','yyyy-mm-dd) 1. 索引顺序为id,create_time的示意图 ![图片 5.png](http://www.icode9.com/i/li/?n=2&i=images/20210702/1625211006461578.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) 从上面的示意图可以看出只需要扫描3行数据,就可以定位到所有条件需要的数据。 2. 索引顺序为create_time,id的示意图 ![图片1.png](http://www.icode9.com/i/li/?n=2&i=images/20210702/1625211516844241.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) 从上面的示意图可以看出,需要从(2021/1/2,79)行开始扫描,一直扫描到第(2021/1/4,79)行。扫描行数明显比索引顺序为id,create_time的索引扫描的行数多,所有消耗的资源也会相应的增加。 等值查询的示意图就不再画了,感兴趣的同学可以自己画一下,感觉一下索引的逻辑结构。 ## 结论 where条件都是等值查询的情况,列顺序对性能无影响;where条件存在不等值查询情况,等值查询的列在前。 > 参考链接:https://www.cnblogs.com/hmwh/p/9916830.html

标签:10,create,查询,索引,中列,time,Oracle,id
来源: https://blog.51cto.com/hbxztc/2970861