powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Улучшить производительность WINDOW SORT
38 сообщений из 38, показаны все 2 страниц
Улучшить производительность WINDOW SORT
    #39259008
Фотография --Eugene--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Привет

Есть табличка
Код: plsql
1.
2.
3.
4.
create table t1 as
select trunc(level/10) a, dbms_random.value b,
(тут еще куча колонок)
from dual connect by level <= дохрена


И есть запросик
Код: plsql
1.
2.
3.
select *
from (select max(b) over (partition by a) max_b, t1.* from t1) x
where b = max_b


Подскажите, пожалуйста, как ускорить запрос? Например, чтобы как-то маркировать строки с максимальным значением b over partition by a..

Спасибо
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259026
Relict_35
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
посмотрите на
Код: plsql
1.
max(b) keep (dens_rank...
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259034
Фотография --Eugene--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Relict_35,

а как быть с "кучей колонок" в случае keep?
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259039
Relict_35
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
так же через KEEP
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259043
Фотография Egoр
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--Eugene--,

Код: plsql
1.
select * from t1 where (a,b) in (select a, max(b) from t1 group by a)
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259058
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--Eugene--,

"улучшить производительность WINDOW SORT" есть два способа:

1) пытаться превратить его в WINDOW BUFFER путем создания подходящего индекса.
в твоем случае, вероятно по (a, b), м.б. с учетом доп полей от прочих предикатов в условии запроса.

2) заменить его на aggregation/group by
запрос окажется зависимым от того, какой смысл ты вкладываешь в термин "улучшить производительность".
Например, если тебя интересует в первую очередь скорость выдачи первых строк и есть "подходящий индекс" по (a, b)
в наличии, то попробуй вариант.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
select t1.b as max_b, t1.*
from t1
Where 
  t1.b = (
     Select Max(b)
     From t1 t2
     Where t2.a = t1.a
)
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259088
Фотография --Eugene--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

допустим, есть индекс
Код: plsql
1.
create index t1_i1 on t1(a, b)

но в Вашем запросе он всеравно не задействуется (судя по плану)
Код: plaintext
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.
SANDBOX@EE>;create index t1_i1 on t1(a, b);

Index created.

explain plan for
  2  select t1.b as max_b, t1.*
  3  from t1
  4  Where
  5    t1.b = (
  6       Select Max(b)
  7       From t1 t2
  8       Where t2.a = t1.a
  9  );

Explained.

Elapsed: 00:00:00.16
SANDBOX@EE>;select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 2573525648

----------------------------------------------------------------------------------------
| Id  | Operation            | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |         |     1 |    65 |       |  8006   (2)| 00:01:37 |
|*  1 |  HASH JOIN           |         |     1 |    65 |    45M|  8006   (2)| 00:01:37 |
|   2 |   VIEW               | VW_SQ_1 |  1259K|    31M|       |  1376   (8)| 00:00:17 |
|   3 |    HASH GROUP BY     |         |  1259K|    31M|       |  1376   (8)| 00:00:17 |
|   4 |     TABLE ACCESS FULL| T1      |  1259K|    31M|       |  1294   (2)| 00:00:16 |
|   5 |   TABLE ACCESS FULL  | T1      |  1259K|    46M|       |  1296   (2)| 00:00:16 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."B"="MAX(B)" AND "ITEM_1"="T1"."A")

Note
-----
   - dynamic sampling used for this statement (level=2)

21 rows selected.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259100
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--Eugene--,

этот план соответствует запросу, который показал Egoр
т.е. - произошел unnest.
Прибейте его.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259114
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby--Eugene--,

этот план соответствует запросу, который показал Egoр
т.е. - произошел unnest.
Прибейте его.
По дороге поправьте Max(b) на Max(t2.b)

кроме того, проверьте вариант
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
select t1.b as max_b, t1.*
from t1
Where 
  Exists(
     Select null
     From t1 t2
     Where t2.a = t1.a
     Group By t2.a 
     Having Max(t2.b) = t1.b
)
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259128
Фотография --Eugene--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

