powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Выборка уникальных значений из хронологической таблицы
59 сообщений из 59, показаны все 3 страниц
Выборка уникальных значений из хронологической таблицы
    #33096075
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Иногда требуется сделать джойн по хитрому условию: для каждой записи ведущей таблицы выбрать только одну запись ведомой таблицы (обычно максимальную или минимальную) из всех, удовлетворяющих условиям соединения.

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

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

Обычные джойны с группировкой и сортировкой работают медленно, и тут нам на помощь приходит хитрость. Блюстители чистоты SQL меня, конечно, засмеют, ну да мне не привыкать :)

Итак, дано:

Таблица проводок:
Код: plaintext
CREATE TABLE transactions (xid NUMBER, xsum FLOAT, xdate DATE, xcurrency NUMBER)

Таблица курсов:
Код: plaintext
CREATE TABLE rates (rcurrency NUMBER, rdate DATE, rrate FLOAT)

Итак, для начала создадим уникальный индекс:

Код: plaintext
CREATE UNIQUE INDEX ux_rate_currency_date ON rates (rcurrency, rdate)

Как правило, этот индекс и должен быть уникальным: два курса одной валюты на одну дату — это плохо.

Пишем запрос:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT	(
	SELECT	/*+ INDEX_DESC (r ux_rate_currency_date) */
		rrate
	FROM	rates r
	WHERE	r.rcurrency = x.xcurrency
		AND r.rdate <= x.xdate
		AND rownum =  1 
	) AS eff_rate
FROM	transactions x

Если мы посмотрим на план, то увидим там

ACCESS PATH: INDEX RANGE SCAN DESCENDING

, а также условие:

COUNT STOPKEY

Что это значит?

Это значит, что для каждой строки из ведущей таблицы (таблицы проводок) Oracle будет находить первую удовлетворяющую его запись путём сканирования по индексу, а затем останавливаться по условию rowcount = 1 и выкидывать результат в итоговый запрос в качестве поля eff_rate .

То есть для каждой строки из таблицы transactions у нас будет дополнительное поле с эффективным курсом валюты проводки на её, проводки, дату — что от нас и требовалось.

Если не будет найдено ни одной записи, то eff_rate примет значение NULL .

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

К сожалению, Oracle версии 9i не позволяет передавать в FIELD SUBQUERY поля из внешнего запроса, если глубина вложения FIELD SUBQUERY больше 1. То есть такой, казалось бы, естественный запрос:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
SELECT	(
	SELECT	rrate
	FROM	(
		SELECT	rate
		FROM	rates r
		WHERE	r.rcurrency = x.xcurrency
			AND r.rdate <= x.xdate
		ORDER BY
			r.rdate DESC
		)
	WHERE	rownum =  1 
FROM	transactions x

приведёт к ошибке ORA-00904: недопустимый идентификатор .

Поэтому и приходится использовать хинты для явного прописывания логики запроса.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33096432
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Квасной
Код: plaintext
1.
2.
3.
4.
	SELECT	/*+ INDEX_DESC (r ux_rate_currency_date) */ 
        ...
	WHERE	...
		AND rownum =  1 
Это тысячи раз обсуждалось. И хотя существуют странные альтернативные мнения, но так делать категорически нельзя . Ибо порядок строк гарантирует ORDER BY и только ORDER BY.
Надёжней и понятней будет использовать функцию GetRate(x.xcurrency,x.xdate).
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33096508
Splain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В 9-ке

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SELECT	rrate
	FROM	(
		SELECT	rate
		FROM	rates r
		WHERE	r.rcurrency = x.xcurrency
			AND r.rdate <= x.xdate
		ORDER BY
			r.rdate DESC
		)
	WHERE	rownum =  1 


можно заменить на

Код: plaintext
1.
2.
3.
4.
SELECT MAX(rrate) KEEP (DENSE_RANK LAST ORDER BY r.rdate)
  FROM rates r
WHERE	r.rcurrency = x.xcurrency
      AND r.rdate <= x.xdate

производительность протестировать было негде
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33096846
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Elic Квасной
Код: plaintext
1.
2.
3.
4.
	SELECT	/*+ INDEX_DESC (r ux_rate_currency_date) */ 
        ...
	WHERE	...
		AND rownum =  1 
Это тысячи раз обсуждалось. И хотя существуют странные альтернативные мнения, но так делать категорически нельзя . Ибо порядок строк гарантирует ORDER BY и только ORDER BY.
Надёжней и понятней будет использовать функцию GetRate(x.xcurrency,x.xdate).

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

На тестовой базе в ведущей таблице около 2 000 000 строк, в ведомой — около 2 000. Мой запрос работает несколько секунд, а если использовать функцию, то время возрастает до десятков секунд — feel the difference :)

Что же до порядка строк — так он при корректном прописывании пути доступа по индексу тоже гарантирован.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33097079
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойНа тестовой базе в ведущей таблице около 2 000 000 строк, в ведомой — около 2 000. Мой запрос работает несколько секунд, а если использовать функцию, то время возрастает до десятков секунд — feel the difference :)И что, эти два лимона каждый раз обсчитываются?
КваснойЧто же до порядка строк — так он при корректном прописывании пути доступа по индексу тоже гарантирован. Не гарантирован
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33097737
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SplainВ 9-ке

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SELECT	rrate
	FROM	(
		SELECT	rate
		FROM	rates r
		WHERE	r.rcurrency = x.xcurrency
			AND r.rdate <= x.xdate
		ORDER BY
			r.rdate DESC
		)
	WHERE	rownum =  1 


можно заменить на

Код: plaintext
1.
2.
3.
4.
SELECT MAX(rrate) KEEP (DENSE_RANK LAST ORDER BY r.rdate)
  FROM rates r
WHERE	r.rcurrency = x.xcurrency
      AND r.rdate <= x.xdate

производительность протестировать было негде

К сожалению, в этом случае Oracle не использует INDEX RANGE SCAN DESCENDING с остановкой на первом значении.

Он делает INDEX RANGE SCAN по всем значениям, удовлетворяющим условию выборки, сортирует найденные строки по полю rdate ( SORT AGGREGATE ), и выбирает из них первую.

Производительность, соответственно, падает. Запрос работает несколько десятков секунд.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33097821
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Elic КваснойНа тестовой базе в ведущей таблице около 2 000 000 строк, в ведомой — около 2 000. Мой запрос работает несколько секунд, а если использовать функцию, то время возрастает до десятков секунд — feel the difference :)И что, эти два лимона каждый раз обсчитываются?

Ну, не каждый раз. Но даже с учётом фильтров лям строк нет-нет, да и получится.

КваснойЧто же до порядка строк — так он при корректном прописывании пути доступа по индексу тоже гарантирован. Не гарантирован

То, что наличие ORDER BY лучше, чем его отсутствие, объяснять никому не надо. Быть молодым, богатым, но здоровым гораздо лучше, чем бедным, старым, но больным.

В данном сообщении рассматривается следующий вопрос: «что делать, когда ORDER BY по каким-то причинам недоступен?»

Ответ на этот вопрос такой: «следует использовать хинт для доступа по индексу».
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098007
ы
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ы
Гость
КваснойВ данном сообщении рассматривается следующий вопрос: «что делать, когда ORDER BY по каким-то причинам недоступен?»
Или ликвидировать причину, или уволиться/застрелиться/повеситься/etc...

КваснойОтвет на этот вопрос такой: «следует использовать хинт для доступа по индексу».
Я за такие ответы бью "Oracle Database Error Messages" по голове. До наступления просветления. Другие кишки тупым ножом выпускают :)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098026
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойВ данном сообщении рассматривается следующий вопрос: «что делать, когда ORDER BY по каким-то причинам недоступен?»

Ответ на этот вопрос такой: «следует использовать хинт для доступа по индексу».Правильный результат достигается соответствующим образом сформулированным запросом. Хинты - это не способ формулирования запроса, это лишь способ достижения результата более эффективным методом.

Каждый волен рисковать по-своему. Я не собираюсь упорствовать в твоем разубеждении. Тебя научит жизнь.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098387
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ElicКаждый волен рисковать по-своему. Я не собираюсь упорствовать в твоем разубеждении. Тебя научит жизнь.

В общем, всё в лучших традициях религий мира: ссылки на мифическую «жизнь» вместо примеров того, когда предложенная конструкция не работает :)

На этот месте обычно следуют рассказы о том что случится, если индекс станет UNUSABLE . Мне до сих пор интересно: найдётся ли хоть один человек, который перед тем , как высказать такое опасение, сделает-таки индекс UNUSABLE и посмотрит, что произойдёт на самом деле? Ну просто из любопытства.

И ещё напомню: не человек для субботы, а суббота для человека . СУБД существуют не для того, чтобы программисты и администраторы писали в них красивые и правильные запросы, а для того, чтобы быстро возвращать заложенные в них данные.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098440
ы
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ы
Гость
КваснойВ общем, всё в лучших традициях религий мира: ссылки на мифическую «жизнь» вместо примеров того, когда предложенная конструкция не работает :)

На этот месте обычно следуют рассказы о том что случится, если индекс станет UNUSABLE . Мне до сих пор интересно: найдётся ли хоть один человек, который перед тем , как высказать такое опасение, сделает-таки индекс UNUSABLE и посмотрит, что произойдёт на самом деле? Ну просто из любопытства.

И ещё напомню: не человек для субботы, а суббота для человека . СУБД существуют не для того, чтобы программисты и администраторы писали в них красивые и правильные запросы, а для того, чтобы быстро возвращать заложенные в них данные.

Код: 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.
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.
SQL*Plus: Release  9 . 2 . 0 . 6 . 0  - Production on Fri Jun  3   00 : 01 : 11   2005 

Copyright (c)  1982 ,  2002 , Oracle Corporation.  All rights reserved.


