|
Андрей Киселев
Ведущий Инженер Группы Интеграции
ЗАО "ПЕТЕР-СЕРВИС"
Andrew.Kiselev@billing.ru
http://www.billing.ru
ОСНОВНЫЕ ПРИЧИНЫ ОШИБОК COST BASED OPTIMIZER (CBO).
Эта статья изначально писалась в раздел FAQ форума sql.ru, поэтому специальных поясняющих примеров я не придумывал, в качестве примеров даны ссылки на реальные обсуждения в форуме sql.ru и на сайте того самого Тома
(asktom.oracle.com) .
Я буду рассматривать только работу стоимостного оптимизатора, отличия CBO от Rule Based Optimizer, вопросы выбора между ними и проблемы при смене типа оптимизатора не входят в обсуждаемые вопросы. В конце статьи приведены ссылки на материалы, посвященные работе CBO, которые на самом деле и представляют наибольшую ценность для желающих разобраться в механизмах работы стоимостного оптимизатора Oracle. Кроме того, нельзя не сказать о вышедшей, уже и в русском переводе, книге Дж. Льюиса "Oracle основы стоимостной оптимизации", которая на текущий момент является наиболее подробным источником сведений по CBO.
Далее я попытаюсь привести основные причины, приводящие к ошибкам оптимизатора (под ошибками тут понимается построение неэффективного плана выполнения запроса) и способы борьбы с ними.
0. Оптимизатор не ошибся.
Часто ошибается как раз разработчик пытающийся заставить оптимизатор работать по "эффективному" как ему кажется плану, использовать индекс там где это не эффективно, избегать Full Table Scan там, где он может являться лучшим решением и т.п.
Пример 1(sql.ru). Пример 2(asktom).
Для начала всегда стоит убедиться, что план, по которому Вы хотите заставить работать оптимизатор действительно эффективнее на реальном наборе данных (например, вставляем хинты и сравниваем статистику работы запросов на реальных данных в реальной среде).
Если ошибся всё-таки оптимизатор, идем дальше...
1. Неверная оценка мощности (cardinality) множества строк возвращаемого на некотором шаге плана обработки.
1.1 Статистика отсутствует или устарела.
- Актуальность статистики.
CBO основывается в своих решениях на некоторых вероятностных предположениях, и ему для работы нужно "горючее" что бы строить эти предположения, т.е. статистика по используемым объектам. И эта статистика должна соответствовать реальному состоянию данных.Она не обязательно должна быть "свежей", если таблица не изменяется, какой смысл по ней собирать статистику? Обычно принято считать, что статистику надо пересобрать, после того как содержимое таблицы изменилось на 10%, и в основном это правильно. Механизм автоматического сбора статистики в Oracle 10g работает, по-моему, по этому же правилу. Но если данные изменились на те самые 10%, но это не оказывает существенного влияния на распределение данных и работу оптимизатора, то может и не стоит дергать лишний раз сбор статистики. Некоторые взгляды на тему "когда надо собирать статистику" приведены в статье [5] (2.5 Dave Ensor's DBMS_STATS paradox.). До Oracle10, даже если по таблицам пользовательских схем собрана статистика, причиной проблемы может являться широко используемая таблица sys.dual, которую оптимизатор рассматривает как самую обычную таблицу, при отсутствии статистики на которой применяются стандартные значения статистик по умолчанию, а не как специальную таблицу с 1 записью.
1.1.2 Временные таблицы.
Временные таблицы по своей природе не могут иметь постоянной статистики, но CBO надо как-то принимать решения при построении плана запроса с использованием временных таблиц, в таких случаях, как и при отсутствии статистики на постоянных таблицах CBO использует значения статистик по умолчанию. Если предположения "по умолчанию" для таких таблиц ведут к неверным решениям CBO, можно попробовать предпринять след. шаги:
Решения:
а) Занести статистику для временной таблицы вручную при помощи пакета dbms_stat (Временные таблицы программа заполняет сама и соответственно она должна знать чего и сколько туда положила)или собрать статистику при “типичном” заполнении временной таблицы. (Следует помнить, что установленная статистика будет использоваться и другими сессиями).
б) Для Oracle >= 9i можно воспользоваться механизмом DYNAMIC SAMPLING, сервер сам предварительно выполнит оценку по таблицам без статистики, сделав тестовую выборку.
в) Предполагаемый объем выборки из временной таблицы можно указать недокументированным хинтом CARDINALITY ( >= 9i ).
Пример 1 CBO и временные таблицы.
Пример 2 (asktom) Temp tables CBO statistics.
1.1.3 Табличные функции (в т.ч. pipelined).
В этом случае CBO не в состоянии определить мощность (cardinality) выборки, и основывается на некотором значении по умолчанию, которое достаточно велико (я встречал только значение 8168, но возможно эта величина связана с размером блока базы данных и/или OS).
Решения:
Если предположения по умолчанию приводят к ошибке, то другого способа кроме как указывать мощность хинтом СARDINALITY я не знаю (ну или прямого указания путей доступа хинтами, что мне кажется худшим путем). Пример1 (sql.ru). Пример 2 ( AskTom).
1.2 Ошибка в расчете cardinality, при наличии актуальной статистики
1.2.1 Перекошенное (skewed) распределение значений атрибута из
предиката запроса .
Оптимизатор предполагает равномерное распределение значений столбца таблицы (uniform distribution of column values over all blocks and all rows [3]). В результате идет неверная оценка селективности предиката запроса, если в нем присутствует "перекошенный" столбец.
Решения:
Помочь решить проблему может собранная гистограмма по "кривому" столбцу.
1.2.2 Использование bind-переменных и функций.
При использовании bind-переменных, оптимизатору не известны возможные значения в них подставляемые (<9i или отключён bind peeking) и он вынужден исходить из необходимости работоспособности запроса при любых подставляемых значениях. Например (sql.ru).
Для основных видов предикатов селективность при использовании bind-переменных оценивается следующим образом:
c1 = :bind1 1/NDV ( NDV - Number of Distinct Values)
c1 > :bind1 5%
c1 >= :bind1 5%
c1 like :bind1 25%
(Тут Oracle достаточно оптимистичен, в теории полагают для выражения
c1>:bind1 считать селективность 33%).
Аналогичное поведение можно наблюдать при использовании в предикатах функций, например, 'mod(number_col,10)= 0', оптимизатор для них будет использовать некоторые фиксированные проценты селективности, аналогичные показанным для bind переменных с некоторыми вариациями. Использование псевдофункций/псевдостолбцов в вычисляемых выражениях тоже в ряде случаев приводит к использованию фиксировнных значений селективности, например, в выражении 'start_date > SYSDATE+1','SYSDATE+1' уже не вычисляется как константа, а рассматривается как переменная с неизвестным значением (в 10 такое поведение SYSDATE исправлено).
Если предположения с фиксированной селективностью оказываются существенно неверными, то есть вероятность получить весьма неэффективный план.
Решения:
а) Для сложных, редко повторяемых запросов, может иметь смысл
отказаться от bind-переменных в пользу константных значений.
б) Можно попробовать дополнительными предикатами с константами
помочь оптимизатору уточнить селективность.
в) Oracle >= 9i умеет "подсматривать" значение bind-переменной при
разборе запроса Peeking of User-Defined Bind Variables.
Хотя это "палка о двух концах", первый вызов может быть
нетипичным.
г) Можно поиграться со сбором гистограмм с разным числом buckets.
Несмотря на то, что напрямую они здесь не могут использоваться
(при bind peeking конечно могут ),
но собранные гистограммы влияют на значение density для столбца,
которое в некоторых случаях используется при расчете селективности [3].
д) Убить статистику (будут использоваться значения по умолчанию )
или подсунуть неправильную, но ведущую к верным выводам.
е) В случае использования функций от столбцов может помочь создания функционального индекса и сбор по нему статистики.
ж) SQL Profiles для >=10g
1.2.3 Коррелированность предикатов
Оптимизатор исходит из предположения о независимости предикатов (the predicate independnece assumption [3]). Если же столбцы участвующие в сложном предикате коррелированны, это ведет к неверной оценке селективности предиката. Например, в некоторой таблице есть два столбца "a" и "b", "a" принимает четыре разных значения 1..4 (density=0.25), "b" сорок разных значений 10..49 (density = 0.025 ), но значение, которое может принимать "b" зависит от значения "a", например для "a"=1, "b" может принимать значения в диапазоне 10..19 и.т.д. В этом случае при расчете селективности предиката "a=2 and b=21" оптимизатор исходя из предположения о независимости предикатов рассчитает селективность предиката как 0.25 *0.025 = 0.00625 (т.е. если в таблице допустим 1000 записей, предикату будут удовлетворять предположительно 6 записей), в то время как фактически селективность будет 0,25*0,1 = 0,025 ( т.е. на самом деле для той же таблицы с 1000 записей, предикату будут удовлетворять около 25 записей).
Решения см. в след. разделе (1.2.4.)
1.2.4 Ошибка оптимизатора в оценке мощности соединения.
Ошибка оптимизатора в оценке мощности соединения может быть вызвана неверностью предположения о "равномерности соединения" (join uniformity assumption [3]) и "принципа включения" (principle of inclusion [5.1], каждое значение из меньшего соединяемого источника имеет соответствие в большем соединяемом источнике строк).
Поскольку предположения о "равномерности" являются основополагающими в работе оптимизатора, то и несоответствие этим предположениям реальных данных ведет к тому, что оптимизатор ошибается. [3]
Решения (1.2.3 и 1.2.4):
a) Для Oracle 9i и выше в случае коррелированности предикатов (1.2.3 ) вычислить более точную селективность поможет использование Dynamic Sampling (см. документацию для своей версии Oracle).
б) И для 1.2.3 и для 1.2.4 вручную изменив значение статистики на основании фактического числа обработанных строк при выполнении некоторого шага запроса (можно посмотреть оттрасировав сессию или в соответствующих V$ представлениях), попытаться добиться правильного определения количества строк возвращаемого проблемным шагом запроса (Tuning by Cardinality Feedback [5]).
в) Случаи 1.2.3 и 1.2.4 можно лечить хинтами (указывая нужный access path) или при помощи механизма стабилизации планов запросов stored outlines.
г) В некоторых случаях, если ошибка вызвана неравномерным распределением значений в столбцах, по которым идет соединение, может помочь сбор гистограмм [5.1].
д) SQL Profile для >=10g
1.2.5 Неверный выбор типов данных и наличие "специальных" значений
Часто приходится наблюдать случаи, когда для хранения данных по тем или иным причинам используются столбцы несоответствующего реальному содержанию данных типа. Например, числа хранятся в полях типа varchar2, даты в полях типа varchar2 или number в формате типа 'ГГГГММДД'. Это может сослужить плохую службу при расчете мощности, например, выборки по диапазону. Если между датами 30 декабря 2006 года и 1 января 2007 года 2 дня, то между числами 20070101 и 20061230 8871 "день", очевидно, это может привести как к ошибке в расчете всего диапазона значений в таблице, так и к ошибке в расчете доли приходящейся на требуемый диапазон. Также плохую шутку может сыграть использование "специальных" значений сильно выходящих за диапазон "нормальных" значений, например, условная дата бесконечность '31.12.2999'. Оптимизатор будет считать, что значения в столбце равномерно распределены между минимальным и максимальным ('31.12.2999') и рассчитанная cardinality для реальных диапазонов значений может быть сильно меньше фактической (это, по сути, частный случай неравномерного распределения значений столбца, рассмотренного в 1.2.1). Пример (sql.ru).
Решения:
а) Ошибки проектирования лучше исправлять на уровне проектирования. ;-)
б) Помочь сгладить проблему может собранная гистограмма по столбцу.
в) Можно лечить хинтами или при помощи механизма стабилизации планов запросов stored outlines.
г) SQL Profile для >=10g
Решение для 10g (в общем по пункту 1.2):
В Oracle 10g появился механизм SQL Profiles, который может построить и предложить использовать SQL Tuning Advisor при обработке запроса. SQL Profile представляет собой набор директив указывающих оптимизатору коэффициенты для коррекции вычисленных значений мощности результирующих множеств получаемых по шагам запроса. Данный механизм
может помочь в случаях, когда ошибки оптимизатора вызваны неправильным определением cardinality ввиду не соответствия распределения данных базовым предположениям оптимизатора.
2. Неправильная оценка соотношения стоимости одноблочных и многоблочных операций i/o.
Обычно эта проблема выбора оптимизатором между индексным доступом к данным и доступом по Full Scan.
Решения:
a) Для Oracle >= 9iR2 наиболее верным решением будет сбор системной статистики, часть из которой это как раз IO_COST. Другая часть, CPU_COST тоже не будет лишней, поскольку дает уточнение стоимости отдельных операций выполнения запроса. К тому же при таком подходе увеличение db_file_multiblock_read_count уже не будет напрямую приводить к преобладанию FULL SCAN. В "новой модели стоимости" (использующей системную статистику) параметр OPTIMIZER_INDEX_COST_ADJ продолжает использоваться, и влияет на расчет стоимости индексного доступа по-прежнему сильно и грубо. Поскольку в "новой модели стоимости" разница между одноблочными и многоблочными операциями i/o уже учтена за счет использования собранной статистики, я бы рекомендовал после сбора системной статистики выставлять значение параметра OPTIMIZER_INDEX_COST_ADJ в значение по умолчанию ( 100), и менять его в дальнейшем очень аккуратно по результатам анализа планов запросов и производительности. Параметр OPTIMIZER_INDEX_CACHING так же продолжает использоваться при оценке стоимости Nested Loops с использованием индекса и INLIST ITERATOR.
б) до 9i и для консерваторов остается развлечение с параметрами DB_FILE_MULTIBLOCK_READ_COUNT, OPTIMIZER_INDEX_CACHING, OPTIMIZER_INDEX_COST_ADJ.
Note! Установка параметра OPTIMIZER_INDEX_COST_ADJ в агрессивно малые значения может привести к нивелированию стоимости доступа по разным индексам, и соответственно к выбору оптимизатором доступа по неоптимальному индексу (вычисленная стоимость доступа по индексу умножается на OPTIMIZER_INDEX_COST_ADJ/100 и округляется до целого). Пример (sql.ru).
3. Недоступность пути доступа к данным.
Простейшим и наиболее часто встречаемым случаем будет, пожалуй невозможность использования индекса, если в результирующее множество могут попасть строки с NULL значением по ключу этого индекса (NULL значения Oracle в индексе не хранит), случай тсутствия среди предикатов ведущих столбцов индекса (начиная с 9i в этом случае доступен метод доступа Index Skip Scan) или случай когда в предикате используется функция (выражение) от проиндексированного столбца.
Решения:
Если хотите, что бы некий путь доступа был рассмотрен, сделайте возможным его применение. Например, добавив условие field is not null, в случае если индекс не применяется по причине того, что оптимизатор ожидает возможность появления NULL значений.
4. Неверно выбран режим оптимизации (optimizer_mode).
Оптимизатор не обладает ясновидением и не в состоянии понять, что Вы хотите от него получить, весь результат целиком или как можно быстрее первые n-записей. Возможно, для текущей сессии, запроса или всей базы надо изменить optimizer_mode. Допустим, для программ интерактивно взаимодействия с пользователем, часто выгоднее будет режим FIRST_ROWS (FIRST_ROWS_n для >=9i), поскольку пользователь ряд ли хочет увидеть ту пару миллионов записей, что вы для него выбрали.
Лучшее выполнение запросов с хинтом RULE, так же может служить признаком того, что для вашего приложения правильнее использовать режимом "наискорейшего отклика" (плюс правильная оценка операций i/o по пункту 2.).
5. Большое число таблиц в запросе.
Большое число таблиц может не позволить оптимизатору проверить все возможные варианты соединения и "оптимальный" остается за рамками рассмотрения.
Metalink:Note:73489.1
Number of tables Total number Proportion of
of possible total represented
permutations by 80,000 permutations
(n) (n!) ( 80,000 / n! * 100)
1 1 Not Relevant
2 2 Not Relevant
3 6 Not Relevant
4 24 Not Relevant
5 120 Not Relevant
6 720 Not Relevant
7 5040 Not Relevant
8 40320 Not Relevant
9 362880 22%
10 3628800 2.2%
11 39916800 0.2%
12 479001600 0.016%
13 6226020800 0.001284%
14 87178291200 0.000092%
15 1307674368000 0.000006%
Таким образом, при значении optimizer_max_permutations=80000, уже для 9-ти таблиц может быть рассмотрено только 22% вариантов соединения.
Решения:
а) Можно поиграться с порядком перечисления таблиц во фразе from, ну и с хинтами LEADING и ORDERED.
б) Правильное определение мощности выборок для базовых таблиц так же может помочь оптимизатору не пропустить лучший план.
в)Можно попробовать увеличить или уменьшить значение параметра optimizer_max_permutations. Параметр OPTIMIZER_MAX_PERMUTATIONS отвечает за количество
рассматриваемых вариантов порядка соединения таблиц, в запросах с соединением. Данный параметр работает только когда число таблиц в соединении больше чем указано в параметре OPTIMIZER_SEARCH_LIMIT ( по умолчанию 5). Если значение параметра OPTIMIZER_MAX_PERMUTATIONS меньше 80000, то для определения порядка соединения Oracle использует некий "эвристический алгоритм" (и этот путь наиболее верный, IMHO).
Note. Начиная с Oracle 9, параметр OPTIMIZER_SEARCH_LIMIT является устаревшим и присутствует только в скрытом виде. Начиная с Oracle 10 параметр OPTIMIZER_MAX_PERMUTATIONS так же скрыт.
6. Неоправданное применение оптимизатором новых возможностей.
Subj. (Например (sql.ru).)
Решения:
а) Дождаться следующего патча, где может всё исправят. :)
б) Попытаться найти и изменить параметры, которые провоцируют использование данной возможности (feature).
в) Если есть соответствующий параметр возможность можно отключить.
г) Поставить optimizer_features_enable в значение, при котором новая возможность не доступна (лучшее средство от головной боли - гильотина!).
7. Неверная трансформация запроса.
Некоторые операции трансформации запроса, например, в 9i это Subquery Unnesting , View Merging, Comlex View Merging, Oracle выполняет на основе эвристических правил, анализ стоимости для планов не преобразованного запроса не выполняется, и таким образом оптимальный план может не попасть в рассмотрение.
Решения:
а) Используйте хинты запрещающее “вредное” преобразование запроса или перепешите View так что бы Oracle не мог использовать преобразование (например, хинт NO_MERGE или добавление условия ' and rownum>0' для запрещения View Merging.).
б) В Oracle 10g многие преобразования производятся с оценкой стоимости, это касается в частности Subquery Unnesting и View Merging и Complex View Merging. Но и рассматривая все варианты, оптимизатор может ошибиться и по прежнему понадобится управление преобразованием хинтами или меры для уточнения расчетов оптимизатора.
Note!!! Такое изменение поведения оптимизатора в Oracle 10g может привести к ухудшению производительности запросов оптимизированных под старые версии при помощи трюков типа ‘and rownum>0’ или хинтов +NO_UNNEST, для таких уже “оптимизированных” запросов планы, построенные оптимизатором Oracle 10g, могут оказаться не эффективными .
Некоторые частные случаи:
1) "Почему мой индекс не используется?!"
Случай не использования индекса чаще всего является следствием одной (или нескольких) указанных выше причин. Обычно это происходит потому, что индекс невозможно использовать (см. п.3) или не выгодно использовать (см п.0) или оптимизатор ошибочно думает, что индекс невыгодно использовать (см. п.1 и п.2).
Этот вопрос достаточно широко освещен во многих статьях и на форумах, несколько ссылок приведены в списке в конце страницы [13]-[16].
2) При установке параметра cursor_sharing=force символьные и числовые константы в запросах заменяются BIND-переменными, соответственно могут возникнуть проблемы описанные в 1.2.2. .
3) Во View используемом в запросе могут присутствовать хинты, которые и мешают оптимизировать запрос в целом.
4) Максимальное значение числа секций гистограмм (250) может не позволить отследить "неравномерность" (часто встречающиеся значения могут замаскировать редко встречающиеся значения, если они попадают в одну секцию гистограммы). Кроме того, для символьных столбцов гистограммы собираются только по первым символам строки (до 31-го символа).
5) Начиная с версии 9i Oracle научился подсматривать значения переменных привязки при hard parse запроса, это позволяет строить более эффективный план при этих значениях переменных. К сожалению, этот план может оказаться не эффективным для другого набора значений переменных, но будет использоваться план построенный и попавший ранее в shared pool.
6) Если используется секционированная (partitioned) таблица, то оптимизатор использует статистику уровня секции, только если на этапе синтаксического анализа известно, что будет использоваться одна это секция, в остальных случаях используется статистика уровня таблицы ( которая может быть не обновлена, например, при exchange partition, или плохо отражать распределение данных в секциях, с которыми идет работа).[26]
При работе с секционированными таблицами нас может ждать еще много сюрпризов.
7) В режиме FIRST_ROWS для запросов с упорядочиванием оптимизатор может использовать сканирование по индексу соответствующему упорядочиванию, даже если оцениваемая стоимость такого плана сильно превышает стоимость плана не использующего этот индекс. В этом случае лучше использовать современный режим оптимизатора first_rows_n, или попробовать по согласованию с oracle support настроить режим оператора first_rows при помощи скрытого параметра _sort_elimination_cost_ratio, но он работает не всегда и не во всех режимах OPTIMIZER_FEATURES_ENABLED.
8) Оптимизатор может построить дополнительные предикаты, используя транзитивное замыкание имеющихся предикатов и предикатов, сгенерированных из ограничений, а иногда даже убрать существующие предикаты. Это может приводить к "интересным" эффектам при построении плана запроса. Пример(sql.ru)
Итого основными причинами "заблуждений" оптимизатора являются следующие:
1. Неверная оценка Cardinality.
2. Неверная оценка IO_COST для одноблочных и многоблочных операций.
3. Недоступность желаемого пути доступа к данным.
4. Неверный выбор режима оптимизации (optimizer_mode).
Извиняюсь, что не привел волшебное значение параметра OPTIMIZER_QUALITY=COOL, и прочие волшебные значения параметров настройки оптимизатора, боюсь, их придется определять для каждого случая свои.
Некоторые связанные вопросы:
1) Получение плана запроса:
Oracle9i Database Performance Tuning Guide and Reference Release 2 (9.2)SQL-Related Performance Tools.[1]
Oracle® Database Performance Tuning Guide 10g Release 2 (10.2) Optimizing SQL Statements[1.1].
Пример использования представления V$SQL_PLAN есть в статье [2].
Автотрассировка в SQL плюс рассмотрена здесь [17]( Autotrace in SQLPLUS. T.Kyte ).
2) Как включить трассировку сессии:
5 Способов Включить SQL-trace.[18]
Анализ результатов tkprof.[19]
P.S. Спасибо Сергею Маркеленкову за замечания и дополнения.
Ссылки по теме:
[1]Oracle9i Database Performance Tuning Guide and Reference Release 2 (9.2) Part Number A96533-02 (анг.)
[1.1]Oracle® Database Performance Tuning Guide 10g Release 2 (10.2) Part Number B14211-01 (анг.)
[2]What is new in the Oracle 9i CBO Wolfgang Breitling, Centrex Consulting Corporation (анг.)
[3]Fallacies of the Cost Based Optimizer Wolfgang Breitling, Centrex Consulting Corporation (анг.)
[4]A Look Under the Hood of CBO: The 10053 Event Wolfgang Breitling, Centrex Consulting Corporation (анг.)
[5] Using DBMS_STATS in Access Path Optimization Wolfgang Breitling, Centrex Consulting Corporation (анг.)
[5.1] Joins, Skew and Histograms Wolfgang Breitling, Centrex Consulting Corporation (анг.)
[5.2] Histograms - Myths and Facts Wolfgang Breitling, Centrex Consulting Corporation (анг.)
[6]Understanding System Statistics Jonathan Lewis (анг.)
[7]The Search For Intelligent Life in the Cost-Based Optimizer Tim Gorman, Evergreen Database Technologies, Inc.( рус.) перевод Edward A. Shevtsov.
[8] Когда ошибается CBO? Edward A. Shevtsov (рус.)
[9]Query optimization in Oracle 9i. An Oracle white Paper George Lumpkin, Hakan Jakobsson, Oracle Corporation(анг.)
[9.1]Query Optimization in Oracle Database10g Release 2. An Oracle white Paper George Lumpkin, Hakan Jakobsson, Oracle Corporation(анг.)
[10]Сколько стоит Стоимость? Edward A. Shevtsov ( рус.)
[11]Cost Control: Inside the Oracle Optimizer,Part 1,Part 2 Donald K. Burleson (анг.)
[12]CBO Defaults. DBGroup Consalting Список параметров оптимизатора.
[13]“Why isn't Oracle using my index ?” Jonathan Lewis (анг.)
[14]DEFENSE OF FULL-TABLE SCANS JEFF MARESH, MARESH CONSULTING, INC. (анг.)
[15]Why is cost based optimizer behaving poorly? AskTom
[16]Индексы на основе битовых карт Jonathan Lewis (рус.) перевод Валерия Кравчука.
[17]Autotrace in SQLPLUS. Tom Kyte (анг.)
[18]5 Способов Включить SQL-trace Edward A. Shevtsov ( рус.)
[19]Анализ результатов tkprof.Tom Kyte (рус.) Перевод Валерия Кравчука.
[20]Metalink Note: 212809 "Cost Based Optimizer Limitations"
[21]Metalink Note:68992.1 "Predicate Selectivity"
[22]Metalink Note:66030.1 "Relationship between OPTIMIZER_MAX_PERMUTATIONS and OPTIMIZER_SEARCH_LIMIT"
[23]Metalink Note:73489.1 "Affect of Number of Tables on Join Order Permutations"
[24]Metalink Note:149560.1 "Collect and Display System Statistics (CPU and IO) for CBO"
[25] Metalink Note:271196.1 "Automatic SQL Tuning - SQL Profiles"
[26] ORACLE основы стоимостной оптимизации. Дж. Льюис. СПб:Питер, 2007
|