да, работает быстро (для первых строк)
но почему в плане такая заоблачная стоимость? - это она для полного фетча чтоли?
Код: plaintext
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.
SANDBOX@EE>;explain plan for
  2  select /*+ first_rows(100) */ t1.b as max_b, t1.*
  3  from t1
  4  Where
  5    Exists(
  6       Select null
  7       From t1 t2
  8       Where t2.a = t1.a
  9       Group By t2.a
 10       Having Max(t2.b) = t1.b
 11  );

Explained.

Elapsed: 00:00:00.01
SANDBOX@EE>;select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3006482294

--------------------------------------------------------------------------------
| Id  | Operation              | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |       |     1 |    29 |  2995K  (1)| 09:59:08 |
|*  1 |  FILTER                |       |       |       |            |          |
|   2 |   TABLE ACCESS FULL    | T1    |   999K|    27M|  1305   (2)| 00:00:16 |
|*  3 |   FILTER               |       |       |       |            |          |
|   4 |    SORT GROUP BY NOSORT|       |     1 |    26 |     3   (0)| 00:00:01 |
|*  5 |     INDEX RANGE SCAN   | T1_I1 |     5 |   130 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( EXISTS (SELECT 0 FROM "T1" "T2" WHERE "T2"."A"=:B1 GROUP
              BY "T2"."A" HAVING MAX("T2"."B")=:B2))
   3 - filter(MAX("T2"."B")=:B1)
   5 - access("T2"."A"=:B1)

20 rows selected.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259133
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--Eugene--,

ну да. годится это или нет - зависит того, что на самом деле вас интересует.
а для "полного фетча" без join толку не будет.
просто заставьте его бежать по индексу.


поскольку сейчас вы про вакуум спрашиваете, то, с некоторой вероятностью, за прокидыванием предикатов в тот join
в вашем настоящем запросе, может быть придется глазками следить.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259146
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
--Eugene--
Код: plsql
1.
trunc(level/10) a

то есть выбираете минимум 1/10 часть таблицы?
что показывает
Код: plsql
1.
select count(distinct a)/count(*) x from dual

?
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259159
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
boobyпытаться превратить его в WINDOW BUFFER путем создания подходящего индексаВ WINDOW BUFFER оно превратится путем создания неподходяшего индекса, с подходящим индексом можно добиться WINDOW NOSORT.

2 ТС
Учитывая 10 записей на группу, использование индекса может быть не особо выгодным, так что смотри в сторону keep как было сказано.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259185
Фотография --Eugene--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender,

Код: plaintext
1.
2.
3.
SANDBOX@EE>;select count(distinct a)/count(1) from t1;
COUNT(DISTINCTA)/COUNT(1)
-------------------------
                 .1000001
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259201
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
--Eugene--,

а размеры сегментов таблицы и индекса на (a,b) какие? Параллелить можно?
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259205
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
--Eugene--,

ну и clustering_factor индекса тоже покажи. впрочем, лучше все статистики покажи
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259236
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopboobyпытаться превратить его в WINDOW BUFFER путем создания подходящего индексаВ WINDOW BUFFER оно превратится путем создания неподходяшего индекса, с подходящим индексом можно добиться WINDOW NOSORT.

это вполне пожалуйста.

dbms_photoshop2 ТС
Учитывая 10 записей на группу, использование индекса может быть не особо выгодным, так что смотри в сторону keep как было сказано.
ппц...
надували бы свой хадуп тщательнЕе.
глядишь, веселее получится.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259244
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

Это случайно не твой клон 10971123 ? :)
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259265
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopbooby,

Это случайно не твой клон 10971123 ? :)

вот чем пытаться кидаться скрытыми обвинениями в хамстве, лучше расскажите:
вы что, правда верите, что в реальной таблице все a рядком друг к другу и по порядку окажутся, прямо как здесь написано:
Код: plsql
1.
2.
3.
4.
create table t1 as
select trunc(level/10) a, dbms_random.value b,
(тут еще куча колонок)
from dual connect by level <= дохрена