Connected to:
Oracle9i Enterprise Edition Release  9 . 2 . 0 . 6 . 0  - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release  9 . 2 . 0 . 6 . 0  - Production

SQL> create table t as select * from all_objects;

Table created.

SQL> create unique index t_i on t(object_id,object_name);

Index created.

SQL> analyze table t compute statistics;

Table analyzed.

SQL> set autotrace traceonly exp
SQL> select object_name from t order by object_id ;

Execution Plan
----------------------------------------------------------
    0       SELECT STATEMENT Optimizer=CHOOSE (Cost= 78  Card= 27240  Bytes=
           735480 )

    1      0    INDEX (FULL SCAN) OF 'T_I' (UNIQUE) (Cost= 310  Card= 27240  B
          ytes= 735480 )




SQL> alter index t_i unusable;

Index altered.

SQL> alter session set skip_unusable_indexes=true;

Session altered.

SQL> select object_name from t order by object_id ;

Execution Plan
----------------------------------------------------------
    0       SELECT STATEMENT Optimizer=CHOOSE (Cost= 430  Card= 27240  Bytes
          = 735480 )

    1      0    SORT (ORDER BY) (Cost= 430  Card= 27240  Bytes= 735480 )
    2      1      TABLE ACCESS (FULL) OF 'T' (Cost= 88  Card= 27240  Bytes= 735 
           480 )




SQL> select /*+ index (t,t_i) */ object_name from t order by object_id ;
select /*+ index (t,t_i) */ object_name from t order by object_id
*
ERROR at line  1 :
ORA- 01502 : index 'SYSTEM.T_I' or partition of such index is in unusable state


SQL> alter index t_i rebuild;

Index altered.

SQL> desc t
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                     NOT NULL VARCHAR2( 30 )
 OBJECT_NAME                               NOT NULL VARCHAR2( 30 )
 SUBOBJECT_NAME                                     VARCHAR2( 30 )
 OBJECT_ID                                 NOT NULL NUMBER
 DATA_OBJECT_ID                                     NUMBER
 OBJECT_TYPE                                        VARCHAR2( 18 )
 CREATED                                   NOT NULL DATE
 LAST_DDL_TIME                             NOT NULL DATE
 TIMESTAMP                                          VARCHAR2( 19 )
 STATUS                                             VARCHAR2( 7 )
 TEMPORARY                                          VARCHAR2( 1 )
 GENERATED                                          VARCHAR2( 1 )
 SECONDARY                                          VARCHAR2( 1 )

SQL> alter table t modify(object_id null, owner null,object_name null,
   2   created null,last_ddl_time null);

Table altered.

SQL> insert into t(object_id) values(null);

 1  row created.


Execution Plan
----------------------------------------------------------
    0       INSERT STATEMENT Optimizer=CHOOSE (Cost= 1  Card= 1  Bytes= 96 )



SQL> select /*+ index (t,t_i) */ object_name from t order by object_id ;

Execution Plan
----------------------------------------------------------
    0       SELECT STATEMENT Optimizer=CHOOSE (Cost= 430  Card= 27240  Bytes
          = 735480 )

    1      0    SORT (ORDER BY) (Cost= 430  Card= 27240  Bytes= 735480 )
    2      1      TABLE ACCESS (FULL) OF 'T' (Cost= 88  Card= 27240  Bytes= 735 
           480 )




SQL> 

P.S. Не надо корчить из себя супер-пупер специалиста, неся при этом чушь и считая других идиотами.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098460
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ы
P.S. Не надо корчить из себя супер-пупер специалиста, неся при этом чушь и считая других идиотами.

Во-первых, не хами. Ты в своих постах нахамил мне, абсолютно незнакомому тебе человеку, уже два раза. Этого делать не надо.

Во-вторых, своим примером ты показал, что если в хинте указаны индексы в состоянии UNUSABLE , то не сработает и сам запрос. Что и требовалось доказать.

А то в приведённой выше дискуссии некоторые её участники ошибочно считают, что если в хинте указан индекс в состоянии UNUSABLE , то CBO просто обойдёт этот индекс.

Это мнение полностью ошибочно и действительности не соответствует. Хотя как раз это мнение и является основным аргументом пуристов SQL.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098512
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Квасной
Это мнение полностью ошибочно и действительности не
соответствует. Хотя как раз это мнение и является основным
аргументом пуристов SQL.
http://groups-beta.google.com/group/fido7.ru.rdbms.oracle/msg/b81a57eace92752a?hl=en

цитата
> Я не уверен что Вы получите _гарантировонный_ результат,
> особенно при распаралеливании запроса

> Гарантий только две ORDER BY или ..

Гарантия одна ORDER BY, те кто знает когда им ORDER BY
не нужен им и не пользуются. Мы же это уже несколько сот
раз обсуждали.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098520
Вячеслав Любомудров
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойВо-вторых, своим примером ты показал, что если в хинте указаны индексы в состоянии UNUSABLE , то не сработает и сам запрос. Что и требовалось доказать.Так именно это тебе и показывают - бывают ситуации, когда программа должна отработать любой ценой (VIP-клиент ждет, начальство отчет требует и т.д.), а админ временно недоступен и перестроить индекс некому. И попробуй объяснить начальнику, что писался супер-пупер оптимизированный запрос под определенное поведение оракла, а тут оракл отказался так себя вести. А тут еще подтянется админ и выскажет вышеприведенные соображения. КваснойА то в приведённой выше дискуссии некоторые её участники ошибочно считают, что если в хинте указан индекс в состоянии UNUSABLE , то CBO просто обойдёт этот индекс.

Это мнение полностью ошибочно и действительности не соответствует. Хотя как раз это мнение и является основным аргументом пуристов SQL.Насколько я помню ту дискуссию, там этого не утверждалось (да это и легко проверяется)

По поводу правильности данных - индекс ведь может быть не только UNUSABLE, но и просто убит (админ решил инсерты оптимизировать или прибили на время заливки большого объема данных и забыли поднять). Вот тогда будет именно НЕПРАВИЛЬНЫЙ результат (и молчаливо, притом). А то есть любители искать минимальное:
Код: plaintext
tst> create table t123(x not null) as\n   2   select  2  from dual union all\n   3   select  1  from dual union all\n   4   select  3  from dual;\n\nTable created.\n\ntst> create index idx_t123_x on t123(x);\n\nIndex created.\n\ntst> set autotrace on exp\ntst> select /*+ index(t123, idx_t123_x) */ * from t123 where rownum= 1 ;\n\n         X\n----------\n          1 \n\n 1  row selected.\n\n\nExecution Plan\n----------------------------------------------------------\n    0       SELECT STATEMENT Optimizer=CHOOSE (Cost= 27  Card= 1  Bytes= 13 )\n    1      0    COUNT (STOPKEY)\n    2      1      INDEX (FULL SCAN) OF \'IDX_T123_X\' (NON-UNIQUE) (Cost= 27  Card= 327  Bytes= 4251 )\n\n\n\ntst> drop index idx_t123_x;\n\nIndex dropped.\n\ntst> select /*+ index(t123, idx_t123_x) */ * from t123 where rownum= 1 ;\n\n         X\n----------\n          2 \n\n 1  row selected.\n\n\nExecution Plan\n----------------------------------------------------------\n    0       SELECT STATEMENT Optimizer=CHOOSE (Cost= 3  Card= 1  Bytes= 13 )\n    1      0    COUNT (STOPKEY)\n    2      1      TABLE ACCESS (FULL) OF \'T123\' (Cost= 3  Card= 327  Bytes= 4251 )\n\n
Самое смешное, что простое добавление ORDER BY нисколько не утяжелит запрос (никто не запрещает использовать и хинты), но всегда гарантирует правильный результат

Еще одно соображение - есть любители использовать обработчик WHEN OTHERS THEN := значение по-умолчанию, дескать не нашли мы требуемого значения (NO_DATA_FOUND) или их больше одного (TOO_MANY_ROWS) или по формату не приводится/длина не та (VALUE_ERROR) или еще чего-нибудь, не удовлетворяющее нашим проверкам, короче, неподходит нам эта строка - нафига все перечислять, просто напишу WHEN OTHERS. А строка-то подходит, просто индекс UNUSABLE. Это ведь тоже неправильный результат.

Конечно, можно разволноваться и кричать, что все это криворукие админы/программеры, но, к сожалению, это встречается на каждом шагу. Поэтому программа должна себя вести как лифт: Аркадий и Борис Стругацкие. Сказка о тройке...
Но монтеры со своей стороны должны обеспечивать бесперебойность. Ничего, понимаете, ссылаться на объективные обстоятельства. У нас лозунг: "лифт для всех". Не взирая на лица. Лифт должен выдержать прямое попадание в кабину самого необученного академика .
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098556
ы
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ы
Гость
Квасной...
Поэтому и приходится использовать хинты для явного прописывания логики запроса...
...Что же до порядка строк — так он при корректном прописывании пути доступа по индексу тоже гарантирован...
...Ответ на этот вопрос такой: «следует использовать хинт для доступа по индексу»...
...На этот месте обычно следуют рассказы о том что случится, если индекс станет UNUSABLE. Мне до сих пор интересно: найдётся ли хоть один человек, который перед тем, как высказать такое опасение, сделает-таки индекс UNUSABLE и посмотрит, что произойдёт на самом деле? Ну просто из любопытства...
ыP.S. Не надо корчить из себя супер-пупер специалиста, неся при этом чушь и считая других идиотами.
Это что - не чушь? Причем безаппеляционно выдаваемая за истину в последней инстанции? Я так понимаю, что все-таки нашлись такие "человеки", которые проверили? Сюда (на sql.ru) заглядывают и серьезные дядьки - только это я и имел виду. Не надо считать себя умнее всех. Чаще всего это не так :)

