暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle索引的基本原理(三)相同列上的多个索引

原创 大柏树 2023-01-04
746

1.12c新特性-相同列创建多个索引

在12c中,在一个表的相同列上可以有多个索引(同类型或不同类型),但是某一时刻只能有一个设置为可见,除非其他索引是基于函数的索引(其实基于函数的索引并不基于相同的列,而是基于列上的函数)。 而在12c之前,相同的列(单个列或者顺序相同的多个列)只能有一个索引,即使是不同类型的索引(比如B树索引和位图索引)也不行。

2.用途

这个特性对于基于一个表的不同类型的负载很有用。一个系统在白天或者晚上的不同时间段,负载类型也会不一样,比如批处理、查询或数据仓库等,通过这个特性可以创建不同类型的索引来满足不同负载的需求。

3.限制

在相同的列上创建多个索引有这样的限制:

  • 不能在相同的列上同时创建B树索引和B树聚簇索引;
  • 不能在相同的列上创建B树索引和索引组织表(IOT);
  • 在做DML操作时,所有的索引都要维护(即便设置为不可见)。

记住,创建太多的索引会拖慢DML操作。

4.示例

4.1.在表dept_test列deptno创建第一个索引

--首先创建测试表dept1 SQL> create table dept_test as select * from dept; 表已创建。 --查看现在表上存在的索引 SQL> select * from dept_test; DEPTNO DNAME LOC ---------- -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON SQL> select index_name,table_name,column_name from user_ind_columns where table_name='DEPT_TEST'; 未选定行 SQL> --在deptno列上创建第一个索引 SQL> create unique index dept_test_unique1 on dept_test(deptno); 索引已创建。 SQL> select index_name,table_name,column_name from user_ind_columns where table_name='DEPT_TEST'; INDEX_NAME TABLE_NAME COLUMN_NAME ------------------------------ ------------------------------ ---------------------------------------- DEPT_TEST_UNIQUE1 DEPT_TEST DEPTNO SQL> insert into dept_test values(10,'oracle1','oracle2'); insert into dept_test values(10,'oracle1','oracle2') * 第 1 行出现错误: ORA-00001: 违反唯一约束条件 (SCOTT.DEPT_TEST_UNIQUE1) SQL> --可以看到,创建的唯一索引已经生效 --测试当设置索引为不可见的时候,是否生效 SQL> set line 200 SQL> col TABLE_NAME for a20 SQL> col index_name for a20 SQL> col column_name for a40 SQL> select a.table_name,a.index_name,b.column_name,a.visibility from user_indexes a,user_ind_columns b where a.index_name = b.index_name and a.table_name = 'DEPT_TEST'; TABLE_NAME INDEX_NAME COLUMN_NAME VISIBILIT -------------------- -------------------- ---------------------------------------- --------- DEPT_TEST DEPT_TEST_UNIQUE1 DEPTNO VISIBLE SQL> SQL> alter index dept_test_unique1 invisible; Index altered. SQL> select a.table_name,a.index_name,b.column_name,a.visibility from user_indexes a,user_ind_columns b where a.index_name = b.index_name and a.table_name = 'DEPT_TEST'; 2 3 4 TABLE_NAME INDEX_NAME COLUMN_NAME VISIBILIT -------------------- -------------------- ---------------------------------------- --------- DEPT_TEST DEPT_TEST_UNIQUE1 DEPTNO INVISIBLE SQL> --可以看到,就算索引设置为不可见,依旧在生效 SQL> insert into dept_test values(10,'oracle1','oracle2'); insert into dept_test values(10,'oracle1','oracle2') * ERROR at line 1: ORA-00001: unique constraint (SCOTT.DEPT_TEST_UNIQUE1) violated SQL>
复制

4.2.在表dept_test列deptno创建第二个索引

