Могу ли я узнать, почему для индекса невозможно ускорить обработку запросов для определенных запросов? - PullRequest
1 голос
/ 24 апреля 2020

Я попытался объяснить и отобразить план выполнения для этого запроса:

Объяснить план для

SELECT *
FROM LINEITEM
WHERE l_quantity = 6
   OR l_shipMode = 'MAIL';

SELECT * FROM table(dbms_xplan.display);

Вывод:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 98068815

------------------------------------------------------------------------------
| Id  | Operation     | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   287K|    34M|  8802   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| LINEITEM |   287K|    34M|  8802   (1)| 00:00:01 |
------------------------------------------------------------------------------

Тогда я создал индекс для l_quantity и l_shipMode:

CREATE INDEX lineItemIdx ON LINEITEM(l_quantity, l_shipMode);

Затем я объясняю и снова отображаю план выполнения:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 98068815

------------------------------------------------------------------------------
| Id  | Operation     | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   287K|    34M|  8802   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| LINEITEM |   287K|    34M|  8802   (1)| 00:00:01 |
------------------------------------------------------------------------------

Разницы нет. Разве запрос не должен теперь использовать индекс?

Ответы [ 2 ]

2 голосов
/ 24 апреля 2020

В вашем запросе есть два условия в сочетании с предложением OR:

 WHERE l_quantity = 6
    OR l_shipMode = 'MAIL';

Это означает, что для оценки критериев фильтра индекс

 INDEX lineItemIdx ON LINEITEM(l_quantity, l_shipMode);

может ' не работает должным образом для каждой из двух частей предложения OR.

Таким образом, запрос требует полного сканирования, а индекс бесполезен.

Индекс в этом случае должен быть полезно только с условием

WHERE l_quantity = 6

или

WHERE l_quantity = 6
  AND l_shipMode = 'MAIL';

или использовать два индекса и перестроить запрос, используя два отдельных запроса на основе UNION

1 голос
/ 24 апреля 2020

Увы, большинство баз данных очень плохо справляются с оптимизацией or выражений (Oracle является исключением).

Вы можете получить то, что хотите, используя union all:

SELECT li.*
FROM LINEITEM li
WHERE l_quantity = 6
UNION ALL
SELECT li.*
FROM LINEITEM li
WHERE l_shipMode = 'MAIL' AND l_quantity <> 6;

Для этого вам нужно два индекса: LINEITEM(l_quantity) и LINEITEM(l_shipMode, l_quantity).

...