что касается
ыЯ за такие ответы бью "Oracle Database Error Messages" по голове. До наступления просветления. Другие кишки тупым ножом выпускают :)
то, во-первых, это лично к тебе/Вам не относится - я так буду поступать со всеми, не смотря на звания и регалии. Во-вторых, обрати внимание на смайлик :)

P.S. Не воспринимай все лично на свой счет. Чуть поменьше распальцовка :), осторожность в выражениях никому не помешают. Извини, если обидел.

ElicЯ не собираюсь упорствовать в твоем разубеждении. Тебя научит жизнь.
Присоединяюсь. Bye.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33098691
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойВ общем, всё в лучших традициях религий мира: ссылки на мифическую «жизнь» вместо примеров того, когда предложенная конструкция не работает :)По существу сказано же достаточно. А по поводу твоей личной религии - это ты в точку :)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33100878
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вячеслав ЛюбомудровСамое смешное, что простое добавление ORDER BY нисколько не утяжелит запрос (никто не запрещает использовать и хинты), но всегда гарантирует правильный результат

Oh my god...

Перечитайте моё сообщение.

Не работает тут ORDER BY , понимаете?

Oracle не поддерживает передачу полей из запроса во вложенные запросы FIELD SUBQUERY .

Вот так:
Код: plaintext
1.
2.
3.
4.
5.
SELECT	(
	SELECT	dummy
	FROM	dual di
	WHERE	di.dummy = do.dummy
	)
FROM	dual do

работает.

А вот так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
SELECT	(
	SELECT	dummy
	FROM	(
		SELECT	dummy
		FROM	dual di
		WHERE	di.dummy = do.dummy
		ORDER BY
			dummy
		)
	WHERE	rownum =  1 
	)
FROM	dual do

не работает.

Я же не против ORDER BY как такового :)

ORDER BY — отличная конструкция, ею отсортировано уже не менее миллиарда запросов в мире.
ORDER BY обеспечивает правильный порядок фамилий в зарплатной ведомости.
ORDER BY выдаёт финансовым аналитикам отсортированный список решений.
Без ORDER BY мы бы запутались в выписке телефонных переговров Би-лайн...

Да чего уж там, очень много вещей, к которым мы привыкли сейчас, возможны только благодаря ORDER BY !

Но только в тех случаях, когда она не работает, надо не искать гарантий, а что-то делать.

Вячеслав Любомудров
Еще одно соображение - есть любители использовать обработчик WHEN OTHERS THEN := значение по-умолчанию, дескать не нашли мы требуемого значения (NO_DATA_FOUND) или их больше одного (TOO_MANY_ROWS) или по формату не приводится/длина не та (VALUE_ERROR) или еще чего-нибудь, не удовлетворяющее нашим проверкам, короче, неподходит нам эта строка - нафига все перечислять, просто напишу WHEN OTHERS. А строка-то подходит, просто индекс UNUSABLE. Это ведь тоже неправильный результат.


Я к таким любителям не отношусь и никому так делать не советую.

Однако к сортировке запросов это не имеет ни малейшего отношения :)

Вячеслав Любомудров
Конечно, можно разволноваться и кричать, что все это криворукие админы/программеры, но, к сожалению, это встречается на каждом шагу. Поэтому программа должна себя вести как лифт: Аркадий и Борис Стругацкие. Сказка о тройке...
Но монтеры со своей стороны должны обеспечивать бесперебойность. Ничего, понимаете, ссылаться на объективные обстоятельства. У нас лозунг: "лифт для всех". Не взирая на лица. Лифт должен выдержать прямое попадание в кабину самого необученного академика .

Ну это...

Мне неловко вам напоминать такую очевидную вещь, но если CBO , даже безо всяких хинтов, и с аккуратнейшим использованием ORDER BY , вдруг да и решит использовать индекс, который находится в состоянии UNUSABLE , то запрос вылетит по той же самой ORA-01502 .

Это к вопросу о лифте, который выдерживает прямое попадание CB ... простите, академика.

Хотя что это я.

Ведь у всех хороших програмистов, читавших Стругацких, процедуры, несомненно, корректно обрабатывают ORA-01502 (и именно её), без использования WHEN OTHERS .

Не так ли? :)

А если серьёзно, то программа должна себя вести не как лифт. Программа должна вести себя так, как прописано в ТЗ.

Если в ТЗ прописано, что программа должна быстро работать в 99,99% случаев, при этом допускается её отказ в 0,01% случаев, — то делать надо так, чтобы она работала быстро.

Если в ТЗ прописано, что программа должна работать в 100% случаев, то надо делать так, чтобы она работала правильно.

И опять же... Вот вы говорите: мол, админ может решить удалить или переименовать индекс. Тут, замечу я вам, проблема не в сортировке или хинтах, тут проблема в админе.

Как это так: он решил переименовать, или, тем более, удалить уникальный индекс?

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

Скажем, так:

Код: 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.
DECLARE
	cnt	NUMBER;
	index_unusable	EXCEPTION;
	PRAGMA EXCEPTION_INIT(index_unusable, - 1502 );
BEGIN
	BEGIN
		SELECT	NULL
		INTO	cnt
		FROM	dba_indexes
		WHERE	owner = SYS_CONTEXT('userenv', 'current_schema')
			AND index_name = 'UX_RATE_CURRENCY_DATE';
	EXCEPTION
	WHEN no_data_found THEN
		RAISE index_unusable;
	END;
	OPEN	:cur
	FOR	SELECT	(
			SELECT	/*+ INDEX_DESC (r ux_rate_currency_date) */
				rte_rate
			FROM	t_rate
			WHERE	rte_currency = acm_currency
				AND rte_date <= acm_date
				AND rownum =  1 
			) * acm_sum
		FROM 	t_accmove;
EXCEPTION
WHEN index_unusable THEN
	OPEN	:cur
	FOR	SELECT	(
			SELECT	/*+ FULL(r) */
				MAX(rte_rate) KEEP (DENSE_RANK LAST ORDER BY rte_date)
			FROM	t_rate r
			WHERE	rte_currency = acm_currency
				AND rte_date <= acm_date
			) * acm_sum
		FROM	t_accmove;
	DBMS_OUTPUT.put_line('Администратор базы данных, козлина тупая, чё-то сделал с уникальным индексом,');
	DBMS_OUTPUT.put_line('от которого, вообще-то, зависит логика работы базы.');
	DBMS_OUTPUT.put_line('Из-за этого ваша программа работает медленно, а скоро ещё и наделает ошибок.');
	DBMS_OUTPUT.put_line('Позвоните хозяину фирмы, пускай он выпишет администратору п' ||
		CHR( 232 ) || CHR( 231 ) || CHR( 228 ) || CHR( 238 ) || 'в, да покрепче');
END;

Чем плохо? :)

У меня , кстати, такая конструкция, без ORDER BY , уже года три работает на production в чуть больше чем тридцати местах.

Пока, тьфу-тьфу, держимся :)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33100882
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владимир Бегун цитата
> Я не уверен что Вы получите _гарантировонный_ результат,
> особенно при распаралеливании запроса

> Гарантий только две ORDER BY или ..

Гарантия одна ORDER BY, те кто знает когда им ORDER BY
не нужен им и не пользуются. Мы же это уже несколько сот
раз обсуждали.

Ну слава богу. Уважаемый человек говорит, что есть гарантии .

А то я вот не так давно читал такое:
Oracle Technology Network Development and Distribution License TermsTHE PROGRAMS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND . WE FURTHER DISCLAIM ALL WARRANTIES, EXPRESS AND IMPLIED, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.

IN NO EVENT SHALL WE BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOSS OF PROFITS, REVENUE, DATA OR DATA USE, INCURRED BY YOU OR ANY THIRD PARTY, WHETHER IN AN ACTION IN CONTRACT OR TORT, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Это, в частности, значит, что Oracle не гарантирует , что запрос будет отсортирован правильно, даже при использовании ORDER BY .

Как показывает практика , ORDER BY сортирует значения правильно. Это всё , что мы можем сказать об использовании ORDER BY .

Я даже документацию читал. Да вот только она попадает под то же лицензионное соглашение, которое ничего не гарантирует .

Но мне тут уже неоднократно говорили о каких-то гарантиях того, что ORDER BY всё отсортирует, как надо.

Владимир, где я могу про упомянутые вами гарантии прочитать подробнее?
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33100885
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойЭто, в частности, значит, что Oracle не гарантирует, что запрос будет отсортирован правильно, даже при использовании ORDER BY.
Нет, это (и даже не в частности) можно назвать попыткой расширить субъект тезиса. Этого делать не нужно.

Расшифровываю относительно лицензии:

Если, скажем, из-за какой-то недоделки ORDER BY не будет правильно (согласно документации) сортировать данные, то ты не можешь подать за это в суд и требовать возмещения убытков и проч. Вот именно об этом и написано в лицензии. Но это поведение и ответ Oracle по поводу недоделки будет железным агрументом в твою пользу и ты сможешь смело сказать: "Начальник, это bug #12345678. Ждём исправления". Т.е. с технической точки зрения, открытый эскалированный (если мощи лицензии хватит) TAR/bug позволит тебе получить исправление.

Теперь о слове "гарантия". Я упоминал его именно в том смысле в каком оно указано в документации, а именно:

Oracle9i SQL Reference Release 2 (9.2)
order_by_clause

Use the ORDER BY clause to order rows returned by the statement. Without an order_by_clause, no guarantee exists that the same query executed more than once will retrieve rows in the same order.

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

В данном же случае речь шла о другом, здесь я думаю со мной согласятся все участники этой дискуссии.

