Объяснить стоимость плана против времени выполнения - PullRequest
4 голосов
/ 19 сентября 2008

Раньше я обнаружил, что «Стоимость» в плане выполнения является хорошим индикатором относительного времени выполнения. Почему этот случай отличается? Я дурак, думая, что план выполнения имеет отношение? Что конкретно я могу попытаться улучшить производительность 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 - несколько секунд.


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

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

Ответы [ 6 ]

4 голосов
/ 19 сентября 2008

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

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

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

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

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

Если вы не можете избавиться от «x is null или x = y», тогда y = nvl (x, «не существует») может иметь лучшие характеристики (при условии, что «не существует» является значение "не может произойти").

3 голосов
/ 19 сентября 2008

Как указано в в документации Oracle , стоимость - это расчетная стоимость относительно конкретного плана выполнения. При настройке запроса конкретный план выполнения, для которого рассчитываются затраты, может измениться. Иногда резко.

Проблема с производительностью 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 голосов
/ 18 ноября 2011

Чтобы немного рассказать о стоимости.

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

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

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

0 голосов
/ 19 сентября 2008

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

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

0 голосов
/ 19 сентября 2008

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

0 голосов
/ 19 сентября 2008

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

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

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

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