Ну, вам вообще не следовало создавать какие-либо из этих индексов, потому что ваше предложение where влияет на все столбцы. Индексы весьма эффективны, когда ваше предложение where ищет определенный c столбец или столбцы, но не тогда, когда все столбцы в вашей таблице являются частью предиката. В этом случае CBO (оптимизатор на основе затрат) всегда будет использовать полное сканирование таблицы.
Позвольте мне показать вам пример с вашей моделью данных
SQL> create table tab_example (
id_tab integer not null,
val1 integer,
val2 integer,
val3 integer,
val4 integer,
val5 integer,
val6 integer,
val7 integer,
val8 integer,
val9 integer,
CONSTRAINT tab_example_pk PRIMARY KEY (id_tab)
)
/
Table created.
SQL> create index val1_index on tab_example (val1);
create index val2_index on tab_example (val2);
create index val3_index on tab_example (val3);
create index val4_index on tab_example (val4);
create index val5_index on tab_example (val5);
create index val6_index on tab_example (val6);
create index val7_index on tab_example (val7);
create index val8_index on tab_example (val8);
create index val9_index on tab_example (val9);
Index created.
SQL>
Index created.
SQL>
Index created.
SQL>
Index created.
SQL>
Index created.
SQL>
Index created.
SQL>
Index created.
SQL>
Index created.
SQL>
Index created.
Я создаю потомок с одним миллионом строк в области видимости
SQL> create or replace procedure test1 as
begin
for x in 1..1000000
loop
insert into tab_example(id_tab, val1, val2, val3, val4, val5, val6, val7, val8, val9)
values ((select nvl(max(id_tab), 0) + 1 from tab_example),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)),
decode(round(dbms_random.value(0,2)), 1, null, dbms_random.value(1,9)));
end loop;
end;
/
Procedure created.
SQL> set timing on
SQL> begin
2 test1;
3 insert into tab_example (id_tab, val1, val2, val3, val4, val5, val6, val7, val8, val9)
4 values(-1, 3, 1, null, 5, 2, 1, 9, null, 1);
5* end;
/
PL/SQL procedure successfully completed.
Elapsed: 00:08:09.34
Как видите, выполнение процедуры занимает много времени, в основном потому, что в операции задействовано 9 индексов. Помните, что любая операция DML с таблицей должна делать то же самое для индексов. В вашем случае эти индексы не предлагают никакой помощи в отношении вашего запроса, потому что, как я уже сказал, ваш предикат просматривает каждый столбец в вашей таблице.
Давайте вычислим статистику и посмотрим план объяснения вашего query
SQL> exec dbms_stats.gather_table_stats( 'MYUSER' , 'TAB_EXAMPLE' );
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.19
SQL> set autotrace traceonly explain
SQL> SELECT * FROM tab_example
where
2 3 (decode(val1, 3, 1) = 1) and -- it's like: (val1 = 3 or (val1 is null and 3 is null)
4 (decode(val2, 1, 1) = 1) and
(decode(val3, null, 1) = 1) and -- it's like: (val1 = null or (val1 is null and null is null)
5 6 (decode(val4, 5, 1) = 1) and
(decode(val5, 2, 1) = 1) and
(decode(val6, 1, 1) = 1) and
(decode(val7, 9, 1) = 1) and
7 8 9 10 (decode(val8, null, 1) = 1) and
11 (decode(val9, 1, 1) = 1);
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 2592949226
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 23 | 709 (3)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TAB_EXAMPLE | 1 | 23 | 709 (3)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(DECODE("VAL1",3,1)=1 AND DECODE("VAL2",1,1)=1 AND
DECODE("VAL4",5,1)=1 AND DECODE("VAL5",2,1)=1 AND DECODE("VAL6",1,1)=1
AND DECODE("VAL7",9,1)=1 AND DECODE("VAL9",1,1)=1 AND
DECODE(TO_CHAR("VAL3"),NULL,1)=1 AND DECODE(TO_CHAR("VAL8"),NULL,1)=1)
В моем случае запрос почти ничего не берет, и план выполнения является правильным с учетом информации о предикате. Я проверяю каждый столбец, поэтому ПОЛНЫЙ ДОСТУП к таблице в этом случае лучше.
SQL> SELECT * FROM tab_example
where
2 3 (decode(val1, 3, 1) = 1) and -- it's like: (val1 = 3 or (val1 is null and 3 is null)
(decode(val2, 1, 1) = 1) and
(decode(val3, null, 1) = 1) and -- it's like: (val1 = null or (val1 is null and null is null)
(decode(val4, 5, 1) = 1) and
4 5 6 7 (decode(val5, 2, 1) = 1) and
(decode(val6, 1, 1) = 1) and
(decode(val7, 9, 1) = 1) and
8 9 10 (decode(val8, null, 1) = 1) and
(decode(val9, 1, 1) = 1) 11 ;
ID_TAB VAL1 VAL2 VAL3 VAL4 VAL5 VAL6 VAL7 VAL8 VAL9
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
-1 3 1 5 2 1 9 1
Elapsed: 00:00:00.21
Если я удалю индексы (кроме принудительного индекса, используемого первичным ключом), посмотрим, сколько времени Мне нужно сделать вставку
SQL> declare
begin
for i in ( select index_name from dba_indexes where table_name = 'TAB_EXAMPLE' and index_name like 'VAL%' )
loop
execute immediate ' drop index '||i.index_name||' ' ;
end loop;
end;
/
2 3 4 5 6 7 8
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.32
SQL> truncate table TAB_EXAMPLE ;
Table truncated.
Elapsed: 00:00:00.17
SQL> begin
test1;
insert into tab_example (id_tab, val1, val2, val3, val4, val5, val6, val7, val8, val9)
values(-1, 3, 1, null, 5, 2, 1, 9, null, 1);
end;
/ 2 3 4 5 6
PL/SQL procedure successfully completed.
Elapsed: 00:02:41.01
Резюме: Правильная индексация - хорошее упражнение при построении физической модели данных. Индексирование всех столбцов - не лучший вариант и плохое решение. Бывают ситуации, например, возможно, вам понадобится IOT (Index Organized Table), но я не вижу здесь случая и не использовать столько бесполезных индексов.
Надеюсь, это немного поможет!