?
Как и в то, что пара (a, b) окажется "почти уникальной"?
Имхо, это не из той истории нам картинки пытаются нарисовать.
(А для случая уникальной пары (a, b) так и запросы иначе пишутся.
И keep там как раз вполне годным имеет право быть)

Ладно, возьмем за базу 10 записей на группу.
На сколько-нибудь близком к правдоподобному распределении данных,
вы на какой LIO рассчитываете в среднем на возвращенную строку, предлагая "глядеть" на keep? Блоков 10 на запись? Или поболее?

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

Как-то так про клонов.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259268
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

Основных подхода два - WINDOW NOSORT + INDEX FULL SCAN vs SORT GROUP BY + TABLE ACCESS FULL.
В любом случае целиком сканируется либо сегмент индекса либо сегмент таблицы.
Сегмент индекса чуть больше, но при его сканировании можно избежать сортировки (кроме того больше вероятность что он будет в кеше).
На сортировке в этом примере особо не выиграешь независимо от кол-ва b в рамках a.
Так что скорее всего полное сканирование таблицы с группировкой наиболее предпочтительный варинат (можно еще добавить параллельность).
При других особенностях данных могла бы быть быстрее аналитика. Особенно если есть толстое поле, которое не нужно в результате и в индексе.
Если заранее известны какие-то особенности данных, например, множество значений a, то можно было бы мудрить другие варианты.
Иначе все измышлизмы относительно self join (semi join) мимо кассы.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
drop table xt;

create table xt(a, b not null,x1,x2,x3) as
select trunc(level/1e5) a, dbms_random.value b,
rownum x1, rownum x2, rownum x3
from dual connect by level <= 2e6-1;

create index xt_i on xt(a,b desc,x1,x2,x3);

select *
  from (select xt.*, rank() over(partition by a order by b desc) rn
          from xt)
 where rn = 1;

select a,
       max(b) b,
       max(x1) keep(dense_rank first order by b desc) x1,
       max(x2) keep(dense_rank first order by b desc) x2,
       max(x3) keep(dense_rank first order by b desc) x3
  from xt
 group by a;

...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259270
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopИначе все измышлизмы относительно self join (semi join) мимо кассы.Хотя при индексе по двум полям a, b может дать некоторый профит, да.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259271
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Только джойн все равно должен быть по rowid.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259294
Фотография Egoр
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--Eugene--,

Ну, раз пошла такая пьянка, то оптимизация вашей задачи детально разбирается у Кайта Best performance of Top N by X .
Там есть и про нахождение всех уникальных t1.а и про нахождение top N t1.b по каждому t1.a. В вашем случае top N - это top 1.
Сам этим пользуюсь, т.к. совершенно незаменимая операция при анализе динамики.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259361
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshop,

create index xt_i on xt(a,b... шурум-брум);

вот-вот.
такой шурум-бурум как форму борьбы с вредоносным lio встретить-то можно.
но вы же советуете keep с серьезной формой лица, без оговорок и не зная какого размера покрывающий индекс потребуется в конкретном случае.
вы уш как-нибудь поосторожнее с советами.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39259917
Nikolay Savvinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--Eugene--,

Та задача, которую вы пытаетесь решить, встречается весьма часто, и правильного решения в рамках СУБД Oracle, к сожалению, не имеет.

Как правило она связана с моделями данных, имеющих временной разрез (т.н. темпоральными данными), когда описывается состояние объекта во времени (и часто встречаются уникальные/первичные ключи типа (ID, TSTAMP) или (ID, VERSION). Для таких моделей очень популярен вид запросов "дай мне состояние данных на такой-то момент" или "покажи мне последний срез данных", которые реализуются как раз через подобного рода аналитические функции.

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

Все известные мне решения (а я копал на эту тему достаточно давно и долго, и даже как-то Тома Кайта доставал на какой-то конференции этим вопросом) достаточно кривые, но для каких-то конкретных случаев работают workaroundы, например:

1) поддерживать избыточную таблицу с последним срезом данных (b = max_b в вашем примере)
2) добавить флажок, который идентифицирует эти данные, и добавить логику, которая обновляла бы его значения при DML в триггер на вставку.

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

