Оптимизация Oracle Query для огромной таблицы для отчета - PullRequest
0 голосов
/ 15 января 2019

Я пытаюсь получить вывод следующего запроса. Это берет навсегда и не выводит. Можете ли вы помочь в оптимизации запроса? Я попытался использовать подсказку параллельно, но все еще не выводится. У TabA около 1,2 миллиона записей, а у TabB 0,7 миллиона записей. База данных Oracle.

WITH TAB1 as (
SELECT
P_TXN_ID,PROD_CD,P_TYPE1,P_TYPE2,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='FBO' AND LAST_UPD_DT='20-NOV-17' ) FBO,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='ORG' AND LAST_UPD_DT='20-NOV-17' ) ORG,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='SEND' AND LAST_UPD_DT='20-NOV-17' )  SEND,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='RCV' AND LAST_UPD_DT='20-NOV-17' ) RCV,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='SCND' AND LAST_UPD_DT='20-NOV-17' ) SCND,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='BENE' AND LAST_UPD_DT='20-NOV-17' ) BENE,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='INT1' AND LAST_UPD_DT='20-NOV-17' ) INT1,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='INT2' AND LAST_UPD_DT='20-NOV-17' ) INT2,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='INT3' AND LAST_UPD_DT='20-NOV-17' ) INT3,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='INT4' AND LAST_UPD_DT='20-NOV-17' ) INT4,
(SELECT COALESCE(FT.V_PARTY_ID_TYPE,'XX') FROM TabA FT WHERE FT.P_TXN_ID=ST.P_TXN_ID AND FT.P_ROLE='INT5' AND LAST_UPD_DT='20-NOV-17' ) INT5
FROM 
(SELECT PROD_CD,P_TYPE1,P_TYPE2,LAST_UPD_DT,P_TXN_ID 
FROM TabB
) ST
WHERE LAST_UPD_DT>='20-NOV-17' AND LAST_UPD_DT<='22-NOV-17'  
)

SELECT /*+ parallel(100)*/
COUNT(*),
PROD_CD,
P_TYPE1,
FBO,ORG,SEND,RCV,SCND,BENE,
INT1,INT2,INT3,INT4,INT5
FROM 
TAB1 
GROUP BY PROD_CD,
P_TYPE1,
FBO,ORG,SEND,RCV,SCND,BENE,
INT1,INT2,INT3,INT4,INT5
ORDER BY PROD_CD;

Спасибо заранее. Чтобы упростить задачу, приведенный ниже пример пытается выполнить запрос. Скажем, есть таблица TXN со следующими данными:

TXN
Col1 Col2 Col3 Type
1    AA    abc  FBO
2    null  abc  FBO
3    BB    abc  ORG
4    CC    def  ORG
5    DD    def  ORG
6    EE    pqr  SCND
7    EE    pqr  SCND
8    CC    def  RCV

Тогда вывод запросов будет:

 Col2   Col3 FBO ORG SCND RCV
 AA     abc    1   0    0   0
 null   abc    1   0    0   0
 BB     abc    1   0    0   0
 CC     def    0   1    0   1
 DD     def    0   1    0   0
 EE     pqr    0   0    2   0

Ответы [ 4 ]

0 голосов
/ 16 января 2019

Чтобы получить пример данных для получения результата, вам просто нужны «условные агрегаты», в основном это означает, что для вашего запроса count(case when ... then 1 end):

SELECT
    col2
  , col3
  , COUNT( CASE WHEN type = 'FBO'  THEN 1 END ) AS FBO
  , COUNT( CASE WHEN type = 'ORG'  THEN 1 END ) AS ORG
  , COUNT( CASE WHEN type = 'SCND' THEN 1 END ) AS SCND
  , COUNT( CASE WHEN type = 'RCV'  THEN 1 END ) AS RCV
FROM txn
GROUP BY
    col2
  , col3
ORDER BY
    col2
  , col3

и результат:

+----+------+------+-----+-----+------+-----+
|    | COL2 | COL3 | FBO | ORG | SCND | RCV |
+----+------+------+-----+-----+------+-----+
|  1 | AA   | abc  |   1 |   0 |    0 |   0 |
|  2 | BB   | abc  |   0 |   1 |    0 |   0 |
|  3 | CC   | def  |   0 |   1 |    0 |   1 |
|  4 | DD   | def  |   0 |   1 |    0 |   0 |
|  5 | EE   | pqr  |   0 |   0 |    2 |   0 |
|  6 | NULL | abc  |   1 |   0 |    0 |   0 |
+----+------+------+-----+-----+------+-----+

так что вы можете сделать это:

SELECT
    b.PROD_CD
  , b.P_TYPE1
  , b.P_TYPE2
  , COUNT( CASE WHEN FT.P_ROLE = 'FBO'  THEN a.V_PARTY_ID_TYPE END ) AS FBO
  , COUNT( CASE WHEN FT.P_ROLE = 'ORG'  THEN a.V_PARTY_ID_TYPE END ) AS ORG
  , COUNT( CASE WHEN FT.P_ROLE = 'SEND' THEN a.V_PARTY_ID_TYPE END ) AS SEND
  , COUNT( CASE WHEN FT.P_ROLE = 'RCV'  THEN a.V_PARTY_ID_TYPE END ) AS RCV
  , COUNT( CASE WHEN FT.P_ROLE = 'SCND' THEN a.V_PARTY_ID_TYPE END ) AS SCND
  , COUNT( CASE WHEN FT.P_ROLE = 'BENE' THEN a.V_PARTY_ID_TYPE END ) AS BENE
  , COUNT( CASE WHEN FT.P_ROLE = 'FBO'  THEN a.V_PARTY_ID_TYPE END ) AS FBO
  , COUNT( CASE WHEN FT.P_ROLE = 'INT1' THEN a.V_PARTY_ID_TYPE END ) AS INT1
  , COUNT( CASE WHEN FT.P_ROLE = 'INT2' THEN a.V_PARTY_ID_TYPE END ) AS INT2
  , COUNT( CASE WHEN FT.P_ROLE = 'INT3' THEN a.V_PARTY_ID_TYPE END ) AS INT3
  , COUNT( CASE WHEN FT.P_ROLE = 'INT4' THEN a.V_PARTY_ID_TYPE END ) AS INT4
  , COUNT( CASE WHEN FT.P_ROLE = 'INT5' THEN a.V_PARTY_ID_TYPE END ) AS INT5
FROM TabB b
JOIN TabA a ON a.P_TXN_ID = b.P_TXN_ID
AND a.LAST_UPD_DT = DATE '2017-11-20'
WHERE LAST_UPD_DT >= DATE '2017-11-20' AND LAST_UPD_DT <= DATE '2017-11-22'
GROUP BY
    PROD_CD
  , P_TYPE1
  , P_TYPE2;

Но учтите, что ЕСЛИ a.V_PARTY_ID_TYPE равно NULL, то счетчик НЕ будет увеличиваться на 1.

0 голосов
/ 15 января 2019

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

Вот контрольный список:

1) Таблица TABA не индексируется - очевидно, что приводит к лоту FULL TABLE SCAN s

2) Таблица TABA неправильно проиндексирована - например, есть индекс для P_ROLE, LAST_UPD_DT, который не помогает, потому что P_TXN_ID отсутствует или

индексируется только столбец P_TXN_ID, и вам необходимо отсканировать большое число или строку, прежде чем сопоставлять роль и дату

3) Таблица TABA надлежащим образом проиндексирована, то есть для P_TXN_ID, P_ROLE, LAST_UPD_DT, но вы обрабатываете большое количество строк в TABB

Пример для обработки строки 100 КБ из TABB вам нужно 100 КБ * 11 = 1,1 МБ (количество подзапросов) index access. Для большой таблицы с индексом на диске вы получите не более 100 строк в секунду. Так вам будет намного лучше избавиться от него, выполнить хеш-соединение ваших таблиц.

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

0 голосов
/ 15 января 2019

Мне трудно следовать вашему коду и вашим объяснениям. Однако я уверен, что условное агрегирование - это все, что вам нужно.

Примерно так:

SELECT b.PROD_CD, b.P_TYPE1, b.P_TYPE2,
       MAX(CASE WHEN FT.P_ROLE = 'FBO' THEN a.V_PARTY_ID_TYPE END) as FBO,
       MAX(CASE WHEN FT.P_ROLE = 'ORG' THEN a.V_PARTY_ID_TYPE END) as ORG,
       MAX(CASE WHEN FT.P_ROLE = 'SEND' THEN a.V_PARTY_ID_TYPE END) as SEND,
       MAX(CASE WHEN FT.P_ROLE = 'RCV' THEN a.V_PARTY_ID_TYPE END) as RCV,
       MAX(CASE WHEN FT.P_ROLE = 'SCND' THEN a.V_PARTY_ID_TYPE END) as SCND,
       MAX(CASE WHEN FT.P_ROLE = 'BENE' THEN a.V_PARTY_ID_TYPE END) as BENE,
       MAX(CASE WHEN FT.P_ROLE = 'FBO' THEN a.V_PARTY_ID_TYPE END) as FBO,
       MAX(CASE WHEN FT.P_ROLE = 'INT1' THEN a.V_PARTY_ID_TYPE END) as INT1,
       MAX(CASE WHEN FT.P_ROLE = 'INT2' THEN a.V_PARTY_ID_TYPE END) as INT2,
       MAX(CASE WHEN FT.P_ROLE = 'INT3' THEN a.V_PARTY_ID_TYPE END) as INT3,
       MAX(CASE WHEN FT.P_ROLE = 'INT4' THEN a.V_PARTY_ID_TYPE END) as INT4
       MAX(CASE WHEN FT.P_ROLE = 'INT5' THEN a.V_PARTY_ID_TYPE END) as INT5
FROM TabB b JOIN
     TabA a
      ON a.P_TXN_ID = b.P_TXN_ID AND
         a.LAST_UPD_DT = DATE '2017-11-20'
WHERE LAST_UPD_DT >= DATE '2017-11-20' AND LAST_UPD_DT <= DATE '2017-11-22'
GROUP BY PROD_CD, P_TYPE1, P_TYPE2;
0 голосов
/ 15 января 2019
  1. Если tabB разделен с помощью LAST_UPD_DT или проиндексирован с помощью LAST_UPD_DT, просто убедитесь, что '20 -NOV-17' и '22 -NOV-17 'являются датами. Для этого используйте to_date: to_date ('22 -NOV-2017 ',' dd-mon-yyyy ') и т. Д. (Возможно, по идее индексировать этот столбец, но если вы действительно обновите записи, ваши обновления будут медленными.)
  2. не используйте параллель 100, но параллель 8 или 16. 100 слишком тяжелая, и это может нанести вред базе данных.
  3. Вам нужен заказ по PROD_CD? Зачем? Без него будет быстрее.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...