2008-09-19 3 views
4

Прежде, я нашел «Стоимость» в плане выполнения хорошим индикатором относительного времени выполнения. Почему этот случай отличается? Неужели я дурак, думая, что план исполнения имеет значение? Что конкретно я могу попытаться улучшить производительность v_test?Объясните стоимость плана и время выполнения

спасибо.

Использование Oracle 10g У меня есть простой вид запроса определен ниже

create or replace view v_test as 
    select distinct u.bo_id as bo_id, upper(trim(d.dept_id)) as dept_id 
    from 
     cust_bo_users u 
    join cust_bo_roles r on u.role_name=r.role_name 
    join cust_dept_roll_up_tbl d on 
          (r.region is null or trim(r.region)=trim(d.chrgback_reg)) and 
          (r.prod_id is null or trim(r.prod_id)=trim(d.prod_id)) and 
          (r.div_id is null or trim(r.div_id)=trim(d.div_id)) and 
          (r.clus_id is null or trim(r.clus_id)=trim(d.clus_id)) and 
          (r.prod_ln_id is null or trim(r.prod_ln_id)=trim(d.prod_ln_id)) and 
          (r.dept_id is null or trim(r.dept_id)=trim(d.dept_id)) 

определен заменить следующий вид

 create or replace view v_bo_secured_detail 
    select distinct Q.BO_ID, Q.DEPT_ID 
    from (select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'REGION' and 
       trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'RG_PROD' and 
       trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) and 
       trim(R.PROD_ID) = UPPER(trim(D.PROD_ID)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'PROD' and 
       trim(R.PROD_ID) = UPPER(trim(D.PROD_ID)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'DIV' and 
       trim(R.DIV_ID) = UPPER(trim(D.DIV_ID)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'RG_DIV' and 
       trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) and 
       trim(R.DIV_ID) = UPPER(trim(D.DIV_ID)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'CLUS' and 
       trim(R.CLUS_ID) = UPPER(trim(D.CLUS_ID)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'RG_CLUS' and 
       trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) and 
       trim(R.CLUS_ID) = UPPER(trim(D.CLUS_ID)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'PROD_LN' and 
       trim(R.PROD_LN_ID) = UPPER(trim(D.PROD_LN_ID)) 
     union all 
     select U.BO_ID BO_ID, UPPER(trim(R.DEPT_ID)) DEPT_ID 
     from CUST_BO_USERS U, CUST_BO_ROLES R 
     where U.ROLE_NAME = R.ROLE_NAME and 
       R.ROLE_LEVEL = 'DEPT') Q 

с целью устранения зависимости от колонки ROLE_LEVEL.

План выполнения v_test значительно ниже, чем v_bo_secured_detail для простого

select * from <view> where bo_id='value' 

запросов. И значительно ниже при использовании в реальном мире.

select CT_REPORT.RPT_KEY, 
     CT_REPORT_ENTRY.RPE_KEY, 
     CT_REPORT_ENTRY.CUSTOM16, 
     Exp_Sub_Type.value, 
     min(CT_REPORT_PAYMENT_CONF.PAY_DATE), 
     CT_REPORT.PAID_DATE 
    from CT_REPORT, 
     <VIEW> SD, 
     CT_REPORT_ENTRY, 
     CT_LIST_ITEM_LANG Exp_Sub_Type, 
     CT_REPORT_PAYMENT_CONF, 
     CT_STATUS_LANG Payment_Status 
    where (CT_REPORT_ENTRY.RPT_KEY = CT_REPORT.RPT_KEY) and 
     (Payment_Status.STAT_KEY = CT_REPORT.PAY_KEY) and 
     (Exp_Sub_Type.LI_KEY = CT_REPORT_ENTRY.CUSTOM9 and Exp_Sub_Type.LANG_CODE = 'en') and 
     (CT_REPORT.RPT_KEY = CT_REPORT_PAYMENT_CONF.RPT_KEY) and 
     (SD.BO_ID = 'JZHU9') and 
     (SD.DEPT_ID = UPPER(CT_REPORT_ENTRY.CUSTOM5)) and 
     (Payment_Status.name = 'Payment Confirmed' and (Payment_Status.LANG_CODE = 'en') and 
     CT_REPORT.PAID_DATE > to_date('01/01/2008', 'mm/dd/yyyy') and Exp_Sub_Type.value != 'Korea') 
    group by CT_REPORT.RPT_KEY, 
      CT_REPORT_ENTRY.RPE_KEY, 
      CT_REPORT_ENTRY.CUSTOM16, 
      Exp_Sub_Type.value, 
      CT_REPORT.PAID_DATE 

Время исполнения ДИЗАЙНО отличается. Вид v_test занимает 15 часов, а v_bo_secured_detail занимает несколько секунд.


Спасибо всем, кто откликнулся

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

ответ

3

В качестве the Oracle documentation says, расчетная стоимость зависит от конкретного плана выполнения. Когда вы настраиваете запрос, вычисляется конкретный план выполнения, стоимость которого может быть изменена. Иногда резко.

Проблема с производительностью v_test заключается в том, что Oracle не может думать о том, что он не сможет выполнить ее, кроме выполнения вложенного цикла, для каждого cust_bo_roles сканировать все cust_dept_roll_up_tbl, чтобы найти совпадение. Если таблица имеет размер n и m, это занимает n * m время, что медленно для больших таблиц. В отличие от этого v_bo_secured_detail настроен так, что это серия запросов, каждая из которых может быть выполнена через какой-то другой механизм. (Oracle имеет номер, который он может использовать, включая использование индекса, построение хэша «на лету» или сортировку наборов данных и их объединение. Эти операции - все O (n * log (n)) или лучше.) Небольшая серия быстрые запросы выполняются быстро.

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

+0

Вам даже не нужно настраивать запрос. Изменения в индексах/ограничениях, загрузке машины или других факторах, которые вы не контролируете, могут привести к изменению плана. – EvilTeach 2011-04-14 21:20:08

0

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

Много раз, когда вам нужен быстрый результат, подсказка оптимизатора USE_NL поможет.

Кроме того, в вашем тестовом представлении он полагается на IS NULL ... IS NULL не может использовать индекс и не может использовать такую ​​функцию, как обрезка по параметру «table-side».

4

План исполнения - это теория, время исполнения - это реальность.

В плане показано, как двигатель выполняет ваш запрос, но некоторые шаги могут привести к чрезмерному количеству работы для разрешения запроса. Использование «x равно null или x = y» плохо пахнет. Если r и d - большие таблицы, у вас может быть какой-то комбинаторный взрыв, поражающий вас, а запрос циклов бесконечно через большие списки блоков диска. Я предполагаю, что во время исполнения вы видите много ввода-вывода.

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

Также использование триммеров() и upper() повсеместно выглядит немного подозрительным.Если ваши данные настолько нечисты, иногда может потребоваться периодическая уборка, поэтому вы можете сказать «x = y» и знать, что это работает.

обновление: вы попросили советы по улучшению v_test. Очистите данные, чтобы не было необходимости обрезать() и верхнюю(). Они могут препятствовать использованию индексов (хотя это повлияет и на объединенную версию выбора).

Если вы не можете избавиться от "x равно null или x = y", то y = nvl (x, 'does-not-exist') может иметь лучшие характеристики (при условии, что 'does-not-exist' является значение «не может быть» id).

+0

+1 для плана исполнения - это теория, время исполнения - это реальность. – 2013-07-01 09:53:04

0

Вы собрали статистику оптимизатора на всех базовых таблицах? Без них оценки оптимизатора могут быть безупречно из-за обстановки с реальностью.

0

Когда вы говорите, что «план запроса ниже», вы имеете в виду, что он короче или что фактические сметы расходов ниже? Одна очевидная проблема с вашим замещающим представлением заключается в том, что соединение с cust_dept_roll_up_tbl использует почти исключительно невыполненные критерии (тесты «null» могут быть удовлетворены индексом, но те, которые связаны с настройкой вызова для каждого аргумента, не могут быть), поэтому планировщик должен выполнить хотя бы одно и, возможно, несколько последовательных сканирований таблицы, чтобы удовлетворить запрос.

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

0

Подробно о стоимости.

В Oracle 9/10g, что упрощает немного, стоимость определяется по формуле:

Стоимость = (SrCount * SrTime + MbrCount * MbrTime + CpuCyclesCount * CpuCycleTime)/SrTime

Где SrCount - счета общее количество одноблочных чтений, SrTime - среднее время одного блока, считанное в соответствии с собранной статистикой системы, MbrCount и MbrTime, то же, что и для многоблочного считывания соответственно (одни используют во время полного сканирования таблицы и быстрых полных сканирований), связанные с Cpu метрики -explanatory .. и все разделены на однократное чтение.

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