Как заставить СУБД начать строить запрос от другой таблицы?

Запрос большой, много джойнов, но суть такая:

  • Есть таблица TABLE_A из которой выборка небольшая. Логично вытянуть эту выборку первой и к ней джойнить другую таблицу (TABLE_B).
  • При некоторых входных параметрах предиката для выборки из TABLE_A план строится именно описанным образом. Но при других (чуть больше будет выборка, но не значительно) первым начинает выполняться запрос из TABLE_B и уже к ней джойнится таблица TABLE_A.

Это занимает в десятки раз больше времени. Уж не знаю, что за беда там со статистиками.

Как явным образом подсказать СУБД строить запрос именно от TABLE_A?
И возможно ли это?


Ответы (1 шт):

Автор решения: 0xdb

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

Now Oracle provides a number of tools, including the SQL Tuning Advisor, SQL plan management, and SQL Performance Analyzer, to help you address performance problems that are not solved by the optimizer. Oracle strongly recommends that you use those tools rather than hints. [...]

Hints should be used sparingly, and only after you have collected statistics on the relevant tables and evaluated the optimizer plan without hints using the EXPLAIN PLAN statement.

Можно попробовать подсказки LEADING (рекомендуемый) и ORDERED, но оптимизатор всё равно может на основании других критериев выбрать другой план, то что он обязательно "послушается", нет никакой гарантии:

select /*+ LEADING(d e) */ /*+ ORDERED */  e.*, d.*
from hr.departments d
join hr.employees e on d.department_id = e.department_id
/

Execution Plan
----------------------------------------------------------
Plan hash value: 1343509718

--------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |   106 |  9540 |     6  (17)| 00:00:01 |
|   1 |  MERGE JOIN                  |             |   106 |  9540 |     6  (17)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |    27 |   567 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | DEPT_ID_PK  |    27 |       |     1   (0)| 00:00:01 |
|*  4 |   SORT JOIN                  |             |   107 |  7383 |     4  (25)| 00:00:01 |
|   5 |    TABLE ACCESS FULL         | EMPLOYEES   |   107 |  7383 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

PS чтобы выключить или включить подсказку достаточно вставить пробел /* + или убрать его /*+ соответственно.

→ Ссылка