Я не могу не согласиться (зависит от понимания проблемы и ситуации), что иногда только так (index=source of pre-ordered data) и можно добиться нужной скорости выборки, но в целом, "without an order_by_clause, no guarantee exists that the same query executed more than once will retrieve rows in the same order". Я думаю этого достаточно, чтобы понять, что тех. поддержка тебя вышлет, если ты будешь им рассказывать о своей жизненной позиции по поводу использования индекса.

Если у тебя требования только обеспечить скорость и ты её обеспечиваешь написав такой код и все счастливы -- радуйся жизни. Если что-то сломается и тебя "не поймут", тогда сам решишь, что лучше -- "крепко спать" или "быстро бегать" ("бегать" в смысле на работу, к заказчику и проч. и исправлять ситуацию).

Всё нужно делать с умом.

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

Забавно, что с завидной переодичностью эта тема всплывает то там то сям... :-)

P.S.: Беседа на счёт смысла слов и их понимания, мне, честно говоря, мало интересна, поэтому если ты хочешь её продолжить, не расчитывай на моё в ней участие.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101306
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владимир БегунЯ думаю этого достаточно, чтобы понять, что тех. поддержка тебя вышлет, если ты будешь им рассказывать о своей жизненной позиции по поводу использования индекса.
Можно по поводу этого поподробнее?

Мои рассуждения строятся на двух предположениях:

1. Указанный хинт заставляет CBO использовать метод доступа INDEX RANGE SCAN DESCENDING .

Oracle9i Database Performance Tuning Guide and ReferenceSpecifying one of these hints causes the optimizer to choose the specified access path only if the access path is available based on the existence of an index or cluster and on the syntactic constructs of the SQL statement. If a hint specifies an unavailable access path, then the optimizer ignores it.
В данном случае мы будем предполагать, что индекс с заданным названием существует.

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

Вопрос: будет ли считаться багом ситуация, когда хинт указывает метод доступа INDEX RANGE SCAN DESCENDING по существующему индексу, конструкция запроса позволяет использовать этот метод, а CBO , вопреки тому, что написано в документации, этот метод не использует?

2. Если используется метод доступа INDEX RANGE SCAN DESCENDING , то значения возвращаются отсортированными по убыванию величины индексированных полей.

Oracle9i Database Performance Tuning Guide and ReferenceThe INDEX_DESC hint explicitly chooses an index scan for the specified table. If the statement uses an index range scan, then Oracle scans the index entries in descending order of their indexed values.
, и оттуда же:
Oracle9i Database Performance Tuning Guide and ReferenceAn index range scan descending is identical to an index range scan , except that the data is returned in descending order. Indexes, by default, are stored in ascending order. Usually, this scan is used when ordering data in a descending order to return the most recent data first, or when seeking a value less than a specified value.
Вопрос: будет ли считаться багом ситуация, в которой Oracle при использовании данного метода доступа возвращает строки не в порядке убывания величины индексированных полей, а в каком-то ином порядке, не соответствующем тому, что написано в документации?

Заранее спасибо за ответ.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101616
gz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
gz
Гость
КваснойОбычные джойны с группировкой и сортировкой работают медленно, и тут нам на помощь приходит хитрость. Блюстители чистоты SQL меня, конечно, засмеют, ну да мне не привыкать :)
Самое интересное в том, что Вы прекрасно понимаете, что это хитрость. Позвольте сделать одно предположение - над Вами нет начальника, понимающего эти проблемы. В противном случае Вы бы вылетели с работы после пары таких "закидонов".
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101680
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Квасной Вопрос : будет ли считаться багом ситуация, когда хинт указывает метод доступа INDEX RANGE SCAN DESCENDING по существующему индексу, конструкция запроса позволяет использовать этот метод, а CBO , вопреки тому, что написано в документации, этот метод не использует?


Well, lets not twist the facts:

Oracle9i Database Performance Tuning Guide and Reference. GlossaryCBO
Cost-based optimizer. Generates a set of potential execution plans for SQL statements, estimates the cost of each plan, calls the plan generator to generate the plan, compares the costs, and chooses the plan with the lowest cost . This approach is used when the data dictionary has statistics for at least one of the tables accessed by the SQL statements. The CBO is made up of the query transformer, the estimator, and the plan generator.

So the fact CBO will not use a hint because it conlicts with plan CBO considers optimal is normal and is not a bug:

Oracle9i Database Performance Tuning Guide and Reference Release 2 (9.2) Optimizer Hints Specifying a Full Set of Hints
When using hints, in some cases, you might need to specify a full set of hints in order to ensure the optimal execution plan. For example, if you have a very complex query, which consists of many table joins, and if you specify only the INDEX hint for a given table, then the optimizer needs to determine the remaining access paths to be used, as well as the corresponding join methods. Therefore, even though you gave the INDEX hint, the optimizer might not necessarily use that hint, because the optimizer might have determined that the requested index cannot be used due to the join methods and access paths selected by the optimizer.

Anyway, bottom line: only ORDER BY guarantees ordered resultset - using something else is just a ticking bomb.

SY.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101751
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY Квасной Вопрос : будет ли считаться багом ситуация, когда хинт указывает метод доступа INDEX RANGE SCAN DESCENDING по существующему индексу, конструкция запроса позволяет использовать этот метод, а CBO , вопреки тому, что написано в документации, этот метод не использует?

Well, lets not twist the facts:

Oracle9i Database Performance Tuning Guide and Reference. GlossaryCBO
Cost-based optimizer. Generates a set of potential execution plans for SQL statements, estimates the cost of each plan, calls the plan generator to generate the plan, compares the costs, and chooses the plan with the lowest cost . This approach is used when the data dictionary has statistics for at least one of the tables accessed by the SQL statements. The CBO is made up of the query transformer, the estimator, and the plan generator.

So the fact CBO will not use a hint because it conlicts with plan CBO considers optimal is normal and is not a bug:

Oracle9i Database Performance Tuning Guide and Reference Release 2 (9.2) Optimizer Hints Specifying a Full Set of Hints
When using hints, in some cases, you might need to specify a full set of hints in order to ensure the optimal execution plan. For example, if you have a very complex query, which consists of many table joins, and if you specify only the INDEX hint for a given table, then the optimizer needs to determine the remaining access paths to be used, as well as the corresponding join methods. Therefore, even though you gave the INDEX hint, the optimizer might not necessarily use that hint, because the optimizer might have determined that the requested index cannot be used due to the join methods and access paths selected by the optimizer.

Question: if I do specify full set of hints (with a STORED OUTLINE , for instance, or with hints as such), all tables and indexes do exist and are is usable state, then do I ensure the execution plan?

Note that there are no table joins in the FIELD SUBQUERY above.

And again,

Question: if CBO does use INDEX RANGE SCAN DESCENDING and returns rows not in descending order of indexed values (as said in specification), will it be considered a bug?

SYAnyway, bottom line: only ORDER BY guarantees ordered resultset - using something else is just a ticking bomb.
I have read the manuals and I have heard this sentence several hundred times before.

If one has a tiniest possibility to use ORDER BY clause, he must use it

There are some situations when ORDER BY clause is unavailable (see example above)

Once again: there are some situations when ORDER BY clause is unavailable (see example above)

The method described handles these situations correctly.

This method is intended for usage only in situations when ORDER BY clause is unavailable (see example above)

This method does conform to the specifications and it is tested on production systems.

ORDER BY clause does guarantee data order, but it cannot be used in some queries (see example above)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101762
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойOnce again: there are some situations when ORDER BY clause is unavailable (see example above)
Всегда найдутся пути ( например ) разрешения подобной проблемы без ущерба правильности результата .
КваснойThe method described handles these situations correctly.
Твои слова да богу в уши!
КваснойThis method does conform to the specifications and it is tested on production systems.
Даже тысячи успешных экспериментов не смогут превратить "лженаучную" () гипотезу в теорию.



Ты уже сделал свой выбор. Бог с тобой. Неси свой крест сам.
Но не надо пытаться привлекать за собой в эту странную религию другие неокрепшие умы.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101763
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойQuestion: if I do specify full set of hints (with a STORED OUTLINE, for instance, or with hints as such), all tables and indexes do exist and are is usable state, then do I ensure the execution plan?

Well, problem is it is difficult (at least for me) to determine what constitutes a full set of hints for a specific SQL statement. In terms of STORED OUTLINES, CBO should use same plan, however, in general, it might require certain INIT.ORA parameters be set same way (for example, QUERY_REWRITE_ENABLED, STAR_TRANSFORMATION_ENABLED, OPTIMIZER_FEATURES_ENABLE).

КваснойQuestion: if CBO does use INDEX RANGE SCAN DESCENDING and returns rows not in descending order of indexed values (as said in specification), will it be considered a bug?

No. For a simple reason you heard "several hundred times before". Besides, if you are joining tables, CBO might use index in desc order but then use hash join or some sort of conversion to bitmap which will affect resultset row order or simply whoever wrote CBO code felt like it. All INDEX_DESC hint tells CBO is how to access the table - it does not tell it to return it in desc or any other, for that matter, order.

SY.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101766
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ElicВсегда найдутся пути ( например ) разрешения подобной проблемы без ущерба правильности результата .

Они хорошие, эти пути. Медленно работают, а так хорошие.

ElicДаже тысячи успешных экспериментов не смогут превратить "лженаучную" () гипотезу в теорию.

Наука, гипотезы и теории здесь не причём.

Мы разговариваем про программное обеспечение СУБД Oracle, написанное определённым образом.

Оно написано таким образом, что мой запрос работает быстро (и правильно), а твой — медленно.

Причём тут наука?

ElicТы уже сделал свой выбор. Бог с тобой. Неси свой крест сам.
Но не надо пытаться привлекать за собой в эту странную религию другие неокрепшие умы.

Можно, я сам решу, что мне делать?

