powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Оптимизация start_of_group. Или вообще не start_of_group...
9 сообщений из 9, страница 1 из 1
Оптимизация start_of_group. Или вообще не start_of_group...
    #39709542
IAmAllan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Приветствую!

Есть таблица истории операций – дата, место, операция, надо вытащить оттуда с какой операции началась последняя серия по месту.

Сделал с помощью start_of_group:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
WITH tbl AS
  (SELECT TO_DATE ('27.09.2018', 'dd.mm.yyyy') op_date, 1 op_place, 10 oper FROM dual UNION ALL
   SELECT TO_DATE ('26.09.2018', 'dd.mm.yyyy'), 1, 20 FROM dual UNION ALL
   SELECT TO_DATE ('22.09.2018', 'dd.mm.yyyy'), 2, 30 FROM dual UNION ALL
   SELECT TO_DATE ('20.09.2018', 'dd.mm.yyyy'), 1, 40 FROM dual UNION ALL
   SELECT TO_DATE ('19.09.2018', 'dd.mm.yyyy'), 2, 50 FROM dual)
SELECT MIN (oper) KEEP (DENSE_RANK LAST ORDER BY op_date)
FROM (SELECT op_date, op_place, oper,
             DECODE (op_place, lag (op_place) OVER (ORDER BY op_date),0, 1) sog
      FROM tbl)
WHERE sog = 1 AND op_place = :pOP



Всё работает, для места 1 выдаёт 20, для 2 – 30, всё верно.

Проблема в том, что Tbl на самом деле содержит более 2 млрд записей, поиск идёт по некоей сущности, над которой делались операции, но это всё равно десятки тысяч. И внутренний select просматривает их все.
А надо-то всего-то самую последнюю по времени группу, а в ней самую первую по времени запись.
Может быть есть какой-то финт ушами?

План там такой:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                      | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                           |        |       |  7264 (100)|          |       |       |          |
|   1 |  SORT AGGREGATE                |                           |      1 |    51 |            |          |       |       |          |
|*  2 |   VIEW                         |                           |   7295 |   363K|  7264   (1)| 00:01:28 |       |       |          |
|   3 |    WINDOW BUFFER               |                           |   7295 |   199K|  7264   (1)| 00:01:28 |  1470K|   606K| 1306K (0)|
|   4 |     TABLE ACCESS BY INDEX ROWID| TBL                       |   7295 |   199K|  7262   (1)| 00:01:28 |       |       |          |
|*  5 |      INDEX RANGE SCAN          | AK_TBL                    |   7295 |       |    50   (0)| 00:00:01 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------



Я уж думаю, может PL/SQL лучше будет? У таблички есть индекс на ID и время, выбрать всё по ID order by op_date desc и в цикле найти начало группы. По идее, хоть на окно столько не отожрёт. Да и вызывается оно всё равно в пакете…

Код: plsql
1.
2.
3.
4.
5.
6.
7.
-----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                      | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                           |        |       |  7262 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID | TBL                       |   7295 |   199K|  7262   (1)| 00:01:28 |
|*  2 |   INDEX RANGE SCAN DESCENDING| AK_TBL                    |   7295 |       |    50   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------



Или вообще можно без start_of_group? Скажем, если не завязываться на op_place, а просто брать самую последнюю серию? Это не совсем то, но это можно будет снаружи поправить. Упёрся в start_of_group, уже не вижу других решений)
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39709566
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
При условии op_date меняется при переходе на новый op_place и есть индекс на op_lace,op_date а лучше на op_lace,op_date,oper:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
WITH tbl AS
  (SELECT TO_DATE ('27.09.2018', 'dd.mm.yyyy') op_date, 1 op_place, 10 oper FROM dual UNION ALL
   SELECT TO_DATE ('26.09.2018', 'dd.mm.yyyy'), 1, 20 FROM dual UNION ALL
   SELECT TO_DATE ('22.09.2018', 'dd.mm.yyyy'), 2, 30 FROM dual UNION ALL
   SELECT TO_DATE ('20.09.2018', 'dd.mm.yyyy'), 1, 40 FROM dual UNION ALL
   SELECT TO_DATE ('19.09.2018', 'dd.mm.yyyy'), 2, 50 FROM dual),
t1 as (
       select  max(op_date) pOP_max_op_date
         from  tbl
         where op_place = :pOP
      ),
t2 as (
       select  max(op_date) non_pOP_max_op_date
         from  tbl
         where tbl.op_date < (select pOP_max_op_date from t1)
           and op_place != :pOP
      )
select  min(oper) keep(dense_rank first order by op_date)
  from  tbl
  where op_date >= nvl((select non_pOP_max_op_date from t2),op_date)
    and op_date <= (select pOP_max_op_date from t1)
    and op_place = :pOP