По идее, существуют темпоральные (и даже битемпоральные) СУБД в которых такие запросы должны и кодироваться легко, и выполняться влет. Oracle к их числу, к сожалению, не относится. В 12й версии был сделан некий шаг в этом направлении (см. например "temporal validity"), но это по сути только компактный синтаксис, внутри все осталось примерно то же самое поэтому с производительностью все плохо.

С уважением,
Николай
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260009
ora601
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nikolay SavvinovВсе известные мне решения (а я копал на эту тему достаточно давно и долго, и даже как-то Тома Кайта доставал на какой-то конференции этим вопросом) достаточно кривые, но для каких-то конкретных случаев работают ...


Как раз таки решение через index lookup, о котором говориться выше отлично справляется. booby был прав с подходом, но промазал с запросом, результата его запроса я не дождался (что и логично, ведь там еще присутствует ненужный group by, да и гарантии доступа по индексу нет).

На данных и индексах photoshop'a :


Код: 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.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
SQL> drop table xt;

Table dropped.

Elapsed: 00:00:00.03
SQL>
SQL> create table xt(a, b not null,x1,x2,x3) as
  2  select trunc(level/1e5) a, dbms_random.value b,
  3  rownum x1, rownum x2, rownum x3
  4  from dual connect by level <= 2e6-1;

Table created.

Elapsed: 00:00:15.45
SQL>
SQL> create index xt_i on xt(a,b desc,x1,x2,x3);

Index created.

Elapsed: 00:00:11.32
SQL>
SQL> select *
  2    from (select xt.*, rank() over(partition by a order by b desc) rn
  3            from xt)
  4   where rn = 1;

20 rows selected.

Elapsed: 00:00:04.45

Execution Plan
----------------------------------------------------------
Plan hash value: 3812567171

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1576K|   117M| 14846   (1)| 00:02:59 |
|*  1 |  VIEW             |      |  1576K|   117M| 14846   (1)| 00:02:59 |
|*  2 |   WINDOW NOSORT   |      |  1576K|    97M| 14846   (1)| 00:02:59 |
|   3 |    INDEX FULL SCAN| XT_I |  1576K|    97M| 14846   (1)| 00:02:59 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RN"=1)
   2 - filter(RANK() OVER ( PARTITION BY "A" ORDER BY
              SYS_OP_DESCEND("B"))<=1)

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      14633  consistent gets
          0  physical reads
          0  redo size
       1758  bytes sent via SQL*Net to client
        430  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         20  rows processed

SQL> select a,
  2         max(b) b,
  3         max(x1) keep(dense_rank first order by b desc) x1,
  4         max(x2) keep(dense_rank first order by b desc) x2,
  5         max(x3) keep(dense_rank first order by b desc) x3
  6    from xt
  7   group by a;

20 rows selected.

Elapsed: 00:00:02.57

Execution Plan
----------------------------------------------------------
Plan hash value: 3894939874

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  1576K|    97M|  3538   (3)| 00:00:43 |
|   1 |  SORT GROUP BY     |      |  1576K|    97M|  3538   (3)| 00:00:43 |
|   2 |   TABLE ACCESS FULL| XT   |  1576K|    97M|  3470   (1)| 00:00:42 |
---------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      12577  consistent gets
      12573  physical reads
          0  redo size
       1683  bytes sent via SQL*Net to client
        430  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         20  rows processed