Спасибо.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101770
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY
Well, problem is it is difficult (at least for me) to determine what constitutes a full set of hints for a specific SQL statement. In terms of STORED OUTLINES, CBO should use same plan, however, in general, it might require certain INIT.ORA parameters be set same way (for example, QUERY_REWRITE_ENABLED, STAR_TRANSFORMATION_ENABLED, OPTIMIZER_FEATURES_ENABLE).


We are getting more and more clear :)

So, once again:

Question 1 : if I set up database with all the parameters needed for the STORED OUTLINES to work (according to specification), make a STORED OUTLINE to use INDEX RANGE SCAN DESCENDING , and the indexes in question are present and functional, will it be considered a bug if the CBO chooses another access method?

Question 2 : if CBO does use INDEX RANGE SCAN DESCENDING and returns rows not in descending order of their indexed values (as said in specification), will it be considered a bug?

Thanks in advance for answering.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101773
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY КваснойQuestion: if I do specify full set of hints (with a STORED OUTLINE, for instance, or with hints as such), all tables and indexes do exist and are is usable state, then do I ensure the execution plan?

Well, problem is it is difficult (at least for me) to determine what constitutes a full set of hints for a specific SQL statement. In terms of STORED OUTLINES, CBO should use same plan, however, in general, it might require certain INIT.ORA parameters be set same way (for example, QUERY_REWRITE_ENABLED, STAR_TRANSFORMATION_ENABLED, OPTIMIZER_FEATURES_ENABLE).

КваснойQuestion: if CBO does use INDEX RANGE SCAN DESCENDING and returns rows not in descending order of indexed values (as said in specification), will it be considered a bug?

No. For a simple reason you heard "several hundred times before". Besides, if you are joining tables, CBO might use index in desc order but then use hash join or some sort of conversion to bitmap which will affect resultset row order or simply whoever wrote CBO code felt like it. All INDEX_DESC hint tells CBO is how to access the table - it does not tell it to return it in desc or any other, for that matter, order.

SY.

Sorry for repeating, but:

Oracle9i Database Performance Tuning Guide and ReferenceAn index range scan descending is identical to an index range scan , except that the data is returned in descending order. Indexes, by default, are stored in ascending order. Usually, this scan is used when ordering data in a descending order to return the most recent data first , or when seeking a value less than a specified value.

Again, there are no table joins in the query in question.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101778
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Почитай пожалуйста указанную мной ссылку на одну из нитей обсуждения этой ситуации -- фраза "[ но в целом , "without an order_by_clause, no guarantee exists that the same query executed more than once will retrieve rows in the same order".] Я думаю этого достаточно, чтобы понять, что тех. поддержка тебя вышлет, если ты будешь им рассказывать о своей жизненной позиции по поводу использования индекса." -- это один из примеров когда запрос может возвращать вовсе не то что ожидается (там другой план выполнения, но по рукам будут бить не потому что у Oracle план поменялся, а потому что приложение что-то посчитало неправильно). Вообщем и целом такой подход менее foolproof, чем подход с явным использованием ORDER BY или другой функциональности, где бы всё было сделано с учётом изменений схемы, сообственно, об этом и говорилось. Также, опыт показывает что число проблем (bugs) связанных с использованием подсказки INDEX_DESC было несколько больше чем с использованием ORDER BY. И если вдруг такая проблема возникнет, то в тех местах где ты используешь INDEX_DESC тебе придётся менять функциональность или ждать исправлений. Вот тут и скажут тебе о заветном "workaround": USE ORDER BY! Поэтому здесь замечание "Тебя научит жизнь." справедливо. Несколько выше ты пытался доказать что появление проблемы подобного плана при использовании ORDER BY равновероятна появлению проблемы при использовании INDEX_DESC, должен отметить что это несколько не так. Их появление неравновероятно.

<OFFTOPIC>Да, и не нужно неумело вырывать фразы из контекста.</OFFTOPIC>

КваснойВопрос: будет ли считаться багом ситуация, когда хинт указывает метод доступа INDEX RANGE SCAN DESCENDING по существующему индексу, конструкция запроса позволяет использовать этот метод, а CBO, вопреки тому, что написано в документации, этот метод не использует?CBO обязан подчиниться подсказке, если нет синтаксических и семантических проблем с её применением. Основная проблема -- понимание семантики выполнения.

КваснойВ данном случае мы будем предполагать, что индекс с заданным названием существует.В каком "данном"? Если ты говоришь только о том примере, который ты привёл в своём самом первом сообщении, то да, индекс будет использоваться. Здесь нет никаких противоречий и возражений. Более того как говорил Станислав, здесь перефразировано, "как же так? примерчик-то был" :-)
Квасной 2. Если используется метод доступа INDEX RANGE SCAN DESCENDING , то значения возвращаются отсортированными по убыванию величины индексированных полей.
Грубо: при INDEX RANGE SCAN DESCENDING значения будут "появлятся" в rowsource, по мере чтения блоков индекса. Поскольку они хранятся отсортированными, то да, они будут попадать в rowsource отсортированными. Как они будут возвращаться из запроса, зависит от того что происходит дальше, используется ли, скажем, PQO, joins и т.д.
Квасной Вопрос: будет ли считаться багом ситуация, в которой Oracle при использовании данного метода доступа возвращает строки не в порядке убывания величины индексированных полей, а в каком-то ином порядке, не соответствующем тому, что написано в документации?Я уже писал об этом, если поведение Oracle RDBMS не соответствует тому о чём написано в документации -- нужно открывать TAR и разговаривать с тех. поддержкой.

http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:9843506698920#9896083461138

Я не могу сказать что здесь я на 100% согласен с Томасом Кайтом (я оставляю 1%, именно потому что пару раз мне пришлось решать проблему, котороая вынуждала использовать такой подход. Дело было на 7.3 и 8.0.x да и то только потому что были какие-то старнные баги, разбираться было некогда), но за всеми теми красноречивыми высказываниями есть рациональное зерно... Даже твой код выше, в котором ты обругал абстрактного администратора БД абсолютно не foolproof -- ошибки ищи сам. :-)

Ради любопытства, я хотел бы увидеть raw tracefiles твоего запроса и того что ниже. Пожалуйста, если нужно, сделай соответсвующий корректировки для своей системы. Проверь три варианта:

1. Твой оригинальный запрос.
2. Тот что ниже.
3. Тот что ниже с подсказкой /*+ INDEX_DESC (r ux_rate_currency_date) */

и выложи сюда zipped raw trace files.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
DEFINE numb_mask = 'FM9999999999.99999'
DEFINE date_mask = 'YYYYMMDD'
DEFINE date_mast_l1 =  9 

SELECT TO_NUMBER(
         SUBSTR(
           (
           SELECT MAX(TO_CHAR(r.rdate, '&&date_mask') || TO_CHAR(r.rrate, '&&numb_mask', 'NLS_NUMERIC_CHARACTERS=".,"')) l
             FROM rates r
            WHERE r.rdate <= x.xdate
              AND r.rcurrency = x.xcurrency
            GROUP BY
                  r.rcurrency
           )
         , &&date_mast_l1
         )
       , '&&numb_mask'
       , 'NLS_NUMERIC_CHARACTERS=".,"'
       ) rate
  FROM transactions x
/
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33101891
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: 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.
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.
SQL> SELECT * FROM v$version WHERE ROWNUM =  1 ;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release  10 . 1 . 0 . 4 . 0  - Prod

SQL> CREATE TABLE transactions (xid NUMBER, xsum FLOAT, xdate DATE, xcurrency NUMBER);

Таблица создана.

SQL> CREATE TABLE rates (rcurrency NUMBER, rdate DATE, rrate FLOAT);

Таблица создана.

SQL> CREATE UNIQUE INDEX ux_rate_currency_date ON rates (rcurrency, rdate);

Индекс создан.

SQL> BEGIN
   2     dbms_stats.gather_table_stats(ownname => USER, tabname => 'RATES', CASCADE => TRUE);
   3     dbms_stats.gather_table_stats(ownname => USER, tabname => 'TRANSACTIONS');
   4   END;
   5   /

Процедура PL/SQL успешно завершена.

SQL> INSERT INTO transactions VALUES( 1 ,  1 , TRUNC(SYSDATE),  1 );

 1  строка создана.

SQL> INSERT INTO transactions VALUES( 1 ,  2 , TRUNC(SYSDATE),  2 );

 1  строка создана.

SQL> INSERT INTO transactions VALUES( 1 ,  2 , TRUNC(SYSDATE) -  1 ,  2 );

 1  строка создана.

SQL> INSERT INTO rates VALUES( 1 , TRUNC(SYSDATE) -  1 ,  1 . 2 );

 1  строка создана.

SQL> INSERT INTO rates VALUES( 1 , TRUNC(SYSDATE) -  2 ,  1 . 1 );

 1  строка создана.

SQL> INSERT INTO rates VALUES( 2 , TRUNC(SYSDATE) -  0 ,  1 . 0 );

 1  строка создана.

SQL> INSERT INTO rates VALUES( 2 , TRUNC(SYSDATE) -  1 ,  1 . 1 );

 1  строка создана.

SQL> INSERT INTO rates VALUES( 2 , TRUNC(SYSDATE) -  2 ,  1 . 2 );

 1  строка создана.

SQL> 
SQL> SET AUTOTRACE ON EXPL
SQL> SELECT  (
   2   	     SELECT  /*+ INDEX_DESC (r ux_rate_currency_date) */
   3   		     rrate
   4   	     FROM    rates r
   5   	     WHERE   r.rcurrency = x.xcurrency
   6   		     AND r.rdate <= x.xdate
   7   		     AND rownum =  1 
   8   	     ) AS eff_rate
   9   FROM    transactions x
  10   /

  EFF_RATE
----------
        1 , 2 
          1 
        1 , 1 


План выполнения
----------------------------------------------------------
    0       SELECT STATEMENT Optimizer=ALL_ROWS (Cost= 2  Card= 1  Bytes= 22 )
    1      0    COUNT (STOPKEY)
    2      1      TABLE ACCESS (BY INDEX ROWID) OF 'RATES' (TABLE)
    3      2        INDEX (RANGE SCAN DESCENDING) OF 'UX_RATE_CURRENCY_DATE' (INDEX (UNIQUE))
    4      0    TABLE ACCESS (FULL) OF 'TRANSACTIONS' (TABLE) (Cost= 2  Card= 1  Bytes= 22 )



SQL> ALTER SESSION SET -
> "_optimizer_ignore_hints"=TRUE
   2   /

Сеанс изменен.

SQL> SELECT  (
   2   	     SELECT  /*+ INDEX_DESC (r ux_rate_currency_date) */
   3   		     rrate
   4   	     FROM    rates r
   5   	     WHERE   r.rcurrency = x.xcurrency
   6   		     AND r.rdate <= x.xdate
   7   		     AND rownum =  1 
   8   	     ) AS eff_rate
   9   FROM    transactions x
  10   /

  EFF_RATE
----------
        1 , 1 
        1 , 2 
        1 , 2 


План выполнения
----------------------------------------------------------
    0       SELECT STATEMENT Optimizer=ALL_ROWS (Cost= 2  Card= 1  Bytes= 22 )
    1      0    COUNT (STOPKEY)
    2      1      TABLE ACCESS (BY INDEX ROWID) OF 'RATES' (TABLE)
    3      2        INDEX (RANGE SCAN) OF 'UX_RATE_CURRENCY_DATE' (INDEX (UNIQUE))
    4      0    TABLE ACCESS (FULL) OF 'TRANSACTIONS' (TABLE) (Cost= 2  Card= 1  Bytes= 22 )



SQL> DROP TABLE rates;

Таблица удалена.

SQL> DROP TABLE transactions;

Таблица удалена.

SQL> EXEC EXECUTE IMMEDIATE 'purge recyclebin';

Процедура PL/SQL успешно завершена.

SQL> SPOOL OFF
Срочно беги за валидолом :-)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33102113
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владимир Бегун
Код: plaintext
1.
SQL> ALTER SESSION SET "_optimizer_ignore_hints"=TRUE
   2   /

Сеанс изменен.

Интересно: а почему, например, не DROP TABLE , или не SHUTDOWN ABORT ?

К чему такие полумеры? :)

У нас, например, такие вещи никто не делает, тем более на боевых серверах, потому как запрещено монаршей властию.

Хочешь поменять что-то в базе — проконсультируйся с заинтересоваными лицами.

Владимир БегунСрочно беги за валидолом :-)

Да я уж как-нибудь так, аскорбинкой :)

P.S. Трейсы вечерком выложу, ОК?
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103261
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойSorry for repeating, but:


Oracle9i Database Performance Tuning Guide and Reference An index range scan descending is identical to an index range scan, except that the data is returned in descending order. Indexes, by default, are stored in ascending order. Usually, this scan is used when ordering data in a descending order to return the most recent data first, or when seeking a value less than a specified value.

Again, there are no table joins in the query in question.


Well, Владимир Бегун already answered it - PQO. Phrase "the data is returned in descending order" you are referring to applies not to a session executing SQL statement, but rather to individual processes/threads/slaves session is executing. So in case of PQO, each slave will return data in descending order. However, when results are merged, there is no guarantee such order will be preserved.

SY.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103287
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну-с, вот обещанные трейсы.

В таблице transactions около 1 600 000 строк;

В таблице rates около 25 000 строк;

Селективность индекса ux_rates_currency_date по полю currency — около 8% , т. е. около 2 000 строк по каждой валюте.

В целях ускорения запроса выборка велась по первым 9 999 строкам из transactions . Результаты агрегировались и по ним считалась сумма.

Мой запрос работал 0,40 сек.
Запрос, предложенный тов. "Splain", работал 10,64 сек.
Запрос тов. "Владимира Бегуна" работал 34,53 сек.
Запрос тов. "Владимира Бегуна" с хинтом работал 34,04 сек.

Общую сумму по всей таблице transactions ( 1 600 000 строк) мой запрос считает около 25 сек.

Результатов работы остальных запросов я, понятное дело, ждать не стал, время из работы, по прогнозам, составило бы от 250 до 750—800 секунд. Желающие могут проверить сами.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103307
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SYWell, Владимир Бегун already answered it - PQO. Phrase "the data is returned in descending order" you are referring to applies not to a session executing SQL statement, but rather to individual processes/threads/slaves session is executing. So in case of PQO, each slave will return data in descending order. However, when results are merged, there is no guarantee such order will be preserved.

SY.

That's true, PQO may affect data order. I use Standard Edition with no PQO , so that's not a problem for me, but it may be a problem for Enterprise Edition users.

So what if we disable PQO for that query with /*+ NOPARALLEL_INDEX (r ux_rates_currency_date) */ ?

There will be no parallel scans and no table joins.

What else can violate the data order returned by INDEX RANGE SCAN DESCENDING ?
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103459
Oleg Perekhrest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
КваснойНу-с, вот обещанные трейсы.

В таблице transactions около 1 600 000 строк;

В таблице rates около 25 000 строк;

Селективность индекса ux_rates_currency_date по полю currency — около 8% , т. е. около 2 000 строк по каждой валюте.

В целях ускорения запроса выборка велась по первым 9 999 строкам из transactions . Результаты агрегировались и по ним считалась сумма.

Мой запрос работал 0,40 сек.
Запрос, предложенный тов. "Splain", работал 10,64 сек.
Запрос тов. "Владимира Бегуна" работал 34,53 сек.
Запрос тов. "Владимира Бегуна" с хинтом работал 34,04 сек.

Общую сумму по всей таблице transactions ( 1 600 000 строк) мой запрос считает около 25 сек.

Результатов работы остальных запросов я, понятное дело, ждать не стал, время из работы, по прогнозам, составило бы от 250 до 750—800 секунд. Желающие могут проверить сами.


Для запроса Бегуна, надо было ф-ый индекс создавать
по выражению TO_CHAR(r.rdate, \'&&date_mask\') || TO_CHAR(r.rrate, \'&&numb_mask\', \'NLS_NUMERIC_CHARACTERS=".,"\')

Скиньте еще результаты с другим индексом
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103512
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Oleg PerekhrestДля запроса Бегуна, надо было ф-ый индекс создавать
Ты "поторопился" с советом :-) а мне нужно что-то делать с cut&paste...
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103513
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Oleg Perekhrest
Для запроса Бегуна, надо было ф-ый индекс создавать
по выражению TO_CHAR(r.rdate, '&&date_mask') || TO_CHAR(r.rrate, '&&numb_mask', 'NLS_NUMERIC_CHARACTERS=".,"')

Скиньте еще результаты с другим индексом

Он его не цепляет. То есть цепляет, конечно, но делает так:

Код: plaintext
1.
2.
CREATE INDEX ux_rates_function
ON rates (rcurrency, TO_CHAR(rdate, 'YYYYMMDD') ||
TO_CHAR(rrate, 'FM9999999999.99999', 'NLS_NUMERIC_CHARACTERS=".,"'))

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
EXPLAIN PLAN FOR
SELECT	/*+ INDEX (r ux_rates_function) */
	MAX(TO_CHAR(rdate, 'YYYYMMDD') ||
	TO_CHAR(rrate, 'FM9999999999.99999', 'NLS_NUMERIC_CHARACTERS=".,"'))
FROM	rates r
WHERE	rcurrency = :cur
	AND (TO_CHAR(rdate, 'YYYYMMDD') ||
	TO_CHAR(rrate, 'FM9999999999.99999', 'NLS_NUMERIC_CHARACTERS=".,"')) <= :xdate
GROUP BY
	rcurrency

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id  | Operation                    |  Name              | Rows  | Bytes | Cost
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                    |     8 |   216 |
|   1 |  SORT GROUP BY NOSORT        |                    |     8 |   216 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| RATES              |     8 |   216 |
|*  3 |    INDEX RANGE SCAN          | UX_RATES_FUNCTION  |    61 |       |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_CHAR("R"."RDATE",'YYYYMMDD')||TO_CHAR("R"."RRATE",'FM9999999999
              .9999','nls_numeric_characters=''".''')<=:Z)
   3 - access("R"."RCURRENCY"=:Z)
Note: cpu costing is off

Производительность, понятно, ещё меньше.

Почему-то при использовании функциональных индексов CBO не делает INDEX RANGE SCAN / FIRST ROW (MIN/MAX) .

Я когда-то пытался с этим экспериментировать, но результаты абсолютно невоспроизводимы (в отличие от использования INDEX_DESC по обычному индексу)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103528
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Покажи результаты такого же теста, но с FBI, также охота посмотреть на waits.

Честно говоря, удивлён, что ты делаешь NL на таких объёмах -- если это действительно рабочий запрос на таком количестве данных.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103538
?
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
?
Гость
Квасной...
Note: cpu costing is off
...
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103542
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владимир БегунПокажи результаты такого же теста, но с FBI, также охота посмотреть на waits.

Завтра вечером, ОК?

Владимир БегунЧестно говоря, удивлён, что ты делаешь NL на таких объёмах -- если это действительно рабочий запрос на таком количестве данных.

Ну, по всем проводкам он практически никогда не бывает. Обычно отфильтровываются пятьдесят-сто-двести тысяч строк, реже пятьсот, реже миллион, по ним считаются суммы в базовой валюте (как раз таким вот способом), и делаются всякие агрегаты. На боевом сервере это доли секунд-секунды. Но всё равно нет предела совершенству :)

А как быстрее сделать джойн по условию минимакса, я не знаю. Если подскажешь способ — с меня стакан кориандровой.

Мне ведь этот самопал с хинтами тоже не особо нравится :) Я его предлагаю только потому, что он работает и более-менее документирован.

