Как оптимизировать следующий оракул-запрос? - PullRequest
2 голосов
/ 23 декабря 2011

У меня есть 2 таблицы.Таблица "Accs" содержит 9 миллионов строк (3 столбца: acc_id, month, year).Сначала мне нужно извлечь записи, содержащие частичную запись номера счета, а затем в этих записях найти полное совпадение, если нет - то первое частичное совпадение

WITH t AS (
  SELECT a.acc_id,
         t1.as,
         t1.cust,
         t1.curr,
         t1.code,
         t1.depart,
         t1.sdate,
         t1.stype,
         t1.amount,
         t1.s_id
  FROM table1 t1 
  LEFT JOIN Accs a 
  ON SUBSTR(a.acc_id,7,12)=t1.curr||LPAD(t1.code,4,'0')||LPAD(t1.depart,3,'0')
  WHERE t1.sdate='20.11.2011' AND t1.stype='A' AND a.month=11 ANd a.year=2011)
SELECT MAX(t.s_id),
       (CASE WHEN t.as='000000' 
             THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
             ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END) acc_id
FROM t 
LEFT JOIN (SELECT t.acc_id FROM t) ac2 
ON SUBSTR(ac2.acc_id,1,6)='000'||LPAD(t.depart,3,'0')
GROUP BY      
       (CASE WHEN t.as='000000' 
             THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
             ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END)

Этот запрос занимает много времени,Правильно ли я делаю?

Ответы [ 2 ]

2 голосов
/ 23 декабря 2011

Первая попытка

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

Прежде всего, я изменил LEFT JOIN в with части на INNER JOIN. Поскольку вы используете значения a в предложении WHERE, он все равно будет функционировать как inner join, и обычно это происходит намного быстрее, особенно с таким количеством данных и правильными индексами.

Я изменил внутренний CASE на NVL, потому что это, по сути, то, что он делает. Не знаю, ускорит ли это все.

Перемещена конкатенация строк из внешнего запроса в часть with.

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

WITH t AS 
(
  SELECT 
    a.acc_id,
    t1.as,
    t1.cust,
    t1.curr,
    t1.code,
    t1.depart,
    t1.sdate,
    t1.stype,
    t1.amount,
    t1.s_id,
    t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield
  FROM 
    table1 t1 
    INNER JOIN Accs a
      ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
  WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A' AND a.month = 11 ANd a.year = 2011
)
SELECT
  MAX(t.s_id),
  (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id)
  ELSE
    t.groupfield
  END) acc_id
FROM 
  t 
  LEFT JOIN t ac2 on ac2 
    ON SUBSTR(ac2.acc_id, 1, 6) = '000' || LPAD(t.depart, 3, '0')
GROUP BY      
  (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id)
  ELSE
    t.groupfield
  END)

Вторая попытка

Посмотрев немного больше на ваш запрос, я задаюсь вопросом, не можете ли вы просто сделать его одним / простым запросом вместо использования with. Я думаю, что сначала присоединившись к Accs, а затем снова оставив присоединение к Accs с дополнительным условием, вы действительно хороший путь.

  SELECT 
    MAX(t1.s_id) AS s_id,
    CASE WHEN t.as = '000000' THEN
      NVL(a2.acc_id, a.acc_id)
    ELSE
      t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
    END AS acc_id
  FROM 
    table1 t1 
    INNER JOIN Accs a
      ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
      AND a.month = 11 AND a.year = 2011
    LEFT JOIN Accs a2
      ON SUBSTR(a2.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
      AND a2.month = 11 AND a2.year = 2011
      AND SUBSTR(a2.acc_id, 1, 6) = '000' || LPAD(t1.depart, 3, '0')
  WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A'
  GROUP BY 
    CASE WHEN t.as = '000000' THEN
      NVL(a2.acc_id, a.acc_id)
    ELSE
      t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield
    END AS acc_id
0 голосов
/ 23 декабря 2011

Вы можете попробовать создать индексы на основе функций, подобные этому:

create index xxx on accs (SUBSTR(a.acc_id,7,12));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...