2015-10-28 2 views
0

У меня есть этот запрос, который выполняется 100 000 секунд. В настоящее время он работает довольно быстро. Мне просто интересно, есть ли лучший способ запустить его еще быстрее.Оптимизация запросов PL/SQL

CODES TABLE = 160KB 

INDEXES: INSTANCE(UNIQUE) SHORT)DESC 

CODE_VALUES=10MB 

INDEXES: INSTANCE(UNIQUE), INTFC_INST, CODE_INST,SHORT_DESC 

INTERFACES=160KB 

INDEXES: INSTANCE (UNIQUE), SHORT_DESC 
id="0" operation="SELECT STATEMENT" optimizer="ALL_ROWS" search_columns="0" cost="7"> 
    id="1" operation="NESTED LOOPS" search_columns="0" cost="7" cardinality="1" bytes="102" cpu_cost="54,820" io_cost="7" qblock_name="SEL$1" time="1"> 
     id="2" operation="MERGE JOIN" option="CARTESIAN" search_columns="0" cost="3" cardinality="1" bytes="33" cpu_cost="23,764" io_cost="3" time="1"> 
      object_ID="0" id="3" operation="TABLE ACCESS" option="BY INDEX ROWID" object_name="CODES" object_type="TABLE" search_columns="0" cost="2" cardinality="1" bytes="19" cpu_cost="15,443" io_cost="2" qblock_name="SEL$1" time="1"> 
       object_ID="1" id="4" operation="INDEX" option="RANGE SCAN" object_name="CODES_SHORT_DESC_FINDX" object_type="INDEX" search_columns="1" cost="1" cardinality="1" cpu_cost="8,171" io_cost="1" qblock_name="SEL$1" access_predicates=""A"."SYS_NC00010$"='MANAGER_GROUP'" time="1"/> 
      id="5" operation="BUFFER" option="SORT" search_columns="0" cost="1" cardinality="1" bytes="14" cpu_cost="8,321" io_cost="1" time="1"> 
       object_ID="2" id="6" operation="TABLE ACCESS" option="BY INDEX ROWID" object_name="INTERFACES" object_type="TABLE" search_columns="0" cost="1" cardinality="1" bytes="14" cpu_cost="8,321" io_cost="1" qblock_name="SEL$1" time="1"> 
        object_ID="3" id="7" operation="INDEX" option="RANGE SCAN" object_name="INTERFACES_SHORT_DESC_FINDX" object_type="INDEX" search_columns="1" cost="0" cardinality="1" cpu_cost="1,050" io_cost="0" qblock_name="SEL$1" access_predicates=""C"."SYS_NC00007> 
     object_ID="4" id="8" operation="TABLE ACCESS" option="BY INDEX ROWID" object_name="CODE_VALUES" object_type="TABLE" search_columns="0" cost="4" cardinality="1" bytes="69" cpu_cost="31,056" io_cost="4" qblock_name="SEL$1" filter_predicates="("A"."INSTANCE"="B"."CODE_INST" AND "B"."INTFC_INST"="C"."INSTANCE")" time="1"> 
      object_ID="5" id="9" operation="INDEX" option="RANGE SCAN" object_name="CODE_VALUES_FUN_IDX" object_type="INDEX" search_columns="1" cost="1" cardinality="4" cpu_cost="8,771" io_cost="1" qblock_name="SEL$1" access_predicates=""B"."SYS_NC00010$"='150'" time="1"/> 


SELECT A.INSTANCE, C.INSTANCE, B.LONG_DESC 
    FROM CODES A, 
    CODE_VALUES B, 
    INTERFACES C 
WHERE A.INSTANCE = B.CODE_INST 
    AND B.INTFC_INST = C.INSTANCE 
    AND TRIM (A.SHORT_DESC) = TRIM (var1) 
    AND TRIM (B.SHORT_DESC) = TRIM (var2) 
    AND TRIM (C.SHORT_DESC) = TRIM (var3) 
+0

Было бы неплохо увидеть план в формате таблицы, не могли бы вы сделать это? сейчас трудно прочитать план. –

+0

Лучший способ создать и предоставить общий доступ к проекту объяснения - запустить «объяснение плана для SELECT ...», а затем «выбрать» из таблицы (dbms_xplan.display); '. –

ответ

2

Избегайте TRIM функции в WHERE и JOIN положения ->TRIM (A.SHORT_DESC) = TRIM (var1)

Просто создание индексов на JOIN, ГДЕ и п GROUP столбцов не означает, что ваш запрос всегда будет возвращать ваши необходимые результаты быстро. Оптимизатор запросов, который выбирает правильный индекс для запроса, чтобы дать вам оптимальную производительность, но оптимизатор запросов может предложить только оптимальный план запроса, используя правильные индексы, КОГДА вы помогаете ему, написав хороший синтаксис запроса.

Использование любого типа функций (системных или определенных пользователем) в предложениях WHERE или JOIN может резко уменьшать производительность запроса, поскольку эта практика создает препятствия в работе оптимизатора запросов при правильном выборе индекса. Одним из распространенных примеров являются функции TRIM, которые обычно используются разработчиками в предложении WHERE.

USE AdventureWorks 
GO 
SELECT pr.ProductID,pr.Name,pr.ProductNumber,wo.* fROM Production.WorkOrder wo 
INNER JOIN Production.Product pr 
ON PR.ProductID = wo.ProductID 
WHERE LTRIM(RTRIM(pr.name)) = 'HL Mountain Handlebars' 
GO 
SELECT pr.ProductID,pr.Name,pr.ProductNumber,wo.* fROM Production.WorkOrder wo 
INNER JOIN Production.Product pr 
ON PR.ProductID = wo.ProductID 
WHERE pr.name = 'HL Mountain Handlebars' 

enter image description here

Хотя выходы обоих запросов одинаковы, но первый запрос занял почти 99% от общего времени выполнения. Это огромное различие заключается только в том, что эти триммерные функции, поэтому на производственных базах данных мы должны избегать этих TRIM и других функций как в предложениях JOIN, так и WHERE.

Взятые из AASIM ABDULLAH blog

Так что вы можете/должны сделать, это запустить обновление ваших данных, чтобы обрезать его раз и навсегда, и начать Triming его в то время как его добавления в таблицу, так что никаких новых данных будет когда-либо требуют обрезки. Или, если это по какой-то причине невозможно, найдите функциональные индексы, как это предложил Морис Ривз в комментариях.

+0

В качестве еще одного дополнительного, если ему абсолютно необходимо сделать «TRIM» на данных, он может сделать это в индексе Function-Based, но после этого ему нужно будет запустить статистику по таблице. Это не здорово, но это вариант. –

+2

Его также можно запустить обновление своих данных, чтобы обрезать его раз и навсегда и начать обрезать его при его добавлении в таблицу, поэтому никакие новые данные никогда не потребуют обрезки. –

+0

Согласен. Это лучший вариант. –

Смежные вопросы