А так я ночи не сплю, думаю, как бы ORDER BY половчее прикрутить :)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103547
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойТо есть цепляет, конечно, но делает так:
Нет, это ты так руками написал, делает он так:
Код: 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.
SQL> SELECT * FROM TABLE(dbms_xplan.display());

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value:  204164600 

--------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|    0  | SELECT STATEMENT             |                   |      3  |     66  |      3    ( 0 )|  00 : 00 : 01  |
|    1  |  SORT GROUP BY NOSORT        |                   |      1  |     35  |      2    ( 0 )|  00 : 00 : 01  |
|*   2  |   TABLE ACCESS BY INDEX ROWID| RATES             |      1  |     35  |      2    ( 0 )|  00 : 00 : 01  |
|*   3  |    INDEX RANGE SCAN          | UX_RATES_FUNCTION |      1  |       |      1    ( 0 )|  00 : 00 : 01  |
|    4  |    TABLE ACCESS FULL         | TRANSACTIONS      |      3  |     66  |      3    ( 0 )|  00 : 00 : 01  |
--------------------------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------

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

    2  - filter("R"."RDATE"<=:B1)
    3  - access("R"."RCURRENCY"=:B1)
Но дело даже не в этом. "Проблема" у запроса это -- NL, и на больших объёмах в системах с большим числом одновременно работающих пользователей это приведёт к общему падению производительности системы -- CPU будет NL "работать". Поэтому, "меня терзают смутные сомнения" что ты действительно используешь именно этот запрос (именно так как ты его написал без дополнтельных фильтров) в более чем 30(?) местах.

Проверять с FBI большого смысла нет. Отменяю запрос.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103557
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владимир Бегун
Нет, это ты так руками написал, делает он так:


Ну что я, совсем, что ли, шакал позорный — руками что-то подписывать?

В точности так он делает, как я в посте написал.

Я план делал для FIELD SUBQUERY , а не для всего запроса.

Для всего запроса вот, пожалуйста:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id  | Operation                    |  Name              | Rows  | Bytes | Cost
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                    |   637K|    16M|  118
|   1 |  SORT GROUP BY NOSORT        |                    |     8 |   216 |
|   2 |   TABLE ACCESS BY INDEX ROWID| RATES              |     8 |   216 |
|*  3 |    INDEX RANGE SCAN          | UX_RATES_FUNCTION  |     3 |       |
|   4 |  TABLE ACCESS FULL           | TRANSACTIONS       |   637K|    16M|  118
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("RATES"."RCURRENCY"=:B1)
       filter(TO_CHAR("RATES"."RDATE",'YYYYMMDD')||TO_CHAR("RATES"."RRATE",'FM99
              99999999.99999','nls_numeric_characters=''".''')<=:B1)
Note: cpu costing is off

Владимир Бегун
Но дело даже не в этом. "Проблема" у запроса это -- NL, и на больших объёмах в системах с большим числом одновременно работающих пользователей это приведёт к общему падению производительности системы -- CPU будет NL "работать". Поэтому, "меня терзают смутные сомнения" что ты действительно используешь именно этот запрос (именно так как ты его написал без дополнтельных фильтров) в более чем 30(?) местах.

Проверять с FBI большого смысла нет. Отменяю запрос.

Одновременно работающих пользователей там как раз мало.

Да к тому же я уже говорил: фильтры используются, запрос работает секунды, как сделать джойн по минимаксу быстрее — не знаю.

И всё таки, вернёмся к нашим хинтам.

Итак, на текущий момент имеем следующий вопрос : если дополнительным хинтом отключить PARALLEL ACCESS в INDEX RANGE SCAN DESCENDING , и не использовать в запросе джойнов, должна ли правильность порядка возвращаемых данных определяться правильностью хранения их в индексе?

Согласно документации — да, должна.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103559
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Квасной Владимир Бегун
Нет, это ты так руками написал, делает он так:

Ну что я, совсем, что ли, шакал позорный — руками что-то подписывать?

Ты сам себя так назвал, вот этот запрос, это не тот запрос, который я просил тебя проверять, ок?
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT	/*+ INDEX (r ux_rates_function) */
	MAX(TO_CHAR(rdate, 'YYYYMMDD') ||
	TO_CHAR(rrate, 'FM9999999999.99999', 'NLS_NUMERIC_CHARACTERS=".,"'))
FROM	rates r
WHERE	rcurrency = :cur
	AND (TO_CHAR(rdate, 'YYYYMMDD') ||
	TO_CHAR(rrate, 'FM9999999999.99999', 'NLS_NUMERIC_CHARACTERS=".,"')) <= :xdate
GROUP BY
	rcurrency
:-) Тише едешь, дальше будешь...
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103566
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КваснойА так я ночи не сплю, думаю, как бы ORDER BY половчее прикрутить :)

The way I see it, core of the issue is "wrong tool" for the job. Task is to select MIN/MAX value, or generalizing, to select value (or row producing that value) based on its rank. ORDER BY is wrong (in terms of efficiency) tool for the job if value is indexed, assuming corresponding column or columns are NOT NULL or NULLS need to be excluded from ranking process. However and unfortunately, ORDER BY is the only guaranteed tool for the job. Frankly, I am surprised Oracle does not offer any functions based on indexes, so you do not have to sort every time. Something like:

Код: plaintext
INDEX_BASED_RANK(column,index-name,rank,ranking-method,ranking-direction)

where ranking-method is either DENSE or SPARSE and ranking-direction is either ASC or DESC. In any case, I agree with Квасной, indexes are quite underutilized. It is a classic "видит око...".

SY.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103571
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Квасной
Итак, на текущий момент имеем следующий вопрос : если дополнительным хинтом отключить PARALLEL ACCESS в INDEX RANGE SCAN DESCENDING , и не использовать в запросе джойнов, должна ли правильность порядка возвращаемых данных определяться правильностью хранения их в индексе?
Да. Если в системе ничего не происходит:

- изменений схемы
- параметров
- всё жёстко "прошито"

то да, работает так как просили. Твой вопрос абсолютно правомерный -- как при прочих равных добиться быстрой скорости работы "официально разрешенных" конструкций, не жертвуя при этом скоростью. В общем случая, я бы пожертвовал скоростью, но вводная такова что ничего не меняется... :-) ("поймаете" вы что нибудь... жизнь штука жестокая).
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103575
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владимир Бегун
Ты сам себя так назвал, вот этот запрос, это не тот запрос, который я просил тебя проверять, ок?

А я от твоего запроса планов и не постил :) Только трейсы и время исполнения.

То, про что ты говоришь — это план от запроса с ипользованием индекса, предложенного тов. "Oleg Perekhrest", это я ему отвечал. :)

Но твой запрос тоже не быстрит: он не может сделать INDEX RANGE SCAN / FIRST ROW (MIN/MAX) по функции, т. к. она не проиндексирована. Поэтому приходится делать INDEX RANGE SCAN по всей подходящей области, и сортировать по значению функции.

Но даже если функция проиндексирована — то CBO один хрен не делает INDEX RANGE SCAN / FIRST ROW (MIN/MAX) , непонятно, почему.

Кстати, если сделать MAX(rdate) с использованием INDEX RANGE SCAN / FIRST ROW (MIN/MAX) , а потом сджойниться с таблицей rates ещё раз, то всё работает достаточно бодренько. Медленнее, конечно, чем с INDEX RANGE SCAN DESCENDING , но быстрее, чем со всем вышеизложенным.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103581
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Квасной Владимир Бегун
Ты сам себя так назвал, вот этот запрос, это не тот запрос, который я просил тебя проверять, ок?
То, про что ты говоришь — это план от запроса с ипользованием индекса, предложенного тов. "Oleg Perekhrest", это я ему отвечал. :)
Я повторю то, что уже сказал:
Ты "делал для FIELD SUBQUERY, а не для всего запроса." -- и сделал ты это неверно. Вот и всё. :-) Проехали.
КваснойНо твой запрос тоже не быстрит:
Было написано "ради любопытства..."...
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103583
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SYThe way I see it, core of the issue is "wrong tool" for the job. Task is to select MIN/MAX value, or generalizing, to select value (or row producing that value) based on its rank. ORDER BY is wrong (in terms of efficiency) tool for the job if value is indexed, assuming corresponding column or columns are NOT NULL or NULLS need to be excluded from ranking process. However and unfortunately, ORDER BY is the only guaranteed tool for the job. Frankly, I am surprised Oracle does not offer any functions based on indexes, so you do not have to sort every time. Something like:

Код: plaintext
INDEX_BASED_RANK(column,index-name,rank,ranking-method,ranking-direction)

where ranking-method is either DENSE or SPARSE and ranking-direction is either ASC or DESC. In any case, I agree with Квасной, indexes are quite underutilized. It is a classic "видит око...".

SY.

You're absolutely right.

The problem is that such an outstanding software as Oracle has some piece of code in it called CBO . In fact, one should persuade it to use certain access paths, join methods etc., and it may either agree to use the way of work chosen, or silently ignore it and work in its own way.

I think it's quite rotten, ill and wrong situation.

I don't care whether a delivery boy uses subway or bus, but I do care about major things like profit renvestment etc.

The same with CBO . I don't care how CBO selects a row from a table that has 5 rows, but I do care how does it executes queries like described above, as they are quite important for the business logics.

So I think CBO should have an option to use strict hints of something like that. The query with such hints should either run with access paths and join methods offered; or generate an error, if they are unavailable.

