Объясните плановую стоимость и время выполнения

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


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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
21 319
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

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

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

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

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

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

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

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

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

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

DrFloyd5 01.07.2013 13:53

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

Ответ принят как подходящий

Как в документации 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)) или лучше.) Небольшая серия из быстрые запросы быстрые.

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

Вам даже не нужно настраивать запрос. Изменения индексов / ограничений, нагрузки на машину или других факторов, которые вы не контролируете, могут привести к изменению плана.

EvilTeach 15.04.2011 01:20

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

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

Расскажу немного о стоимости.

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

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

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

Другие вопросы по теме