У меня проблемы с производительностью при запросе таблицы в производственной базе данных.В то время как запрос выполняется в тестовой базе данных за 2,1 секунды (возвращая 8640 из 28 миллионов записей), при производстве он занимает 2,05 минуты (возвращая 8640 из 31 миллиона записей).Мне трудно найти проблему, потому что я не эксперт по оракулам.Поскольку план объяснения в обеих базах данных показывает правильное использование индексов, я склонен думать, что проблема заключается в создании таблицы / индексов.Я заметил некоторые небольшие различия между сценариями SQL, используемыми для создания таблицы:
Тестовая база данных:
create table TB_PONTO_ENE
(
cd_ponto NUMBER(10) not null,
cd_fonte NUMBER(10),
cd_medidor NUMBER(10),
cd_usuario NUMBER(10),
dt_hr_insercao DATE,
dt_hr_instante DATE not null,
dt_hr_hora DATE,
dt_hr_dia DATE,
dt_hr_mes DATE,
dt_hr_instante_hv DATE,
dt_hr_hora_hv DATE,
dt_hr_dia_hv DATE,
dt_hr_mes_hv DATE,
vl_eneat_del FLOAT,
vl_eneat_rec FLOAT,
vl_enere_del FLOAT,
vl_enere_rec FLOAT,
vl_eneat_del_cp FLOAT,
vl_eneat_rec_cp FLOAT,
vl_enere_del_cp FLOAT,
vl_enere_rec_cp FLOAT
)
tablespace TELEMEDICAO
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table TB_PONTO_ENE
add constraint CP_TB_PONTO_ENE primary key (CD_PONTO, DT_HR_INSTANTE)
using index
tablespace TELEMEDICAO
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_FONTE foreign key (CD_FONTE)
references TB_FONTE (CD_FONTE) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_MEDIDOR foreign key (CD_MEDIDOR)
references TB_MEDIDOR (CD_MEDIDOR) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_PONTO foreign key (CD_PONTO)
references TB_PONTO (CD_PONTO) on delete cascade;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_USUARIO foreign key (CD_USUARIO)
references TB_USUARIO (CD_USUARIO) on delete set null
disable;
Производственная база данных:
create table TB_PONTO_ENE
(
cd_ponto NUMBER(10) not null,
cd_fonte NUMBER(10),
cd_medidor NUMBER(10),
cd_usuario NUMBER(10),
dt_hr_insercao DATE,
dt_hr_instante DATE not null,
dt_hr_hora DATE,
dt_hr_dia DATE,
dt_hr_mes DATE,
dt_hr_instante_hv DATE,
dt_hr_hora_hv DATE,
dt_hr_dia_hv DATE,
dt_hr_mes_hv DATE,
vl_eneat_del FLOAT,
vl_eneat_rec FLOAT,
vl_enere_del FLOAT,
vl_enere_rec FLOAT,
vl_eneat_del_cp FLOAT,
vl_eneat_rec_cp FLOAT,
vl_enere_del_cp FLOAT,
vl_enere_rec_cp FLOAT
)
tablespace TELEMEDICAO
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 5M
minextents 1
maxextents unlimited
pctincrease 0
);
alter table TB_PONTO_ENE
add constraint CP_TB_PONTO_ENE primary key (CD_PONTO, DT_HR_INSTANTE)
using index
tablespace MEDICAO_NDX
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
pctincrease 0
);
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_FONTE foreign key (CD_FONTE)
references TB_FONTE (CD_FONTE) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_MEDIDOR foreign key (CD_MEDIDOR)
references TB_MEDIDOR (CD_MEDIDOR) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_PONTO foreign key (CD_PONTO)
references TB_PONTO (CD_PONTO) on delete cascade;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_USUARIO foreign key (CD_USUARIO)
references TB_USUARIO (CD_USUARIO) on delete set null;
Производственная база данныхпомещает индексы в другое табличное пространство.Другим отличием является next 5M
в объявлении табличного пространства (значение не определено в тестовой базе данных).
При просмотре свойств индекса я также вижу некоторые различия:
Тестовая база данных:
- AVG_DATA_BLOCKS_PER_KEY 1
- AVG_LEAF_BLOCKS_PER_KEY 1
- BLEVEL 2
- BUFFER_POOL ПО УМОЛЧАНИЮ
- CLUSTERING_FACTOR 611494
- СЖАТИЕ ОТКЛЮЧЕНО
- Градус 1
- DISTINCT_KEYS 28568389
- УДАЛЕН NO
- GENERATED N
- GLOBAL_STATS YES
- INDEX_NAME CP_TB_PONTO_ENE
- INDEX_TYPE NORMAL
- INITIAL_EXTENT 65536
- INI_TRANS 2
- INSTANCES 1
- IOT_REDUNDANT_PKEY_ELIM NO
- JOIN_INDEX NO
- LAST_ANALYZED 21/07/2010 22:08:34
- LEAF_BLOCKS 85809
- LOGGING YES
- MAX_EXTENTS 2147483645
- MAX_TRANS 255
- MIN_EXTENTS 1
- NUM_ROWS 28568389
- PARTITIONED NO
- PCT_FREE 10
- SAMPLE_SIZE 377209
- SECONDARY N
- STATUS VALID
- TABLESPACE_NAME TELEMEDICAO
- TABLE_NAME TB_PONTO_ENE
- TABLE_TYPE TABLE
- TEMPORARY N
- UNIQUENESS UNIQUE
- USER_STATS NO
Производственная база данных:
- AVG_DATA_BLOCKS_PER_KEY 1
- AVG_LEAF_BLOCKS_PER_KEY 1
- BLEVEL 2
- BUFFER_POOL DEFAULT
- CLUSTERING_FACTOR 10154395
- СЖАТИЕ ОТКЛЮЧЕНО
- СТЕПЕНЬ 1
- DISTINCT_KEYS 14004395
- СОЗДАН N
- GLOBAL_STATS ДА
- INDEX_NAME CP_TB_PONTO_ENE
- INDEX_TYPE НОРМАЛЬНЫЙ
- INITIAL_EXTENT 65536
- INI_TRANS 2
- INSTANCEES 1
- JOIN_INDEX NO
- LAST_ANALYZED 05/03/2010 08:45:19
- LEAF_BLOCKS 42865
- Регистрация ДА
- MAX_EXTENTS 2147483645
- MAX_TRANS 255
- MIN_EXTENTS 1
- NEXT_EXTENT 1048576
- NUM_ROWS 14004395
- PARTITIONED NO
- PCT_FREE 10
- PCT_INCREASE 0
- SAMPLE_РАЗМЕР 2800879
- ВТОРИЧНЫЙ N
- STATUS VALID
- TABLESPACE_NAME MEDICAO_NDX
- TABLE_NAME TB_PONTO_ENE
- TABLE_TYPE TABLE
- ВРЕМЕННЫЙ N
- УНИКАЛЬНОСТЬ УНИКАЛЬНО
- USER_STATS NO
Два других момента привлекли мое внимание: план объяснения для select count(*) from thetable
показывает, что индекс используется в тестовой базе данных, но показывает полное сканирование таблицы в рабочей базе данных. Это привело меня к другому наблюдению: индекс тестовой базы данных имеет 160 МБ, а производственная база данных имеет более 1 ГБ (и мы не удаляем эту таблицу).
Кто-нибудь может указать мне на решение?
UPDATE
Вот планы выполнения:
Тестовая база данных:
Execution Plan
----------------------------------------------------------
Plan hash value: 1441290166
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18767 (4)| 00:03:46 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_HV_TB_PONTO_ENE | 28M| 18767 (4)| 00:03:46 |
-------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
111 recursive calls
0 db block gets
83586 consistent gets
83533 physical reads
0 redo size
422 bytes sent via SQL*Net to client
399 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed
Производственная база данных
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=RULE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TB_PONTO_ENE'
Statistics
----------------------------------------------------------
1 recursive calls
3 db block gets
605327 consistent gets
603698 physical reads
180 redo size
201 bytes sent via SQL*Net to client
242 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
ОБНОВЛЕНИЕ 2
Рабочий сервер работает под управлением Oracle 9.2.0.
ОБНОВЛЕНИЕ 3
Вот статистика для выполнения с режимом оптимизатора, установленным на CHOOSE
:
SQL> SELECT dt_hr_instante, vl_eneat_del,vl_eneat_rec,vl_enere_del, vl_enere_rec FROM tb_ponto_ene WHERE cd_ponto = 31 AND dt_hr_instante BETWEEN to_date('01/06/2010 00:05:00','dd/mm/yyyy hh24:mi:ss') AND to_date('01/07/2010 00:00:00', 'dd/mm/yyyy hh24:mi:ss');
8640 rows selected.
Elapsed: 00:01:49.51
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=36)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TB_PONTO_ENE' (Cost=4 Card=1 Bytes=36)
2 1 INDEX (RANGE SCAN) OF 'CP_TB_PONTO_ENE' (UNIQUE) (Cost=3 Card=1)
Statistics
----------------------------------------------------------
119 recursive calls
0 db block gets
9169 consistent gets
7438 physical reads
0 redo size
308524 bytes sent via SQL*Net to client
4267 bytes received via SQL*Net from client
577 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
8640 rows processed