Unfortunately, I can show no key for a limo large enough to criticize Oracle, that's why I'm just trying to work with what they sell us :)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103637
Oleg Perekhrest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В общем что тут сказать...
Я например вот занимаюсь DWH под Oracle, у нас тоже имеются исторические таблицы. Вначале в 98 году начиналось все с табличек вида
CREATE TABLE transactions (bdate DATE, ....);
везде делался поиск по max но без ограничения по rownum, так как случай обычно другой был, надо было достать не одно поле, а все поля - а это значило что надо найти было эффективную дату действия, и связаться с табличкой trasnaction еще раз, чтобы достать все поля - т.е. условия связки были в теле where а не в вычислимых полях.
Потом через годик когда база подросла, пришлось добавить еще одно поле
CREATE TABLE transactions (bdate DATE, edate DATA....);
таким образом избавились от поиска max и перешли на between

Теперь же обычно используем смешанный способ:
1) или банальный between если надо достать строки на указанную дату. или edate='01.01.4000' для доставания действующей строки - так технологически заложено
2) или используем хранимую функцию вида:
обявляем курсор с order by
открываем курсор
берем поле - эффективную дату
закрываем курсор
возвращаем его в запрос где он используется
3) иногда пользуемся вариантом substr(max(поле_даты||поле_данных), x, y)

на больших объемах данных, где надо обрабатывать не одну, а множество строк, эффективнее всего оказались способ 1) или 2). но у нас же вариант достать обычно все поля из исторической таблицы, а не одно.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33103654
Квасной
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Oleg PerekhrestВ общем что тут сказать...
Я например вот занимаюсь DWH под Oracle, у нас тоже имеются исторические таблицы. Вначале в 98 году начиналось все с табличек вида
CREATE TABLE transactions (bdate DATE, ....);
везде делался поиск по max но без ограничения по rownum, так как случай обычно другой был, надо было достать не одно поле, а все поля - а это значило что надо найти было эффективную дату действия, и связаться с табличкой trasnaction еще раз, чтобы достать все поля - т.е. условия связки были в теле where а не в вычислимых полях.
Потом через годик когда база подросла, пришлось добавить еще одно поле
CREATE TABLE transactions (bdate DATE, edate DATA....);
таким образом избавились от поиска max и перешли на between

Теперь же обычно используем смешанный способ:
1) или банальный between если надо достать строки на указанную дату. или edate='01.01.4000' для доставания действующей строки - так технологически заложено
2) или используем хранимую функцию вида:
обявляем курсор с order by
открываем курсор
берем поле - эффективную дату
закрываем курсор
возвращаем его в запрос где он используется
3) иногда пользуемся вариантом substr(max(поле_даты||поле_данных), x, y)

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

Мы тоже раньше делали через функции.

Однако они, сволочи, тормозят (в четыре-пять раз), из за контекст-свитчинга.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #33122985
Владимир Бегун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я открыл баг (снаружи он не виден) относительно проблемной конструкции. Есть
подозрения кое-какие и надеюсь что они верны и вскорости наступит всеобщее
счастье.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Выборка уникальных значений из хронологической таблицы
    #36426872
Владимир БегунЯ открыл баг (снаружи он не виден) относительно проблемной конструкции. Есть
подозрения кое-какие и надеюсь что они верны и вскорости наступит всеобщее
счастье.

Столкнулся с такой же проблемой на этой неделе на 10.2.0.4.
Счастье не наступило.

Радует что баг так и остался невидим снаружи :)
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #36426980
Inline view
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Квасной
К сожалению, Oracle версии 9i не позволяет передавать в FIELD SUBQUERY поля из внешнего запроса, если глубина вложения FIELD SUBQUERY больше 1. То есть такой, казалось бы, естественный запрос:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
SELECT	(
	SELECT	rrate
	FROM	(
		SELECT	rate
		FROM	rates r
		WHERE	r.rcurrency = x.xcurrency
			AND r.rdate <= x.xdate
		ORDER BY
			r.rdate DESC
		)
	WHERE	rownum =  1 
FROM	transactions x

приведёт к ошибке ORA-00904: недопустимый идентификатор .
Inline view не может быть корелированным, и не только в 9-ке, а и в более поздних версиях. Правда, в 10.2.0.1 это разрешалось, что похоже на баг.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #36427263
Inline viewКвасной
К сожалению, Oracle версии 9i не позволяет передавать в FIELD SUBQUERY поля из внешнего запроса, если глубина вложения FIELD SUBQUERY больше 1. То есть такой, казалось бы, естественный запрос:

Код: plaintext
\nSELECT\t(\n\tSELECT\trrate\n\tFROM\t(\n\t\tSELECT\trate\n\t\tFROM\trates r\n\t\tWHERE\tr.rcurrency = x.xcurrency\n\t\t\tAND r.rdate <= x.xdate\n\t\tORDER BY\n\t\t\tr.rdate DESC\n\t\t)\n\tWHERE\trownum =  1 \nFROM\ttransactions x\n

приведёт к ошибке ORA-00904: недопустимый идентификатор .
Inline view не может быть корелированным, и не только в 9-ке, а и в более поздних версиях. Правда, в 10.2.0.1 это разрешалось, что похоже на баг.

Констатация известных фактов.
(демонстрация потенциальной конструкции [не работающей в Oracle] которая могла бы решить проблему)

А проблема в следующем:

КваснойНу-с, вот обещанные трейсы.

В таблице transactions около 1 600 000 строк;

В таблице rates около 25 000 строк;

Селективность индекса ux_rates_currency_date по полю currency — около 8% , т. е. около 2 000 строк по каждой валюте.

В целях ускорения запроса выборка велась по первым 9 999 строкам из transactions . Результаты агрегировались и по ним считалась сумма.

Мой запрос работал 0,40 сек.
Запрос, предложенный тов. "Splain", работал 10,64 сек.
Запрос тов. "Владимира Бегуна" работал 34,53 сек.
Запрос тов. "Владимира Бегуна" с хинтом работал 34,04 сек.

Общую сумму по всей таблице transactions ( 1 600 000 строк) мой запрос считает около 25 сек.


НО САМЫЙ БЫСТРЫЙ ВАРИАНТ

Код: plaintext
SQL> SET AUTOTRACE ON EXPL\nSQL> SELECT  (\n   2   \t     SELECT  /*+ INDEX_DESC (r ux_rate_currency_date) */\n   3   \t\t     rrate\n   4   \t     FROM    rates r\n   5   \t     WHERE   r.rcurrency = x.xcurrency\n   6   \t\t     AND r.rdate <= x.xdate\n   7   \t\t     AND rownum =  1 \n   8   \t     ) AS eff_rate\n   9   FROM    transactions x\n  10   /

ТОЖЕ С БАГОМ - без order by НЕТ гарантии что возьмётся нужная строка.

ИТОГО: нормального решения для такого запроса нет до сих пор.
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #36427917
Быдло__кодер
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
select t.rrate from
  (SELECT  r.rrate, row_number() over (partition by x.rowid order by r.rdate desc) rn
    FROM  rates r, transactions x
    WHERE  r.rcurrency = x.xcurrency
      AND r.rdate <= x.xdate ) t
where t.rn= 1       
Не катит?
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #36430237
AAAx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Какова скорость варианта в пред. посте?
...
Рейтинг: 0 / 0
Выборка уникальных значений из хронологической таблицы
    #36432531
kepka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Кстати, в случае если использовать функцию и в ней запрос с order by, то Oracle делает RANGE SCAN DESCENDING:

Код: 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.
SQL> select rrate
   2       /* into Result */
   3       from (select rt.rrate
   4               from rates rt
   5              where rt.rdate <= :p
   6                and rt.rcurrency = :cr
   7              order by rt.rdate desc
   8              )
   9      where rownum <=  1 ;

no rows selected


Execution Plan
----------------------------------------------------------                      
    0       SELECT STATEMENT Optimizer=CHOOSE (Cost= 4  Card= 1  Bytes= 13 )            
    1      0    COUNT (STOPKEY)                                                     
    2      1      VIEW (Cost= 4  Card= 100  Bytes= 1300 )                                 
    3      2        TABLE ACCESS (BY INDEX ROWID) OF 'RATES' (Cost= 4  Card=          
           100  Bytes= 3000 )                                                       
                                                                                
    4      3          INDEX (RANGE SCAN DESCENDING) OF 'UX_RATE_CURRENCY_D          
          ATE' (UNIQUE) (Cost= 2  Card= 18 )                                        
                                                                                

и явно запретить использование индекса:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
SQL> select rrate
   2       /* into Result */
   3       from (select /*+ no_index(rt) */ rt.rrate
   4               from rates rt
   5              where rt.rdate <= :p
   6                and rt.rcurrency = :cr
   7              order by rt.rdate desc
   8              )
   9      where rownum <=  1 ;

Execution Plan
----------------------------------------------------------                      
    0       SELECT STATEMENT Optimizer=CHOOSE (Cost= 21  Card= 1  Bytes= 13 )           
    1      0    COUNT (STOPKEY)                                                     
    2      1      VIEW (Cost= 21  Card= 100  Bytes= 1300 )                                
    3      2        SORT (ORDER BY STOPKEY) (Cost= 21  Card= 100  Bytes= 3000 )           
    4      3          TABLE ACCESS (FULL) OF 'RATES' (Cost= 19  Card= 100  Byt          
          es= 3000 )        

В первом варианте, сортировка происходит только с участием индекса.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Выборка уникальных значений из хронологической таблицы
    #37210436
Аффтар
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У вас дырко в безопансоти?
ХАКККККККККККККККККККК
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Выборка уникальных значений из хронологической таблицы
    #39445552
Andrews222000
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Столкнулся с такой же проблемой.

Пробуем к хинту index добавить first_rows(1)

/*+ INDEX_DESC (r ux_rate_currency_date) FIRST_ROWS(1) */

как ни странно, результат выборки у меня поменялся (версия oracle 11.2.0.4.0)
...
Рейтинг: 0 / 0
59 сообщений из 59, показаны все 3 страниц
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Выборка уникальных значений из хронологической таблицы
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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