Ни для кого не секрет, что иногда оптимизатор Oracle ведет себя как хочет, и его настройка превращается в сплошное шаманство и пляски с бубном. На волне этой боли и душевных терзаний, я хочу поговорить о подсказке для оптимизатора OPT_PARAM.
Эта подсказка позволяет вам установить значение некоего параметра оптимизатора в процессе выполнения конкретного необходимого вам запроса.
Согласно документации, допустим, для 11G , с помощью этой подсказки можно установить значения всего пяти параметров:
Например, на моем 12C OPT_PARAM выключает _B_TREE_BITMAP_PLANS.
С этого места, начнем другую грустную историю. Скрытый параметр _B_TREE_BITMAP_PLANS начиная, пожалуй с Oracle 9i по умолчанию поставлен в true. Он позволяет генерировать BITMAP планы для таблиц в B-Tree индексами. Так что CBO может устроить использование BITMAP доступа к данным и без существования BITMAP индекса как такового. Для того, чтобы достичь этой цели, он помещает в план выполнения операции BITMAP CONVERSION FROM ROWIDS и BITMAP CONVERSION TO ROWIDS, которые способны серьезно загрузить CPU. Так что если у вас много строк в таблице - у меня для вас плохие новости. Если сервер с БД целиком ваш, и вы можете делать на нем что вашей душе угодно, то нет проблем с тем, что бы написать
Или же:
Но если вы не администратор проблемной БД, и менять настройки вам кто-то не разрешает, то есть вариант положиться на тот самый OPT_PARAM.
Допустим, у вас есть следующий запрос:
Вот это ужасный план, который генерируется моей базой по умолчанию.
На 43673 записях работает 182,655 секунд, грузит проц и всех бесит.
Теперь воспользуемся великой шаманской магией:
План выполнения запроса для этого случая:
Время работы на тех же данных: 1,405 секунд.
Теперь мы лишились возможности пойти налить кофе, пока у нас проходит обновление.
Эта подсказка позволяет вам установить значение некоего параметра оптимизатора в процессе выполнения конкретного необходимого вам запроса.
SELECT /*+ OPT_PARAM('star_transformation_enabled' 'true') */ * FROM ... ;
Согласно документации, допустим, для 11G , с помощью этой подсказки можно установить значения всего пяти параметров:
- OPTIMIZER_DYNAMIC_SAMPLING,
- OPTIMIZER_INDEX_CACHING,
- OPTIMIZER_INDEX_COST_ADJ,
- OPTIMIZER_SECURE_VIEW_MERGING,
- STAR_TRANSFORMATION_ENABLED
Например, на моем 12C OPT_PARAM выключает _B_TREE_BITMAP_PLANS.
С этого места, начнем другую грустную историю. Скрытый параметр _B_TREE_BITMAP_PLANS начиная, пожалуй с Oracle 9i по умолчанию поставлен в true. Он позволяет генерировать BITMAP планы для таблиц в B-Tree индексами. Так что CBO может устроить использование BITMAP доступа к данным и без существования BITMAP индекса как такового. Для того, чтобы достичь этой цели, он помещает в план выполнения операции BITMAP CONVERSION FROM ROWIDS и BITMAP CONVERSION TO ROWIDS, которые способны серьезно загрузить CPU. Так что если у вас много строк в таблице - у меня для вас плохие новости. Если сервер с БД целиком ваш, и вы можете делать на нем что вашей душе угодно, то нет проблем с тем, что бы написать
ALTER SYSTEM SET "_b_tree_bitmap_plans"=false SCOPE=SPFILE;
ALTER SESSION SET "_b_tree_bitmap_plans"=false;
Но если вы не администратор проблемной БД, и менять настройки вам кто-то не разрешает, то есть вариант положиться на тот самый OPT_PARAM.
Допустим, у вас есть следующий запрос:
UPDATE Item_Table ie SET ie.UPDATE_LOAD_ID = ( SELECT MIN(iet.LOAD_ID) KEEP (DENSE_RANK FIRST ORDER BY iet.ID) FROM Item_Table iet WHERE iet.ID > ie.ID AND iet.KEY = ie.KEY AND nvl(iet.LOCATION_ID,'<**null**>') = nvl(ie.LOCATION_ID,'<**null**>') AND nvl(iet.JOB_ID,'<**null**>') = nvl(ie.JOB_ID,'<**null**>') ) WHERE ie.RECENT_FLAG = 'N';
---------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------------------------------- | 0 | UPDATE STATEMENT | | | | 481K(100)| | | 1 | UPDATE | ITEM_TABLE | | | | | |* 2 | TABLE ACCESS FULL | ITEM_TABLE | 43750 | 24M| 655 (1)| 00:00:01 | | 3 | SORT AGGREGATE | | 1 | 582 | | | |* 4 | TABLE ACCESS BY INDEX ROWID BATCHED| ITEM_TABLE | 1 | 582 | 10 (0)| 00:00:01 | | 5 | BITMAP CONVERSION TO ROWIDS | | | | | | | 6 | BITMAP AND | | | | | | | 7 | BITMAP CONVERSION FROM ROWIDS | | | | | | |* 8 | INDEX RANGE SCAN | ITEM_TABLE_KEY_IX | 175 | | 1 (0)| 00:00:01 | | 9 | BITMAP CONVERSION FROM ROWIDS | | | | | | | 10 | SORT ORDER BY | | | | | | |* 11 | INDEX RANGE SCAN | XPK_ITEM_TABLE | 175 | | 3 (0)| 00:00:01 | ---------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("IE"."RECENT_FLAG"='N') 4 - filter((NVL("IET"."LOCATION_ID",:B1)=NVL(:B1,:B1) AND NVL("IET"."JOB_ID",:B1)=NVL(:B2,:B1))) 8 - access("IET"."ITEM_KEY"=:B1) 11 - access("IET"."ID">:B1) filter("IET"."ID">:B1)
Теперь воспользуемся великой шаманской магией:
UPDATE Item_Table ie SET ie.UPDATE_LOAD_ID = ( SELECT /*+ OPT_PARAM('_B_TREE_BITMAP_PLANS','FALSE') */ MIN(iet.LOAD_ID) KEEP (DENSE_RANK FIRST ORDER BY iet.ID) FROM Item_Table iet WHERE iet.ID > ie.ID AND iet.KEY = ie.KEY AND nvl(iet.LOCATION_ID,'<**null**>') = nvl(ie.LOCATION_ID,'<**null**>') AND nvl(iet.JOB_ID,'<**null**>') = nvl(ie.JOB_ID,'<**null**>') ) WHERE ie.RECENT_FLAG = 'N';
---------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------------------------------- | 0 | UPDATE STATEMENT | | | | 3456K(100)| | | 1 | UPDATE | ITEM_TABLE | | | | | |* 2 | TABLE ACCESS FULL | ITEM_TABLE | 43750 | 24M| 655 (1)| 00:00:01 | | 3 | SORT AGGREGATE | | 1 | 582 | | | |* 4 | TABLE ACCESS BY INDEX ROWID BATCHED| ITEM_TABLE | 1 | 582 | 78 (0)| 00:00:01 | |* 5 | INDEX RANGE SCAN | ITEM_TABLE_KEY_IX | 175 | | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("IE"."RECENT_FLAG"='N') 4 - filter(("IET"."ID">:B1 AND NVL("IET"."LOCATION_ID",'<**null**>')=NVL(:B2,'<**null**>') AND NVL("IET"."JOB_ID",'<**null**>')=NVL(:B3,'<**null**>'))) 5 - access("IET"."KEY"=:B1)
Теперь мы лишились возможности пойти налить кофе, пока у нас проходит обновление.
Комментариев нет:
Отправить комментарий