@KTG

Какой вариант запроса из двух производительней?

CREATE TABLE TempForTest (
  id INT,
  Cus INT,
  Nm VARCHAR(10),
  Sm NUMBER,
  Tp Number
);

INSERT INTO TempForTest VALUES (1,  1, 'Ivan', 100, 0);
INSERT INTO TempForTest VALUES (2,  1, 'Ivan', 150, 0);
INSERT INTO TempForTest VALUES (3,  1, 'Ivan', 400, 1);
INSERT INTO TempForTest VALUES (4,  2, 'Petr', 100, 0);
INSERT INTO TempForTest VALUES (5,  2, 'Petr', 350, 0);
INSERT INTO TempForTest VALUES (6,  2, 'Petr', 5, 0);
INSERT INTO TempForTest VALUES (7,  2, 'Petr', 15, 1);
INSERT INTO TempForTest VALUES (8,  2, 'Petr', 35, 1);


В результате хочу получить вот что:
Cus Nm   Sm0 Sm1 Raz
  1 Ivan 250 400 -150
  2 Petr 455 50  405


Есть 2 варианта запроса:
Первый вариант.
SELECT Cus, Nm, SUM(TP0) AS Sm0, SUM(TP1) AS Sm1, SUM(TP0-TP1) AS Raz FROM (
   SELECT Cus, Nm, TP0, TP1 FROM (
      SELECT Cus, Nm,
         SUM(DECODE(Tp, 0, Sm, 0)) OVER (PARTITION BY Cus, Tp) AS TP0
        ,SUM(DECODE(Tp, 1, Sm, 0)) OVER (PARTITION BY Cus, Tp) AS TP1
      FROM TempForTest
      GROUP BY Cus, Nm, Tp, Sm )
   GROUP BY Cus, Nm, TP0, TP1)
GROUP BY Cus, Nm


Второй вариант:
WITH
   TP0 AS (
   SELECT Cus, Nm, SUM(Sm) AS SM
   FROM TempForTest
   WHERE Tp = 0
   GROUP BY Cus, Nm),
TP1 AS (
   SELECT Cus, Nm, SUM(Sm) AS SM
   FROM TempForTest
   WHERE Tp = 1
   GROUP BY Cus, Nm)
SELECT TP0.Cus, TP0.Nm, TP0.SM AS SM0, TP1.SM AS SM1, TP0.SM - TP1.SM AS RAZ
   FROM TP0
      JOIN TP1 ON TP1.Cus = TP0.Cus


В действительности таблица TempForTest собирается из 3-4 других через. JOINы и имеет более 5К записей.
На действующей базе работает 2 вариант. За исключением что вместо временных таблиц заданы курсоры. И сопоставление курсоров по Cus с TempForTest идет в Pl/SQL блоке.
При этом что таблицы с вычислениями, что основная таблица имеют пратически идентичные отборы по ряду других параметров, в том числе и через JOIN.

Первый вариант избавит от PL/SQL блока. Избавит от курсоров. Избавит от выдергиваний одних и тех же "пачек" таблиц с одинаковыми условиями запросов.
Но не уверен что держать в памяти результат запроса и проводить с ним вычисления заворачивая в селекты хорошая идея.

Так какой вариант лучше?
Забыл добавить, функция PIVOT не поддерживается
  • Вопрос задан
  • 71 просмотр
Пригласить эксперта
Ответы на вопрос 1
Vapaamies
@Vapaamies
Разработчик будущей ОС для ПК размером 250 МБ
В первом запросе среднюю группировку можно удалить, он станет еще проще. Мне он нравится больше. Не видя план, приходится строить предположения чисто из опыта.

Если в вашей версии Oracle не поддерживается pivot, то и with реализован не очень производительно, так что при возможности его нужно избегать. В своей прошлой практике я придерживался именно такого мнения. Но я смотрел планы. Вы смотрите планы? Что в них?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы