#sql #oracle #query-performance
#sql #Oracle #запрос-производительность
Вопрос:
Я изучал, как использовать ВНУТРЕННЕЕ СОЕДИНЕНИЕ, поэтому я изменил следующий запрос, чтобы использовать внутреннее соединение, но у меня возникли проблемы с последним фрагментом запроса, можно ли использовать там внутреннее соединение? У меня возникли проблемы, потому что «MOV» — это запрос, выполненный перед этим фрагментом… Может кто-нибудь помочь мне понять, как его использовать? Следующие запросы работают, просто пытаясь улучшить их настолько, насколько я могу
фрагмент:
FROM TBLMOVOBLIGACIONES MOV1
WHERE MOV1.STRMOVANOMES = :periodo
AND MOV1.STRCLINIT = MOV.STRCLINIT
AND MOV1.STROBLOBLIGSARC = MOV.STROBLOBLIGSARC
Полный запрос:
SELECT * FROM (
SELECT MOV.NUMPROCODIGO APLICATIVO,
MOV.STRCLINIT NIT,
CL.STRCLINOMBRE CLIENTE,
MOV.STROBLOBLIGSARC OBLIGACION,
MOV.NUMMOVVLRCAPCREDITO MOV.NUMMOVVLRINTCREDI MOV.NUMMOVVLRCAPOTRO SALDO_OBL,
MOV.NUMMOVTIPOCREDITO TIPO_CREDITO,
MOV.NUMMOVNRODIASCAP DIAS_CAP,
MOV.NUMMOVNRODIASINT DIAS_INT,
MOV.STRMOVCALIFEDAD,
CASE
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=0 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 30 THEN 'A'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=31 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 90 THEN 'B'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=91 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 180 THEN 'C'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=181 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 360 THEN 'D'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=361 THEN 'E'
END AS CALIFEDAD_REAL
FROM TBLMOVOBLIGACIONES MOV INNER JOIN TBLCLIENTES CL ON MOV.STRCLINIT = CL.STRCLINIT
WHERE MOV.STRMOVANOMES = :periodo
AND MOV.NUMPROCODIGO NOT IN (24)
AND MOV.NUMMOVVLRCAPCREDITO MOV.NUMMOVVLRINTCREDI MOV.NUMMOVVLRCAPOTRO > 0
AND MOV.NUMMOVTIPOCREDITO = 1
AND NVL(MOV.STRMOVCALIFEDAD,'N') != (SELECT CASE
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=0 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 30 THEN 'A'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=31 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 90 THEN 'B'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=91 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 180 THEN 'C'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=181 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 360 THEN 'D'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=361 THEN 'E'
END AS CALIF_CALC
FROM TBLMOVOBLIGACIONES MOV1
WHERE MOV1.STRMOVANOMES = :periodo
AND MOV1.STRCLINIT = MOV.STRCLINIT
AND MOV1.STROBLOBLIGSARC = MOV.STROBLOBLIGSARC)
Комментарии:
1. Пожалуйста, задавайте только один вопрос за сообщение — это значительно упрощает ответ. Кроме того, не могли бы вы опубликовать DDL, образцы данных и ожидаемые результаты, в идеале с dbfiddle? Наконец, чего вы пытаетесь достичь — пытаетесь ли вы сделать код «лучше» или у вас проблемы с производительностью?
2. Какой запрос следует изучить? полностью запутался в вопросе.
3. Извините, я сократил вопрос только до основного запроса, который мне нужна помощь в улучшении, я пытаюсь повысить его производительность, а также улучшить обе вещи, но главное, как я могу использовать inner join для последнего фрагмента запроса
4. Преобразование последнего фрагмента для использования внутреннего соединения не имеет смысла (см. Ответ @MatthewMcPeak), и это, вероятно, не сильно улучшит производительность.
Ответ №1:
Я бы поставил под сомнение эту часть вашего запроса:
AND NVL(MOV.STRMOVCALIFEDAD,'N') != (SELECT CASE
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=0 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 30 THEN 'A'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=31 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 90 THEN 'B'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=91 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 180 THEN 'C'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=181 AND GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) <= 360 THEN 'D'
WHEN GREATEST(NVL(MOV1.NUMMOVNRODIASCAP,0), NVL(MOV1.NUMMOVNRODIASINT,0)) >=361 THEN 'E'
END AS CALIF_CALC
FROM TBLMOVOBLIGACIONES MOV1
WHERE MOV1.STRMOVANOMES = :periodo
AND MOV1.STRCLINIT = MOV.STRCLINIT
AND MOV1.STROBLOBLIGSARC = MOV.STROBLOBLIGSARC)
Либо (strmovanomes, strclinit, stroblobligsarc)
включает (или точно есть) первичный ключ tblmovobligaciones
, либо нет.
Если if делает, то подзапрос запрашивает ту же строку, tblmovobligaciones
что у вас уже есть. В этом случае подзапрос должен быть удален, а условие заменено на:
AND NVL(MOV.STRMOVCALIFEDAD,'N') != CASE
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=0 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 30 THEN 'A'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=31 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 90 THEN 'B'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=91 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 180 THEN 'C'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=181 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 360 THEN 'D'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=361 THEN 'E'
END
Если это не так, то что мешает этому подзапросу возвращать несколько строк (что может вызвать ошибку во время выполнения)?
Вы также можете выбрать это большое выражение один раз и повторно использовать его. Это вопрос предпочтений. Это будет выглядеть так:
SELECT MOV.NUMPROCODIGO APLICATIVO,
MOV.STRCLINIT NIT,
CL.STRCLINOMBRE CLIENTE,
MOV.STROBLOBLIGSARC OBLIGACION,
MOV.NUMMOVVLRCAPCREDITO MOV.NUMMOVVLRINTCREDI MOV.NUMMOVVLRCAPOTRO SALDO_OBL,
MOV.NUMMOVTIPOCREDITO TIPO_CREDITO,
MOV.NUMMOVNRODIASCAP DIAS_CAP,
MOV.NUMMOVNRODIASINT DIAS_INT,
MOV.STRMOVCALIFEDAD,
mov.califedad_real_expr CALIFEDAD_REAL
FROM ( SELECT mov.*,
CASE
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=0 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 30 THEN 'A'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=31 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 90 THEN 'B'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=91 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 180 THEN 'C'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=181 AND GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) <= 360 THEN 'D'
WHEN GREATEST(NVL(MOV.NUMMOVNRODIASCAP,0), NVL(MOV.NUMMOVNRODIASINT,0)) >=361 THEN 'E'
END AS califedad_real_expr
FROM TBLMOVOBLIGACIONES MOV) MOV
INNER JOIN TBLCLIENTES CL ON MOV.STRCLINIT = CL.STRCLINIT
WHERE MOV.STRMOVANOMES = :periodo
AND MOV.NUMPROCODIGO NOT IN (24)
AND MOV.NUMMOVVLRCAPCREDITO MOV.NUMMOVVLRINTCREDI MOV.NUMMOVVLRCAPOTRO > 0
AND MOV.NUMMOVTIPOCREDITO = 1
AND NVL(MOV.STRMOVCALIFEDAD,'N') != mov.califedad_real_expr
(Предполагая, что я прав в том, что подзапрос не нужен)