Потомух |
2) Секционирование разве для этого придумали? |
Как я понимаю, и для этого тоже.
Partitioned Tables and Indexes Oracle9i Database Concepts |
Partitioning improves query performance. In many cases, the results of a query can be achieved by accessing a subset of partitions, rather than the entire table. For some queries, this technique (called partition pruning) can provide order-of-magnitude gains in performance.
|
Потомух |
3) Приводите здесь запросы, которые тормозят, их планы, инфу о таблицах/индексах, тогда и будет надежда, что вам здесь помогут, а так - гадание на кофейной гуще |
таблица:
CREATE TABLE act_oper_activ_log
(id NUMBER(*,0) NOT NULL,
oper_id NUMBER(*,0),
oper_login VARCHAR2(50),
event_date DATE,
event_categ VARCHAR2(50),
event_message VARCHAR2(600),
old_state_org_id NUMBER(*,0),
new_state_org_id NUMBER(*,0),
org_id NUMBER(*,0),
interval NUMBER,
machine VARCHAR2(500))
/
-- Indexes for ACT_OPER_ACTIV_LOG
CREATE INDEX idx_act_oper_log_event_date ON act_oper_activ_log
( event_date ASC )
/
CREATE INDEX idx_act_oper_act_log_org_id ON act_oper_activ_log
( org_id ASC )
/
CREATE INDEX idx_act_oper_act_log_new_st_id ON act_oper_activ_log
( new_state_org_id ASC )
/
CREATE INDEX idx_act_oper_activ_log_evntcat ON act_oper_activ_log
( event_categ ASC )
/
-- Constraints for ACT_OPER_ACTIV_LOG
ALTER TABLE act_oper_activ_log
ADD CONSTRAINT pk_act_oper_activ_log_id PRIMARY KEY (id)
USING INDEX
/
-- Foreign Key
ALTER TABLE act_oper_activ_log
ADD CONSTRAINT fk_act_activ_oper_list_oper_id FOREIGN KEY (oper_id)
REFERENCES oper_list (id)
/
Запрос: план выполнения для 28.11.2007
SQL> SELECT ol.oper_display_name
2 , st.wrk_mode
3 , so.status
4 , st.categ_name
5 , count(distinct org.id) AS org_cnt
6 , count(distinct per.id) AS pers_cnt
7 FROM act_oper_wrk_stat st
8 , oper_list ol
9 , act_oper_activ_log lg
10 , act_stat_org so
11 , act_orgnztion org
12 , act_persons per
13 WHERE st.oper_id = ol.id
14 AND st.date_beg >= To_Date('28.11.2007', 'DD.MM.YYYY')
15 AND nvl(st.date_end, sysdate) < To_Date('28.11.2007', 'DD.MM.YYYY') + 1
16 AND lg.event_date >= st.date_beg
17 AND lg.event_date <= nvl(st.date_end, sysdate)
18 AND lg.oper_id = st.oper_id
19 AND lg.event_categ = 'ChangeStatusOrgAMR'
20 AND lg.new_state_org_id = so.id
21 AND lg.org_id = org.id
22 AND org.id = per.id_org(+)
23 GROUP BY ol.oper_display_name, so.status, st.wrk_mode, st.categ_name
24 ORDER BY 1, 4, 2, 3;
160 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=183 Card=1 Bytes=196)
1 0 SORT (GROUP BY) (Cost=183 Card=1 Bytes=196)
2 1 NESTED LOOPS (OUTER) (Cost=182 Card=1 Bytes=196)
3 2 NESTED LOOPS (Cost=179 Card=1 Bytes=184)
4 3 NESTED LOOPS (Cost=178 Card=1 Bytes=178)
5 4 NESTED LOOPS (Cost=177 Card=1 Bytes=141)
6 5 NESTED LOOPS (Cost=12 Card=1 Bytes=104)
7 6 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_OPER_WRK_STAT' (Cost=11 Card=1 Bytes=69)
8 7 INDEX (RANGE SCAN) OF 'IDX_ACT_OPER_WRK_STAT_DATE_BEG' (NON-UNIQUE) (Cost=3 Card=115)
9 6 TABLE ACCESS (BY INDEX ROWID) OF 'OPER_LIST' (Cost=2 Card=1 Bytes=35)
10 9 INDEX (UNIQUE SCAN) OF 'PK_OPER_LIST' (UNIQUE) (Cost=1 Card=1)
11 5 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_OPER_ACTIV_LOG' (Cost=166 Card=1 Bytes=37)
12 11 INDEX (RANGE SCAN) OF 'IDX_ACT_OPER_LOG_EVENT_DATE' (NON-UNIQUE) (Cost=162 Card=73)
13 4 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_STAT_ORG' (Cost=2 Card=1 Bytes=37)
14 13 INDEX (UNIQUE SCAN) OF 'PK_ACT_STAT_ORG_ID' (UNIQUE) (Cost=1 Card=1)
15 3 INDEX (UNIQUE SCAN) OF 'PK_ACT_ORGNZTION_ID' (UNIQUE) (Cost=2 Card=1 Bytes=6)
16 2 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_PERSONS' (Cost=4 Card=1 Bytes=12)
17 16 INDEX (RANGE SCAN) OF 'IDX_ACT_PERSONS_ID_ORG' (NON-UNIQUE) (Cost=3 Card=1)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
40963 consistent gets
8787 physical reads
0 redo size
10657 bytes sent via SQL*Net to client
605 bytes received via SQL*Net from client
24 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
160 rows processed
SQL>
с датой 29.11.2007
SQL> SELECT ol.oper_display_name
2 , st.wrk_mode
3 , so.status
4 , st.categ_name
5 , count(distinct org.id) AS org_cnt
6 , count(distinct per.id) AS pers_cnt
7 FROM act_oper_wrk_stat st
8 , oper_list ol
9 , act_oper_activ_log lg
10 , act_stat_org so
11 , act_orgnztion org
12 , act_persons per
13 WHERE st.oper_id = ol.id
14 AND st.date_beg >= To_Date('29.11.2007', 'DD.MM.YYYY')
15 AND nvl(st.date_end, sysdate) < To_Date('29.11.2007', 'DD.MM.YYYY') + 1
16 AND lg.event_date >= st.date_beg
17 AND lg.event_date <= nvl(st.date_end, sysdate)
18 AND lg.oper_id = st.oper_id
19 AND lg.event_categ = 'ChangeStatusOrgAMR'
20 AND lg.new_state_org_id = so.id
21 AND lg.org_id = org.id
22 AND org.id = per.id_org(+)
23 GROUP BY ol.oper_display_name, so.status, st.wrk_mode, st.categ_name
24 ORDER BY 1, 4, 2, 3;
240 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=183 Card=1 Bytes=196)
1 0 SORT (GROUP BY) (Cost=183 Card=1 Bytes=196)
2 1 NESTED LOOPS (OUTER) (Cost=182 Card=1 Bytes=196)
3 2 NESTED LOOPS (Cost=179 Card=1 Bytes=184)
4 3 NESTED LOOPS (Cost=178 Card=1 Bytes=178)
5 4 NESTED LOOPS (Cost=177 Card=1 Bytes=141)
6 5 NESTED LOOPS (Cost=12 Card=1 Bytes=104)
7 6 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_OPER_WRK_STAT' (Cost=11 Card=1 Bytes=69)
8 7 INDEX (RANGE SCAN) OF 'IDX_ACT_OPER_WRK_STAT_DATE_BEG' (NON-UNIQUE) (Cost=3 Card=115)
9 6 TABLE ACCESS (BY INDEX ROWID) OF 'OPER_LIST' (Cost=2 Card=1 Bytes=35)
10 9 INDEX (UNIQUE SCAN) OF 'PK_OPER_LIST' (UNIQUE) (Cost=1 Card=1)
11 5 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_OPER_ACTIV_LOG' (Cost=166 Card=1 Bytes=37)
12 11 INDEX (RANGE SCAN) OF 'IDX_ACT_OPER_LOG_EVENT_DATE' (NON-UNIQUE) (Cost=162 Card=73)
13 4 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_STAT_ORG' (Cost=2 Card=1 Bytes=37)
14 13 INDEX (UNIQUE SCAN) OF 'PK_ACT_STAT_ORG_ID' (UNIQUE) (Cost=1 Card=1)
15 3 INDEX (UNIQUE SCAN) OF 'PK_ACT_ORGNZTION_ID' (UNIQUE) (Cost=2 Card=1 Bytes=6)
16 2 TABLE ACCESS (BY INDEX ROWID) OF 'ACT_PERSONS' (Cost=4 Card=1 Bytes=12)
17 16 INDEX (RANGE SCAN) OF 'IDX_ACT_PERSONS_ID_ORG' (NON-UNIQUE) (Cost=3 Card=1)
Statistics
----------------------------------------------------------
0 recursive calls
3 db block gets
641646 consistent gets
55835 physical reads
0 redo size
12862 bytes sent via SQL*Net to client
660 bytes received via SQL*Net from client
34 SQL*Net roundtrips to/from client
0 sorts (memory)
1 sorts (disk)
240 rows processed
SQL>
Планы одинаковые - ремя выполнения отличается примерно в 10 раз.
Это из-за того, что 29.11 паралельно с работой операторов производилось массовое обновление информации об организациях, что привело к появлению примерно 200 тыс. записей в истории.
Запрос - эти строки не обрабатывает, однака наполненность блоков данных будет какова, что в них будет много-много строк об изменении организации и одна строка - перевод на другой шаг.
Вобще для этой таблицы как правило используется 2 вида запросов:
1) По смене шагов для организаций
2) Вся история по одной организации (к этим запросам претензий по быстродействию нет)
Теперь к вопросу о секционировании.
Как я понимаю, если мы сделаем отдельную партицию для событий 'ChangeStatusOrgAMR', то кол-во блоков при выборке вышеприведенного запроса сократится, потому что в этой партиции других строк просто не будет.
Сам с партициями не работал, поэтому и спрашиваю - насколько реально это поможет и стоит ли овчинка выделки?
2 orawish : за совет с MATVIEW - спасибо, будем думать!