Оптимизация запросов Oracle: почему мой второй запрос быстрее? - PullRequest
1 голос
/ 03 мая 2010

У меня возникли некоторые проблемы с производительностью запроса Oracle, поэтому я скачал пробную версию Quest SQL Optimizer для Oracle , которая внесла некоторые изменения, которые значительно улучшили производительность запроса. Я не совсем уверен, почему рекомендуемый запрос имел такое улучшение; кто-нибудь может дать объяснение?


До:

SELECT t1.version_id, 
       t1.id, 
       t2.field1, 
       t3.person_id, 
       t2.id 
  FROM table1 t1, 
       table2 t2, 
       table3 t3 
 WHERE t1.id = t2.id 
   AND t1.version_id = t2.version_id 
   AND t2.id = 123
   AND t1.version_id = t3.version_id 
   AND t1.VERSION_NAME <> 'AA' 
 order by t1.id
  • Стоимость плана: 831
  • Истекшее время: 00: 00: 21.40
  • Количество записей: 40,717

После того, как:

SELECT /*+ USE_NL_WITH_INDEX(t1) */ t1.version_id, 
       t1.id, 
       t2.field1, 
       t3.person_id, 
       t2.id 
  FROM table2 t2, 
       table3 t3,
       table1 t1 
 WHERE t1.id = t2.id + 0
   AND t1.version_id = t2.version_id + 0
   AND t2.id = 123
   AND t1.version_id = t3.version_id + 0
   AND t1.VERSION_NAME || '' <> 'AA' 
   AND t3.version_id = t2.version_id + 0
 order by t1.id
  • Стоимость плана: 686
  • Истекшее время: 00: 00: 00.95
  • Количество записей: 40,717

Вопросы:

  1. Почему помогает реорганизация порядка таблиц в предложении FROM?

  2. Почему добавление + 0 в сравнение WHERE помогает?

  3. Почему || '' <> 'AA' в предложении WHERE VERSION_NAME помогает сравнение? Это более эффективный способ обработки nulls в этом столбце?

Ответы [ 5 ]

2 голосов
/ 04 мая 2010

Первое, что нужно отметить, это то, что план «после» стоил дешевле, чем план «до».

Это говорит нам о том, что план, выбранный для второго запроса, не был рассмотрен для первого запроса, поскольку Oracle выбрала бы план с более низкой стоимостью.

Добавление подсказки USE_NL_WITH_INDEX не повлияло бы на стоимость любого плана. Что он делает, если доступен план с вложенным циклом с индексом, то любой другой план будет исключен из рассмотрения, даже если Oracle будет более эффективным планом.

Во-вторых, предикат "t1.id = t2.id" позволяет нам начинать с t1 и связываться с t2 или начинать с t2 и связываться с t1. Изменение этого предиката на «t1.id = t2.id + 0» означает, что он может перейти только от t2 (добавить 0 к идентификатору) для ссылки на t1. Oracle не достаточно умна, чтобы понять, что она может начинаться с t1 (минус 0 от идентификатора) и присоединяться к t2 (или что добавление / минус 0 в любом случае не имеет значения).

Оба этих трюка не позволяют использовать определенные пути доступа. Ни один из них не может объяснить очевидное снижение стоимости выбранного плана.

Учитывая "И t1.version_id = t2.version_id" и "И t1.version_id = t3.version_id", то «t3.version_id = t2.version_id» является заданным (при условии преобразования типов данных). Однако добавление его в явном виде подсказало бы Oracle, что, поскольку применяется дополнительное условие, будет возвращено меньше строк, и это может отразиться на более низкой стоимости.

Если t2 и t3 version_id не были числовыми, это могло бы объяснить изменение стоимости. «+ 0» приведет к преобразованию типа данных, что может позволить использовать индекс. Я думаю, что это вряд ли.

Я подозреваю, что первоначальный план двигался с t1 (с t1.id = 123 и version_name <> 'AA'). Дополнительные предикаты (вероятно) заставят его начинать с t2.

лично, мне не нравятся другие оптимизации. Ни один адрес, почему изначально был выбран неправильный план.

2 голосов
/ 03 мая 2010

Если вы выполните оба утверждения в плане объяснения, вы сами увидите разницу. Для этого введите:

explain plan
for
<your query>;

select * from table(dbms_xplan.display);

Если до сих пор неясно, почему возникает разница, вставьте вывод здесь.

С уважением, Роб.

PS: "+ 0" и "|| ''" - это просто уловки, чтобы убедиться, что обычные индексы в столбцах не используются. Они также делают ваш запрос менее читабельным, поэтому я бы настроил их сам, а не полагался на инструмент.

1 голос
/ 04 мая 2010

В дополнение к уже представленным ответам здесь есть ссылка от Ask Tom о настройке с использованием инструментов (или других n пошаговых подходов).

1 голос
/ 03 мая 2010

Я согласен с комментарием Питера - попробуйте вывести подсказку из «улучшенного» запроса и посмотрите, все ли еще он работает.

Вам может потребоваться обновить статистику этой таблицы, если oracle не хочет ее использовать ...

РЕДАКТИРОВАТЬ: столбцы version_id и id имеют одинаковый тип данных в каждой таблице?

0 голосов
/ 04 мая 2010

Почти наверняка статистика в этих таблицах неверна, из-за чего оптимизатор выбирает плохой план.

Соберите статистику по таблицам и индексам (или обратитесь к своему администратору базы данных, если вы не контролируете подобные вещи), а затем повторите ваши запросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...