Я планирую использовать схему базы данных с зависимыми таблицами. Нетривиальным является то, что каждая таблица также содержит историю записей. И запрос по дате должен искать значения для идентификатора для данной даты, так что это запрос для поиска и объединения записей разных таблиц.
select * from test1 t1
join test2 t2 on t2.t1_id = t1.base_id
join test3 t3 on t3.t2_id = t2.base_id
where t1.ver = (select max(ver) from test1 t where t1.base_id = t.base_id and t.ver <= '01.Jan.2025')
and t2.ver = (select max(ver) from test2 t where t2.base_id = t.base_id and t.ver <= '01.Jan.2025')
and t3.ver = (select max(ver) from test3 t where t2.base_id = t.base_id and t.ver <= '01.Jan.2025')
order by t1.id, t2.id, t3.id;
Я пробовал разные индексы - поэтому я предоставляюздесь только стандартные индексы. Это план атм:
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 840 | | 1149K (1)| 00:00:45 |
| 1 | SORT ORDER BY | | 2 | 840 | 32M| 1149K (1)| 00:00:45 |
|* 2 | FILTER | | | | | | |
|* 3 | HASH JOIN | | 75256 | 30M| 22M| 793K (1)| 00:00:31 |
| 4 | NESTED LOOPS | | 75256 | 21M| | 788K (1)| 00:00:31 |
|* 5 | HASH JOIN | | 156K| 40M| 6128K| 4471 (1)| 00:00:01 |
|* 6 | HASH JOIN | | 39199 | 5665K| | 489 (1)| 00:00:01 |
| 7 | VIEW | VW_SQ_1 | 39199 | 1033K| | 76 (4)| 00:00:01 |
| 8 | HASH GROUP BY | | 39199 | 459K| | 76 (4)| 00:00:01 |
|* 9 | INDEX FAST FULL SCAN | ID_T1_VERB | 66707 | 781K| | 74 (2)| 00:00:01 |
| 10 | TABLE ACCESS FULL | TEST1 | 80000 | 9453K| | 413 (1)| 00:00:01 |
| 11 | TABLE ACCESS FULL | TEST2 | 320K| 38M| | 1610 (1)| 00:00:01 |
|* 12 | VIEW PUSHED PREDICATE | VW_SQ_2 | 1 | 22 | | 5 (0)| 00:00:01 |
|* 13 | FILTER | | | | | | |
| 14 | SORT AGGREGATE | | 1 | 12 | | | |
|* 15 | TABLE ACCESS BY INDEX ROWID BATCHED| TEST2 | 2 | 24 | | 5 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | ID_T2_B | 2 | | | 3 (0)| 00:00:01 |
| 17 | TABLE ACCESS FULL | TEST3 | 320K| 38M| | 1610 (1)| 00:00:01 |
| 18 | SORT AGGREGATE | | 1 | 12 | | | |
|* 19 | TABLE ACCESS BY INDEX ROWID BATCHED | TEST3 | 2 | 24 | | 5 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | ID_T3_B | 2 | | | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------
Какие индексы будут работать? Или есть способ написать лучший запрос?
TABLE ACCESS FULL убивает его для больших наборов данных, более объединенных таблиц или добавления фильтров атрибутов ...
Для создания этих 3 таблиц вы можете использовать этот sql:
create table test1
segment creation immediate nologging as
with generator as (
select rownum id from dual
connect by level <= 10000
)
select
rownum id,
rownum base_id,
to_timestamp(to_date('01.Jan.2010') + rownum) ver,
mod(rownum-1,10) val,
lpad('x',100,'x') padding
from
generator v1
order by
dbms_random.value
;
insert into test1 (id, base_id, ver, val, padding)
(select id + 10000, id, to_timestamp(ver - id), val, padding from test1);
insert into test1 (id, base_id, ver, val, padding)
(select id + 20000, id, to_timestamp(ver - id), val, padding from test1);
insert into test1 (id, base_id, ver, val, padding)
(select id + 40000, id, to_timestamp(ver - id), val, padding from test1);
create table test2
segment creation immediate nologging as
with generator as (
select rownum id from dual
connect by level <= 10000
)
select
rownum id,
rownum base_id,
to_timestamp(to_date('01.Jan.2010') + rownum) ver,
floor(dbms_random.value(1, 10000)) t1_id,
mod(rownum-1,10) val,
lpad('x',100,'x') padding
from
generator v1
order by
dbms_random.value
;
insert into test2 (id, base_id, ver, t1_id, val, padding)
(select id + 10000, id, to_timestamp(ver - id), t1_id, val, padding from test2);
insert into test2 (id, base_id, ver, t1_id, val, padding)
(select id + 20000, id, to_timestamp(ver - id), t1_id, val, padding from test2);
insert into test2 (id, base_id, ver, t1_id, val, padding)
(select id + 40000, id, to_timestamp(ver - id), t1_id, val, padding from test2);
insert into test2 (id, base_id, ver, t1_id, val, padding)
(select id + 80000, id, to_timestamp(ver - id), t1_id, val, padding from test2);
insert into test2 (id, base_id, ver, t1_id, val, padding)
(select id + 160000, id, to_timestamp(ver - id), t1_id, val, padding from test2);
create table test3
segment creation immediate nologging as
with generator as (
select rownum id from dual
connect by level <= 10000
)
select
rownum id,
rownum base_id,
to_timestamp(to_date('01.Jan.3010') + rownum) ver,
floor(dbms_random.value(1, 10000)) t2_id,
mod(rownum-1,10) val,
lpad('x',100,'x') padding
from
generator v1
order by
dbms_random.value
;
insert into test3 (id, base_id, ver, t2_id, val, padding)
(select id + 10000, id, to_timestamp(ver - id), t2_id, val, padding from test3);
insert into test3 (id, base_id, ver, t2_id, val, padding)
(select id + 20000, id, to_timestamp(ver - id), t2_id, val, padding from test3);
insert into test3 (id, base_id, ver, t2_id, val, padding)
(select id + 40000, id, to_timestamp(ver - id), t2_id, val, padding from test3);
insert into test3 (id, base_id, ver, t2_id, val, padding)
(select id + 80000, id, to_timestamp(ver - id), t2_id, val, padding from test3);
insert into test3 (id, base_id, ver, t2_id, val, padding)
(select id + 160000, id, to_timestamp(ver - id), t2_id, val, padding from test3);
alter table test1 add constraint pk_t1 primary key (id);
alter table test2 add constraint pk_t2 primary key (id);
alter table test3 add constraint pk_t3 primary key (id);
alter table test1 add constraint fk_t1 foreign key (base_id) references test1(id);
alter table test2 add constraint fk_t2 foreign key (base_id) references test2(id);
alter table test3 add constraint fk_t3 foreign key (base_id) references test3(id);
alter table test2 add constraint fk_t2t1 foreign key (t1_id) references test1(id);
alter table test3 add constraint fk_t3t2 foreign key (t2_id) references test2(id);
create index id_t1_b on test1 (base_id);
create index id_t2_b on test2 (base_id);
create index id_t3_b on test3 (base_id);
create index id_t1_ver on test1 (ver);
create index id_t2_ver on test2 (ver);
create index id_t3_ver on test3 (ver);
create index id_t2_t1 on test2 (t1_id);
create index id_t2_t1v on test2 (t1_id, ver);
create index id_t3_t1 on test3 (t2_id);
create index id_t3_t1v on test3 (t2_id, ver);