我正在玩Oracle 12和索引...
在这样的查询中:
SELECT a, b, c FROM table WHERE col1 = val1 AND col2 = val2 ORDER BY id DESC
(其中id是表的主键),Oracle总是使用主键上的索引。
因此,即使我在列col1和col2上创建索引,因为有ORDER BY语句,它也不会使用索引。
我可以推断这是一般规则吗?如果我的所有查询都包含" ORDER BY ID"我是否应该永远不会添加额外的索引? ?
这是我的表结构:
ID NUMBER GENERATED ALWAYS AS IDENTITY NOCACHE ORDER,
USERNAME VARCHAR2(30 CHAR)
TYPE_A CHAR(1 BYTE)
TYPE_B CHAR(1 BYTE)
CREATED DATE
UPDATED DATE
ALTER TABLE my_table
ADD CONSTRAINT my_table_pk
PRIMARY KEY (ID)
USING INDEX TABLESPACE XXX;
在表格中,我只执行此查询:
SELECT id, USERNAME, TYPE_A, TYPE_B, CREATED FROM table
where username = 'MYUSER'
AND created >= TO_DATE('2016-01-01','YYYY-MM-DD')
AND created <= TO_DATE('2016-06-30','YYYY-MM-DD')
AND TYPE_A = 1
order by ID desc;
一个索引:在pk(ID)上(由oracle自动创建)
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 384 | 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| table | 2 | 384 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN DESCENDING| INDEX_PK | 10 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
两个索引:首先是pk,第二个是(USERNAME,CREATED,TYPE_A)
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 384 | 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| table | 2 | 384 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN DESCENDING| INDEX_PK | 10 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
所以第二个指数似乎毫无用处。
顺便说一句如果我删除ORDER BY语句,Oracle会使用USERNAME,CREATED,TYPE_A上的第二个索引。
全部谢谢!
答案 0 :(得分:3)
只要首先指定ID
列,Oracle就会知道使用此索引。
您不应该为选项添加不必要的索引,这些选择只会在很多时间内发生一次,或者那些缓慢但不会太慢的选择。您应该只添加与此表中最常见的选择/更新相关的索引。
如果col1
和col2
上的过滤器选择重复,那么很可能(再次,我不知道您在此表上正在执行的其他进程)所有3列上的索引会更好:
(ID,Col1,Col2)
答案 1 :(得分:3)
让我给你一个反例,表明有些情况下Oracle会使用第二个索引。
SQL> create table tab (
2 ID NUMBER GENERATED ALWAYS AS IDENTITY NOCACHE ORDER,
3 USERNAME VARCHAR2(30 CHAR),
4 TYPE_A CHAR(1 BYTE),
5 TYPE_B CHAR(1 BYTE),
6 CREATED DATE,
7 UPDATED DATE
8 )
9 /
Table created.
SQL> alter table tab add constraint tab_pk primary key (id) using index
2 /
Table altered.
SQL> create index SECOND_IDX on tab(username, created, type_a)
2 /
Index created.
SQL> insert into tab(username, type_a, type_b, created)
2 select 'OTHER_USER', '2', '2', date '2015-06-01'
3 from all_objects, all_objects where rownum <= 1e5;
100000 rows created.
SQL>
SQL> update tab
2 set username = 'MYUSER',
3 created = DATE '2016-06-01',
4 type_a = '1'
5 where id = 50000;
1 row updated.
SQL> commit;
Commit complete.
SQL> begin
2 dbms_stats.gather_table_stats(ownname => USER,
3 tabname => 'TAB',
4 estimate_percent => 100,
5 method_opt => 'FOR ALL INDEXED COLUMNS'
6 );
7 end;
8 /
PL/SQL procedure successfully completed.
SQL>
SQL> set autotrace traceonly exp
SQL>
SQL> SELECT id, USERNAME, TYPE_A, TYPE_B, CREATED FROM tab
2 where username = 'MYUSER'
3 AND created >= TO_DATE('2016-01-01','YYYY-MM-DD')
4 AND created <= TO_DATE('2016-06-30','YYYY-MM-DD')
5 AND TYPE_A = '1'
6 order by ID desc;
Execution Plan
----------------------------------------------------------
Plan hash value: 3658386757
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 29 | 5 (20)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 29 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| TAB | 1 | 29 | 4 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | SECOND_IDX | 1 | | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
在这种情况下,使用第二个索引的原因是极高的选择性(100000中的一行)。