/



SY.
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39709575
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
IAmAllanЯ уж думаю, может PL/SQL лучше будет? У таблички есть индекс на ID и время, выбрать всё по ID order by op_date desc и в цикле найти начало группы.да, конечно, так будет лучше, если группы действительно маленькие, а всего записей
IAmAllanдесятки тысяч
Только не надо for loop in (select ... ), т.к. он по 100 записей фетчить будет
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39709690
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
IAmAllanИли вообще можно без start_of_group?Я бы сказал здесь фишка не в SOG, а в чтении таблицы [по индексу] до наступления определенного условия.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
create table tbl(op_date, op_place, oper) as
select date '1900-01-01'+rownum,-rownum,0 from dual connect by rownum <= 43210
union all
SELECT TO_DATE ('27.09.2018', 'dd.mm.yyyy') op_date, 1 op_place, 10 oper FROM dual UNION ALL
SELECT TO_DATE ('26.09.2018', 'dd.mm.yyyy'), 1, 20 FROM dual UNION ALL
SELECT TO_DATE ('22.09.2018', 'dd.mm.yyyy'), 2, 30 FROM dual UNION ALL
SELECT TO_DATE ('20.09.2018', 'dd.mm.yyyy'), 1, 40 FROM dual UNION ALL
SELECT TO_DATE ('19.09.2018', 'dd.mm.yyyy'), 2, 50 FROM dual;

create unique index uk_tbl_op_date on tbl(op_date);
create index uk_tbl_op_place on tbl(op_place);



В общем случае как-то так (должен быть селективный индекс, содержащий op_place)
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
SQL> explain plan for
  2  with rec(op_date, op_place, oper) as
  3   (select tbl.op_date, tbl.op_place, tbl.oper
  4      from tbl
  5     where tbl.op_date = (select max(op_date) from tbl where op_place = :x)
  6    union all
  7    select t.op_date, t.op_place, t.oper
  8      from rec
  9     cross apply (select max(op_date) op_date
 10                   from tbl
 11                  where op_date < rec.op_date) t0
 12      join tbl t
 13        on t0.op_date = t.op_date
 14     where t.op_place = rec.op_place)
 15  cycle op_date set c to 1 default 0
 16  select * from rec;

Explained.

SQL> select * from dbms_xplan.display(format => 'basic');

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 2856472349

---------------------------------------------------------------------
| Id  | Operation                                 | Name            |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT                          |                 |
|   1 |  VIEW                                     |                 |
|   2 |   UNION ALL (RECURSIVE WITH) BREADTH FIRST|                 |
|   3 |    TABLE ACCESS BY INDEX ROWID            | TBL             |
|   4 |     INDEX UNIQUE SCAN                     | UK_TBL_OP_DATE  |
|   5 |      SORT AGGREGATE                       |                 |
|   6 |       TABLE ACCESS BY INDEX ROWID BATCHED | TBL             |
|   7 |        INDEX RANGE SCAN                   | UK_TBL_OP_PLACE |
|   8 |    NESTED LOOPS                           |                 |
|   9 |     NESTED LOOPS                          |                 |
|  10 |      RECURSIVE WITH PUMP                  |                 |
|  11 |      TABLE ACCESS BY INDEX ROWID BATCHED  | TBL             |
|  12 |       INDEX RANGE SCAN                    | UK_TBL_OP_PLACE |
|  13 |     VIEW                                  | VW_LAT_EC725798 |
|  14 |      SORT AGGREGATE                       |                 |
|  15 |       FIRST ROW                           |                 |
|  16 |        INDEX RANGE SCAN (MIN/MAX)         | UK_TBL_OP_DATE  |
---------------------------------------------------------------------

23 rows selected.



При некоторых особенностях можно без rec with как показал SY.

Решение с фетчем в PL/SQL самое простое и поддерживаемое.
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39710185
IAmAllan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо откликнувшимся!
По op_place индекса нет и не предвидится(
Сделал на PL/SQL, будем надеяться, оно не ляжет)
Отдельное спасибо за напоминание про for... select, голова уже вообще не варила.
Спасибо!
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39737834
IAmAllan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshop,

Я всё спросить хотел и стеснялся, про cross, apply, set etc помимо родной документации не посоветуете, что почитать?
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39737838
Вячеслав Любомудров
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Он, наверное, тоже стесняется
The Power of Oracle SQL
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39737861
IAmAllan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вячеслав Любомудров,

Ого! Спасибо!
И dbms_photoshop, конечно, спасибо)
...
Рейтинг: 0 / 0
Оптимизация start_of_group. Или вообще не start_of_group...
    #39738075
IAmAllan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Как мало я знаю, оказывается.
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Оптимизация start_of_group. Или вообще не start_of_group...
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]