Как оптимизировать этот оператор SQL, который выполняется около 4 секунд в ORACLE? Я хочу запрашивать и использовать меньше времени - PullRequest
0 голосов
/ 08 мая 2020

Следующий sql в моем проекте работает около 4 секунд. TB_Order выполняет полное сканирование таблицы. В поле состояния TB_Order есть индекс. Объем данных таблицы составляет 20 миллионов, а объем данных E и P меньше 50. Это SQL можно оптимизировать. И я использую UNION ALL, это это верно? У вас есть лучше sql?

--The first version
SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE (T.STATE = 'E' OR (T.STATE = 'P' AND SYSDATE > T.EFFECTIVE_DATE))
AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
AND ROWNUM <= :1

--The second version
SELECT * FROM (
SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE (T.STATE = 'E')
AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
UINON ALL 
SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE (T.STATE = 'P' AND SYSDATE > T.EFFECTIVE_DATE)
AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
)
where ROWNUM <= :1

Ответы [ 2 ]

2 голосов
/ 08 мая 2020

Не лучший подход, исключено OR и принудительное сканирование INDEX. Попробуйте объяснить план без HINT, чтобы увидеть, используется ли индекс для TB_ORDER.STATE. Добавляйте подсказку, только если индекс не используется. Также рекомендуется запускать статистику по таблице TB_ORDER.

SELECT * FROM
(SELECT /*+ INDEX(T STATE_NDX) */ T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE T.STATE = 'E'                        
AND DECODE(T.PRIORITY,null,0,T.PRIORITY) <= 100
AND ROWNUM <= :1
UNION ALL
SELECT /*+ INDEX(T STATE_NDX) */ T.ORDER_ID, T.PRIORITY, T.SUB_TASK
FROM TB_ORDER T
WHERE T.STATE = 'P' 
AND SYSDATE > T.EFFECTIVE_DATE
AND DECODE(T.PRIORITY,null,0,T.PRIORITY) <= 100
AND ROWNUM <= :1)
0 голосов
/ 10 мая 2020

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

  SELECT T.ORDER_ID, T.PRIORITY, T.SUB_TASK
   FROM TB_ORDER T
  WHERE T.STATE IN ('E', 'P')
  AND (CASE
     WHEN (T.STATE = 'P' AND SYSDATE > T.EFFECTIVE_DATE) THEN
      1
     WHEN T.STATE = 'E' THEN
      1
     ELSE
      0
   END) = 1
 AND (T.PRIORITY <= 100 OR T.PRIORITY IS NULL)
 AND ROWNUM <= :1
...