SQL> alter index dept_test_unique1 visible; Index altered. SQL> select a.table_name,a.index_name,b.column_name,a.visibility from user_indexes a,user_ind_columns b where a.index_name = b.index_name and a.table_name = 'DEPT_TEST'; 2 3 4 TABLE_NAME INDEX_NAME COLUMN_NAME VISIBILIT -------------------- -------------------- ---------------------------------------- --------- DEPT_TEST DEPT_TEST_UNIQUE1 DEPTNO VISIBLE SQL> --当列上已经有索引,并且为可见的时候,相同列创建索引会报错 SQL> create index dept_test_normal1 on dept_test(deptno); create index dept_test_normal1 on dept_test(deptno) * ERROR at line 1: ORA-01408: such column list already indexed SQL> --我们把第一个索引设置为不可见之后创建第二个索引 SQL> alter index dept_test_unique1 invisible; Index altered. SQL> select a.table_name,a.index_name,b.column_name,a.visibility from user_indexes a,user_ind_columns b where a.index_name = b.index_name and a.table_name = 'DEPT_TEST'; TABLE_NAME INDEX_NAME COLUMN_NAME VISIBILIT -------------------- -------------------- ---------------------------------------- --------- DEPT_TEST DEPT_TEST_UNIQUE1 DEPTNO INVISIBLE SQL> create index dept_test_normal1 on dept_test(deptno); Index created. SQL> select a.table_name,a.index_name,b.column_name,a.visibility from user_indexes a,user_ind_columns b where a.index_name = b.index_name and a.table_name = 'DEPT_TEST'; SQL> TABLE_NAME INDEX_NAME COLUMN_NAME VISIBILIT -------------------- -------------------- ---------------------------------------- --------- DEPT_TEST DEPT_TEST_UNIQUE1 DEPTNO INVISIBLE DEPT_TEST DEPT_TEST_NORMAL1 DEPTNO VISIBLE SQL> --可以看到在同一列上创建了两个索引,其中一个为可见,一个为不可见。我们尝试把不可见的索引设置为可见。 SQL> alter index DEPT_TEST_UNIQUE1 visible; alter index DEPT_TEST_UNIQUE1 visible * ERROR at line 1: ORA-14147: There is an existing VISIBLE index defined on the same set of columns. SQL>
复制

值得注意的是尽管有唯一索引,但是只有可见的索引才能被用到。

SQL> select deptno from dept_test where deptno=10; Execution Plan ---------------------------------------------------------- Plan hash value: 4002397063 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 3 | 1 (0)| 00:00:01 | |* 1 | INDEX RANGE SCAN| DEPT_TEST_NORMAL1 | 1 | 3 | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------
复制

4.3.在表dept_test列deptno创建函数索引

如果创建普通索引,那必须把其他索引,也就是前两个索引都设置为不可见才能继续创建。
但如果创建基于函数的索引,则列上可以有两个可见的索引。

SQL> create index dept_test_fb on dept_test(substr(deptno,1,1)); Index created. SQL> select a.table_name,a.index_name,b.column_name,a.visibility from user_indexes a,user_ind_columns b where a.index_name = b.index_name and a.table_name = 'DEPT_TEST'; TABLE_NAME INDEX_NAME COLUMN_NAME VISIBILIT -------------------- -------------------- ---------------------------------------- --------- DEPT_TEST DEPT_TEST_UNIQUE1 DEPTNO INVISIBLE DEPT_TEST DEPT_TEST_NORMAL1 DEPTNO VISIBLE DEPT_TEST DEPT_TEST_FB SYS_NC00004$ VISIBLE SQL>
复制

可以看到,有两个索引是可见的。

5.总结

在oracle 12c以上,通过使用不可见索引,可以在同一列或相同的多个列上创建多个索引。这对于不同负载会很有用。比如白天的负载中国使用B树索引,而在晚上的负载中使用反向键索引。但是需要注意的是,在做DML操作的时候,这些索引需要额外的开销进行维护。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论

目录
  • 1.12c新特性-相同列创建多个索引
  • 2.用途
  • 3.限制
  • 4.示例
    • 4.1.在表dept_test列deptno创建第一个索引
    • 4.2.在表dept_test列deptno创建第二个索引
    • 4.3.在表dept_test列deptno创建函数索引
  • 5.总结