Oracle выбирает оптимизацию индекса - PullRequest
3 голосов
/ 22 сентября 2019

Мне нужно оптимизировать этот запрос с помощью индексации.Я попытался проиндексировать некоторые из столбцов, но это не помогает.Есть ли у кого мысли?

Запрос, который мне нужно оптимизировать:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from vineyard, class, wine
where wine.vid = vineyard.vid
and wine.cid = class.cid
and wine.cid = 'SHIRAZ' and grade = 'A';

Я пытался создать следующие индексы: '' 'create index wine_vid_idx для wine (vid);создать индекс wine_cid_idx для вина (cid);создать индекс wine_grade_idx для Wine (класс); `` `

Мой план выполнения для исходного запроса:

----------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |    42 |  9114 |    10   (0)| 00:00:01 |
|*  1 |  HASH JOIN                    |              |    42 |  9114 |    10   (0)| 00:00:01 |
|   2 |   NESTED LOOPS                |              |    42 |  6930 |     2   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| CLASS    |     1 |    50 |     1   (0)| 00:00:01 |
|*  4 |     INDEX UNIQUE SCAN         | SYS_C0027457 |     1 |       |     1   (0)| 00:00:01 |
|*  5 |    TABLE ACCESS CLUSTER       | WINE    |    42 |  4830 |     1   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT                                                                                                                                                                                                                                                                                           
---------------------------------------------------------------------------------------------
|   6 |   TABLE ACCESS FULL           | VINEYARD |   160 |  8320 |     8   (0)| 00:00:01 |

Ответы [ 3 ]

1 голос
/ 22 сентября 2019

Для начала: вы используете старый синтаксис соединения (фактически 1980-х).Вот как мы могли бы написать запрос сегодня:

Select
   w.vintage, w.wine_no, w.wname, w.pctalc, w.grade, w.price, w.vid, v.vname, w.cid, c.cname
from wine w
join vineyard v on v.vid = w.vid
join class c on c.cid = w.cid
where w.cid = 'SHIRAZ' 
and w.grade = 'A';

Здесь достаточно просто взглянуть на предложение WHERE, чтобы увидеть, что вы ищете вина, соответствующие классу и сорту.Итак, индекс по двум столбцам.Порядок может иметь значение, поэтому укажите два индекса.Расширьте это с идентификатором виноградника, чтобы быстро добраться до таблицы виноградника.

Что касается класса и виноградника, у вас уже должны быть индексы на их идентификаторах.Возможно, вы захотите добавить один столбец для каждой выбранной таблицы, чтобы СУБД могла получать значения непосредственно из индекса.

create index idx01 on wine ( cid, grade, vid );
create index idx02 on wine ( grade, cid, vid );
create index idx03 on class ( cid, cname );
create index idx04 on vineyard ( vid, vname );

Использование плана выполнения для обнаружения неиспользуемых индексов (запросбудет использовать только idx01 или idx02 или даже ни один из них, но не оба) и удалит их.

1 голос
/ 22 сентября 2019

Индексация является часто эффективной мерой для оптимизации запросов, однако вам необходимо выполнить дальнейшие шаги.Поиск по тексту, как правило, медленнее, поэтому настоятельно рекомендуется изменить таблицу class, чтобы она имела числовое значение primary key и избегала хранения таких текстов, как SHIRAZ, в вашем винном столе, а скорее числовое *От 1003 * до class table и сохраните текст SHIRAZ ровно один раз для его записи class, на который будет ссылаться из wine table через числовое значение.Также вы должны сделать то же самое для grade.Если у вас еще нет grade table, создайте его с числовым значением primary key и полем для хранения значений, например A.

Наконец, ваш запрос вычисляет умножение Декарта, которое,Как мы знаем из теории множеств, совпадает ли каждая координата в топологии задачи.Кроме того, как мы знаем из реляционной алгебры, ваше предложение where будет работать для всех точек вашего трехмерного (виноградник, класс, вино) проблемного пространства.Насколько я знаю, если вы реорганизуете свой запрос для использования объединений, он должен стать намного быстрее, потому что есть некоторые оптимизации для объединений, чтобы избежать вычисления всех точек в вашей топологии.

Давайте проведем рефакторинг вашего текущего запроса:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from wine
join class
on wine.cid = class.cid and wine.cid = 'SHIRAZ' and wine.grade = 'A'
join vineyard
on wine.vid = vineyard.vid;

Давайте проведем рефакторинг этого запроса, чтобы он был совместим с вашей схемой после предложенных мною структурных изменений:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from wine
join class
on wine.class_id = class.id and class.cid = 'SHIRAZ'
join grade
on wine.grade_id = grade.id and grade.value = 'A'
join vineyard
on wine.vid = vineyard.vid;

Кроме того, поскольку можно с уверенностью предположить, что существует всего несколько классови на виноградниках мы можем изменить порядок ввода таблиц в запрос:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from grade
join wine
on wine.grade_id = grade.id and grade.value = 'A'
join class
on wine.class_id = class.id and class.cid = 'SHIRAZ'
join vineyard
on wine.vid = vineyard.vid;

Если есть еще какие-то шаги, нужно предпринять дальнейшие шаги, дайте мне знать, если необходимы дальнейшие шаги.

0 голосов
/ 22 сентября 2019

Это ваш запрос:

select w.vintage, w.wine_no, w.wname, w.pctalc, w.grade,
       w.price, w.vid, v.vname, w.cid, c.cname
from wine w join
     vineyard v
     on v.vid = w.vid join
     class c
     on c.cid = w.cid
where w.cid = 'SHIRAZ' and
      w.grade = 'A';

Все join s являются внутренними объединениями, вся фильтрация находится на одной таблице, а условия являются условиями равенства.Следовательно, эта таблица должна быть первой доступной.Затем вы хотите join s для условий фильтрации и соответствующие join ключи других других таблиц:

  • wine(cid, grade, vid) (первые две клавиши могут быть в любом порядке).

Ключи join других таблиц vineyard(vid) и class(cid) уже проиндексированы, поскольку они объявлены как первичные ключи.Следовательно, приведенный выше единственный дополнительный индекс, который вам нужен.

...