Я часто сталкиваюсь со следующей ситуацией в моих планах выполнения Oracle:
Operation | Object | Order | Rows | Bytes | Projection
----------------------------+---------+-------+------+-------+-------------
TABLE ACCESS BY INDEX ROWID | PROD | 7 | 2M | 28M | PROD.VALUE
INDEX UNIQUE SCAN | PROD_PK | 6 | 1 | | PROD.ROWID
Это выдержка из более крупного плана выполнения.По сути, я получаю доступ (присоединяюсь) к таблице, используя ее первичный ключ.Обычно существует другая таблица ACCO
с ACCO.PROD_ID = PROD.ID
, где PROD_PK
- первичный ключ на PROD.ID
.Очевидно, что к таблице можно получить доступ, используя UNIQUE SCAN
, но как только у меня возникнет какая-то глупая проекция на эту таблицу, создается впечатление, что всю таблицу (около 2 миллионов строк) планируется прочитать в памяти.Я получаю много ввода-вывода и буфер получает.Когда я удаляю проекцию из большего запроса, проблема исчезает:
Operation | Object | Order | Rows | Bytes | Projection
----------------------------+---------+-------+------+-------+-------------
TABLE ACCESS BY INDEX ROWID | PROD | 7 | 1 | 8 | PROD.ID
INDEX UNIQUE SCAN | PROD_PK | 6 | 1 | | PROD.ROWID
Я не понимаю этого поведения.Какие могут быть причины для этого?Обратите внимание, я не могу опубликовать полный запрос.Это довольно сложно и требует много вычислений.Шаблон, однако, часто один и тот же.
ОБНОВЛЕНИЕ : я пометил, чтобы свести мою довольно сложную установку к простой симуляции, которая в обоих случаях выдает похожий план выполнения (при проецировании PROD.VALUE
или оставляя его вне):
Создайте следующую базу данных:
-- products have a value
create table prod as
select level as id, 10 as value from dual
connect by level < 100000;
alter table prod add constraint prod_pk primary key (id);
-- some products are accounts
create table acco as
select level as id, level as prod_id from dual
connect by level < 50000;
alter table acco
add constraint acco_pk primary key (id);
alter table acco
add constraint acco_prod_fk foreign key (prod_id) references prod (id);
-- accounts have transactions with values
create table trxs as
select level as id, mod(level, 10) + 1 as acco_id, mod(level, 17) + 1 as value
from dual connect by level < 100000;
alter table trxs
add constraint trxs_pk primary key (id);
alter table trxs
add constraint trxs_acco_fk foreign key (acco_id) references acco (id);
create index acco_i on acco(prod_id);
create index trxs_i on trxs(acco_id);
alter table acco modify prod_id not null;
alter table trxs modify acco_id not null;
Выполните следующий запрос
select v2.*
from (
select
-- This calculates the balance for every transaction as a
-- running total, subtracting trxs.value from the product's value
--
-- This is the "projection" I mentioned that causes I/O. Leaving it
-- away (setting it to 0), would improve the execution plan
prod.value - v1.total balance,
acco.id acco_id
from (
select
acco_id,
sum(value) over (partition by acco_id
order by id
rows between unbounded preceding
and current row) total
from trxs
) v1
join acco on v1.acco_id = acco.id
join prod on acco.prod_id = prod.id
) v2
-- This is the single-row access predicate. From here, it is
-- clear that there can only be 1 acco and 1 prod
where v2.acco_id = 1;
Анализ
Когдаанализируя планы выполнения для вышеупомянутого запроса (с или без какой-либо проекции prod.value
), я могу воспроизвести чрезмерное количество строк / байтов в плане при доступе к таблице prod
.
Я нашел решение этой проблемы .Но я действительно заинтересован в объяснении того, что происходит не так, и как я мог бы исправить эту проблему, не слишком меняя запрос
Обновление
ОК, после гораздо большего анализа я долженскажем, что реальный проблемный ввод-вывод был вызван тем, что неверный индекс использовался где-то еще.К сожалению, это не было достаточно хорошо спроектировано в общей статистике (или в плане выполнения), чтобы заметить.
Что касается этого вопроса, мне все еще интересно узнать о предполагаемом вводе / выводе в плане выполнения, поскольку это, кажется, сбивает с толку нашего DBA (и меня) снова и снова.И иногда это действительно является источником проблем ввода-вывода ...