SQL> with t_unique(a) as
  2   (select min(t1.a) a from xt t1
  3    union all
  4    select (select min(t1.a) a from xt t1 where t1.a > t.a) from t_unique t w
here a is not null),
  5  xt_with_max_rowids AS
  6   (SELECT t1.a,
  7           (select t2.column_value rid
  8              FROM TABLE(cast(multiset (select t2.rowid rid
  9                                 from xt t2
 10                                where t1.a = t2.a
 11                                  and rownum = 1
 12                                order by t2.b desc) as sys.odcivarchar2list)
 13                         ) t2) rid_max
 14      from t_unique t1)
 15  SELECT * FROM xt t1 WHERE rowid IN (SELECT rid_max FROM xt_with_max_rowids)
;

20 rows selected.

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 723862557

--------------------------------------------------------------------------------

-------------------------

| Id  | Operation                                    | Name     | Rows  | Bytes
| Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

-------------------------

|   0 | SELECT STATEMENT                             |          | 31533 |    62M

|     9  (12)| 00:00:01 |

|   1 |  NESTED LOOPS                                |          | 31533 |    62M

|     9  (12)| 00:00:01 |

|   2 |   COLLECTION ITERATOR SUBQUERY FETCH         |          |     1 |     2
|     2   (0)| 00:00:01 |

|*  3 |    COUNT STOPKEY                             |          |       |
|            |          |

|*  4 |     INDEX RANGE SCAN                         | XT_I     | 15767 |   585K

|    62   (0)| 00:00:01 |

|   5 |   VIEW                                       | VW_NSO_1 |     2 |  4004
|     7  (15)| 00:00:01 |

|   6 |    HASH UNIQUE                               |          |     2 |    26
|     7  (15)| 00:00:01 |

|   7 |     VIEW                                     |          |     2 |    26
|     6   (0)| 00:00:01 |

|   8 |      UNION ALL (RECURSIVE WITH) BREADTH FIRST|          |       |
|            |          |

|   9 |       SORT AGGREGATE                         |          |     1 |    13
|            |          |

|  10 |        INDEX FULL SCAN (MIN/MAX)             | XT_I     |     1 |    13
|     3   (0)| 00:00:01 |

|  11 |       SORT AGGREGATE                         |          |     1 |    13
|            |          |

|  12 |        FIRST ROW                             |          |     1 |    13
|     3   (0)| 00:00:01 |

|* 13 |         INDEX RANGE SCAN (MIN/MAX)           | XT_I     |     1 |    13
|     3   (0)| 00:00:01 |

|* 14 |       RECURSIVE WITH PUMP                    |          |       |
|            |          |

|* 15 |   TABLE ACCESS BY USER ROWID                 | XT       | 15767 |  1185K

|     1   (0)| 00:00:01 |

--------------------------------------------------------------------------------

-------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter(ROWNUM=1)
   4 - access("T2"."A"=:B1)
  13 - access("T1"."A">:B1 AND "T1"."A" IS NOT NULL)
  14 - filter("A" IS NOT NULL)
  15 - access(CHARTOROWID("RID_MAX"))

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        125  consistent gets
          0  physical reads
          0  redo size
       1683  bytes sent via SQL*Net to client
        430  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         22  sorts (memory)
          0  sorts (disk)
         20  rows processed

SQL>



Вообщем - то 00:00:04.45 vs 00:00:02.57 vs 00:00:00.01 , Довольно очевидно.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260025
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Николай,

попробую такой комментарий на ваш пост:
По части терминологии сорта "темпоральный", "битемпоральный"
и "правильного решения в рамках СУБД Oracle, к сожалению, не имеет", мое скромное мнение здесь стоит так:
эта опера другими словами поется.
В данном конкретном случае, речь идет всего лишь об ошибке в нормализации данных, допущенной разработчиком.

в задачах на получение "срезов" в любом случае возникает join.
Соединение периода актуальности среза с собственно данными, относящимися к этому срезу.

Там, где он реализован через самосоединение вида
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
Select t2.* From 
    (Select идентификатор_среза as geniuse_id, Max(дата_актуальности) as desired_date
    From креативно_дефектная_таблица
    Where
      дата_актуальности <= :D
    Group by идентификатор_среза) t1, креативно_дефектная_таблица t2
