SQL. Каково влияние производительности нескольких операторов CASE в SELECT - Teradata
Итак, у меня есть запрос, для которого требуется команда CASE-операторов в SELECT. Это был не оригинальный дизайн, а часть компромисса.
Таким образом, запрос выглядит примерно так:
SELECT
CONT.TABLE.FINC_ACCT_NM,
CONT.TABLE.FINC_ACCT_ID,
CONT.TABLE.CURR_END_OF_PERD_ACTL_VAL,
CONT.TABLE.PREV_END_OF_PERD_ACTL_VAL,
CONT.TABLE.VARNC_PLAN_VAL,
CONT.TABLE.OUTLOOK_BDGT_PLAN_VAL,
CONT.TABLE.PERD_END_RPT_DT,
CONT.TABLE.PLAN_VERS_NM,
CONT.TABLE.FRMT_ACTL_CD,
CONT.TABLE.FRMT_PLAN_CD,
CONT.TABLE.RPT_PERD_TYPE_CD,
CASE
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then ' Net Interest Income'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then ' Non Interest Income'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Non-Interest Expense'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then ' Total Marketing Expense'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then ' Total Operating Expense'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Pre-Provision Earnings (before tax)'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then ' Net Charge-offs'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then ' Other'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then ' Allowance Build (Release)'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Provision Expense'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Pretax Income'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Tax Expense'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'NIAT'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'EPS'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Ending Loans - HFI'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'avg' then 'Average Loans - HFI'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'avg' then 'Average Earning Assets'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Ending Deposits'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'avg' then 'Average Deposits'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'NIM on Loans'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Revenue Margin'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'AC579' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Charge off rate'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Efficiency ratio'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'ROA'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'ROE'
WHEN ( CONT.TABLE.FINC_ACCT_ID )= 'XXXX' and ( CONT.TABLE.BAL_TYPE_CD ) = 'EOP' then 'Return on Allocated Capital (ROAC)'
ELSE ( CONT.TABLE.FINC_ACCT_NM ) end
FROM
CONT.TABLE
WHERE
(
(
( ( CONT.TABLE.PERD_END_RPT_DT ) = (
SELECT Max(Perd_END_RPT_DT)
FROM CONT.TABLE
Where VERS_NM='Actual'
AND RPT_PERD_TYPE_CD = 'Q'
AND DATA_VLDTN_IND='Y'
)
AND RPT_PERD_TYPE_CD = 'Q'
AND DATA_VLDTN_IND='Y' )
OR
( ( CONT.TABLE.PERD_END_RPT_DT ) = (
SELECT Max(Perd_END_RPT_DT)
FROM CONT.TABLE
Where VERS_NM='Actual'
AND RPT_PERD_TYPE_CD = 'M'
AND DATA_VLDTN_IND='Y'
)
AND RPT_PERD_TYPE_CD = 'M'
AND DATA_VLDTN_IND='Y' )
)
AND
( ( CONT.TABLE.DATA_VLDTN_IND )='Y' )
AND
( ( CONT.TABLE.FINC_ACCT_ID )IN ('AC0006470','AC8000199','AC8002145','AC0006586','AC8000094') AND ( CONT.TABLE.DEPT_ID )='OR80637' )
)
Мой вопрос в том, какой эффект повлияет на изменение всех этих операторов CASE на прямые ссылки столбца на производительность.
Другими словами: Если я изменил каждый оператор CASE только на имя столбца и удалил все операторы CASE из запроса, будет иметь большое влияние на производительность и почему?
Я тестирую это, поэтому могу понять, влияет ли производительность, но я так же интересуюсь деталями ПОЧЕМУ? (Техническая информация о том, почему)
Спасибо за вашу помощь!
Ответы
Ответ 1
Операторы case будут намного меньше фактора, чем объединения в предложении WHERE.
Основным драйвером производительности в SQL является ввод-вывод - чтение данных с диска. Я думаю, что это на два порядка важнее, чем обработка в строках. Это всего лишь эвристика, не основанная на конкретных тестах в базе данных.
Вы выполняете самообучение, что потребует либо большой работы, читающей таблицу, либо большой объем работы, связанной с индексами.
С другой стороны, оператор case превращается в очень примитивные аппаратные команды - equals, gotos и т.п. Данные хранятся в памяти, ближайшей к процессорам, поэтому она будет застегиваться. Вы ничего не делаете в аргументе case (например, подобный или подзапрос). Я бы предположил, что запрос будет таким же быстрым, если вы удалите большую часть строк в инструкции.
Если у вас возникли проблемы с производительностью, введите индекс (VERS_NM, RPT_PERD_TYPE_CD, DATA_VLDTN_IND, Perd_END_RPT_DT). Этот четырехчастный индекс должен позволить вам получить максимальную дату без вызова запросов ввода-вывода в исходной таблице.
Ответ 2
Изменить: На самом деле вы можете перегруппировать оба этих подзапроса в JOIN
, который, вероятно, будет быстрее, в любом случае. Он также избавляется от большого количества повторений!
Речь идет не о производительности запроса (у @Gordon это было довольно хорошо), но этот огромный случайный пример просто кажется кошмаром для обслуживания. Возможно, лучший способ справиться с этим - преобразовать его в таблицу
CREATE TABLE ACCT_DISPLAY_NAME (
FINC_ACCT_ID CHAR(10),
BAL_TYPE_CD CHAR(3),
DISPLAY_NAME VARCHAR(100)
);
CREATE INDEX ACCT_DISPLAY_INDEX ON ACCT_DISPLAY_NAME (
FINC_ACCT_ID,
BAL_TYPE_CD
);
INSERT INTO ACCT_DISPLAY_NAME VALUES
('AC99800' , 'EOP', ' Net Interest Income' ),
('AC12993' , 'EOP', ' Non Interest Income' ),
('AC667999' , 'EOP', 'Non-Interest Expense' ),
('AC996587' , 'EOP', ' Total Marketing Expense' ),
('AC659986' , 'EOP', ' Total Operating Expense' ),
('AC69678' , 'EOP', 'Pre-Provision Earnings (before tax)' ),
('AC09994' , 'EOP', ' Net Charge-offs' ),
('AC20977' , 'EOP', ' Other' ),
('AC19979' , 'EOP', ' Allowance Build (Release)' ),
('AC7094' , 'EOP', 'Provision Expense' ),
('AC6997' , 'EOP', 'Pretax Income' ),
('AC0994' , 'EOP', 'Tax Expense' ),
('AC9999' , 'EOP', 'NIAT' ),
('AC7990' , 'EOP', 'EPS' ),
('AC9995' , 'EOP', 'Ending Loans - HFI' ),
('AC9995' , 'avg', 'Average Loans - HFI' ),
('AC2991' , 'avg', 'Average Earning Assets' ),
('AC2999' , 'EOP', 'Ending Deposits' ),
('AC9999' , 'avg', 'Average Deposits' ),
('AC0379' , 'EOP', 'NIM on Loans' ),
('AC6999' , 'EOP', 'Revenue Margin' ),
('AC579' , 'EOP', 'Charge off rate' ),
('AC5899' , 'EOP', 'Efficiency ratio' ),
('AC629' , 'EOP', 'ROA' ),
('AC359' , 'EOP', 'ROE' ),
('AC619' , 'EOP', 'Return on Allocated Capital (ROAC)' );
И сделайте a LEFT JOIN
на нем (так как у вас есть ELSE
в CASE
), что-то вроде:
SELECT T.FINC_ACCT_NM,
T.FINC_ACCT_ID,
T.CURR_END_OF_PERD_ACTL_VAL,
T.PREV_END_OF_PERD_ACTL_VAL,
T.VARNC_PLAN_VAL,
T.OUTLOOK_BDGT_PLAN_VAL,
T.PERD_END_RPT_DT,
T.PLAN_VERS_NM,
T.FRMT_ACTL_CD,
T.FRMT_PLAN_CD,
T.RPT_PERD_TYPE_CD,
COALESCE(N.DISPLAY_NAME, T.FINC_ACCT_NM)
FROM CONT.TABLE T
JOIN (
SELECT RPT_PERD_TYPE_CD, DATA_VLDTN_IND, Max(Perd_END_RPT_DT) AS PERD_END_RPT_DT
FROM CONT.TABLE
WHERE VERS_NM='Actual'
AND DATA_VLDTN_IND='Y'
GROUP BY RPT_PERD_TYPE_CD, DATA_VLDTN_IND
) AS MAX_DATES
ON T.RPT_PERD_TYPE_CD = MAX_DATES.RPT_PERD_TYPE_CD
AND T.DATA_VLDTN_IND = MAX_DATES.DATA_VLDTN_IND
AND T.PERD_END_RPT_DT = MAX_DATES.PERD_END_RPT_DT
LEFT JOIN ACCT_DISPLAY_NAME N
ON T.FINC_ACCT_ID = N.FINC_ACCT_ID
AND T.BAL_TYPE_CD = N.BAL_TYPE_CD
WHERE T.DEPT_ID = 'OR80637'
AND T.RPT_PERD_TYPE_CD IN ('Q', 'M')
AND T.FINC_ACCT_ID IN (
'AC0006470',
'AC8000199',
'AC8002145',
'AC0006586',
'AC8000094'
)