Where 
    t2.идентификатор_среза = t1.geniuse_id
And t2.дата_актуальности = t1.desired_date



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

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

Имхо, в 10 случаях из 10 это является следствием того, что никакого "первого" или "последнего" среза в первоначальном дизайне просто не было.
Понимание и потребность в истории срезов пришла потом - по мере развития системы.
И выбран конкретный вариант как наименее затратный в смысле количества штук изменений, вносимых а архитектуру системы для минимально работоспособной реализации.
Так технический дефект заливается бетоном, превращаясь архитектуру, на примере которой следующие поколения пионэров
обучаются истинно правоверному би-темпоральному проектированию, одновременно с усвоением знаний о том, чего не может Oracle.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260033
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ora601,

прошу прощения.
имхо ваши изыскания целиком нерелевантны обсуждаемому случаю.

здесь принципиально , что на пару (a,b) может быть возвращено произвольное количество строк, а вы исходите из предположения о том, что их не более одной.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260043
ora601
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
boobyora601,

прошу прощения.
имхо ваши изыскания целиком нерелевантны обсуждаемому случаю.

здесь принципиально , что на пару (a,b) может быть возвращено произвольное количество строк, а вы исходите из предположения о том, что их не более одной.

Нужно найти для каждой группы а , b с максимальным b. "Возвращено" (куда? ), "не более одной" (строк, пар, ? ) - какой то сплошной вакуум. Приведи пример, чтобы было более понятно о чем ты пишешь.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260081
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ora601,

TC спрашивал, как найти строки у которых b максимальный. Таких строк может быть вся таблица, а может быть ни одной, а в особо тяжком случае это еще и не вся таблица. :)
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260087
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nikolay SavvinovПо понятным причинам эти workaroundы не столько решают проблему, сколько перекладывают ее с этапа опрашивания данных в этап их сохранения или модификации.

По идее, существуют темпоральные (и даже битемпоральные) СУБД в которых такие запросы должны и кодироваться легко, и выполняться влет.
Простите Николай. Но первое утверждение так же справедливо. Либо раскладываешь так, чтоб было удобно искать и теряешь время на записи, либо теряешь время на чтении.

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

И хранение последнего варианта отдельно не такой уж и плохой вариант и тоже один из способов решения проблемы и вполне допустимый.
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260228
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Сергей Арсеньев,

Это SCD (slowly changing dimensions) тип 4
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260406
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtenderЭто SCD (slowly changing dimensions) тип 4
Ну да. Забавная, кстати, классификация.
Метод 4 (по сути методы 1+2), это не метод 3,
но метод 6 именно 6 потому, что 1+2+3. :)
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39260427
Nikolay Savvinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
booby,

Вы берете какой-то сильно оптимистический случай, когда у вас временное измерение представлено только в одной таблице. А если их несколько, а если вся схема такая?

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

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

Вот если вам с самого начала известны требования, как вы их реализуете? Как вы все эти таблицы будете индексировать? Как секционировать, с учетом того, что достаточно быстро счет пойдет на миллиарды строк и терабайты данных?

Эта задача гораздо сложнее, чем может показаться на первый взгляд.

С уважением,
Николай
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39328517
Фотография --Eugene--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Товарищи, кто-нибудь знает, есть ли разница между
Код: plaintext
max(a) keep (dense_rank first order by b)
и
Код: plaintext
max(a) keep (dense_rank last order by b desc)
?
(кроме NULLS FIRST/LAST - допустим, колонка b not null)
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39328610
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
--Eugene--,

Года два назад, разницы для not null не было
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39328617
Фотография --Eugene--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender,

не сочтите за дерзость, а откуда такая информация? (что "не было")
...
Рейтинг: 0 / 0
Улучшить производительность WINDOW SORT
    #39328619
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
--Eugene--,

Пропустил слово: года два назад тестировал...
...
Рейтинг: 0 / 0
38 сообщений из 38, показаны все 2 страниц
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Улучшить производительность WINDOW SORT
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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