Расскажите чуть подробнее, пожалуйста, что будет в выступлении про интеграционные тесты с Oracle, чтобы знать будет это мне интересно как ораклисту или нет?
Да и вообще, 300мс — я бы категорически не назвал высокой скоростью, а уж для простенького джойника по 50к «быстро» вообще должно быть где-то в диапазоне 5-15мс…
В Oracle с этим все легко и просто:
1. Можно использовать композитное секционирование, например: интервальное секционирование по датам datetime и подсекции по message. Допустим, каждая секция содержит только одни сутки, и каждая подсекция только свой message. В таком случае индексы вообще будут не нужны, поэтому такой вариант обычно и рекомендуется для логов, т.к. там нагрузка в основном write-only.
2. если лидирующее поле/поля в индексе имеет небольшое количество разных значений и в запросе нет по нему предиката, но есть хороший селективный предикат по второму полю из индекса, то может использоваться Index Skip Scan
Молодцы, хорошая затея! :)
В 7-й задаче, я бы лучше предложил решать через PL/SCOPE, как мне кажется это было бы правильнее, чем самому парсить. Нужно было лишь откомпилить объекты с alter session set PLSCOPE_SETTINGS='IDENTIFIERS:ALL' и смотреть где CALL к нужной процедуре и REFERENCE к нужному пакету совпадают dba_identifiers.usage
Еще мне кажется, что после 8-й задачи 9-я становится лишней и не является оптимальной, т.к. оптимальным должно быть сокращение объемов только до сумм и произведений, например так:
with
-- закомментировал тестовый генератор
--a(n) as (select/*+ cardinality(1000) */ level-1 n from dual connect by level<=1000),
----------------------
-- calc: пошли вычисления
-- аггрегируем уникальные числа, чтобы уменьшить объемы для перебора
x0 as (select n,count(*) cnt from a group by n order by n)
-- за один "урезанный" селф-джойн рассчитываем и суммируем сразу и суммы и произведения:
,x1 as (
select
x.n + y.n as s
,x.n * y.n as m
,2*sum(x.cnt*y.cnt) cnt
from x0 x,x0 y
where y.n>=x.n -- возьмем только один вариант и просто умножим на 2
group by
x.n + y.n
,x.n * y.n
)
-- тут уже объем для перебора становится практически минимальным:
select sum(x1.cnt*x2.cnt) total
from x1,x1 x2
where x1.s=x2.m;
C таким вариантом, у меня на такой тестовой табличке:
create table a(n) as select ceil(dbms_random.value(0,500)) n from dual connect by level<=1e4ж
решается за 0.5сек. Если же начать собирать сами комбинации чисел, то объемы и время расчета существенно вырастут. По идее, есть еще эвристики для уменьшения перебора да и оптимизации, например, автоматическое деление на группы диапазонов, но их делать уже будет сложнее и в условиях спешки я бы не стал их заморачиваться
А, понятно, старый добрый start-of-group :) кстати, конкретно этот пример и легче, и быстрее, и понятнее решается с помощью pattern matching:
pattern matching
WITH ALL_DATA AS (
SELECT TO_DATE('01.01.2018 00:00:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 5 SPEED, 0.01 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:01:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 25 SPEED, 0.1 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:02:31', 'DD.MM.YYYY HH24:MI:SS') SDATE, 61 SPEED, 0.3 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:02:58', 'DD.MM.YYYY HH24:MI:SS') SDATE, 68 SPEED, 0.3 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:05:01', 'DD.MM.YYYY HH24:MI:SS') SDATE, 45 SPEED, 0.1 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:06:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 25 SPEED, 0.1 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:07:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 25 SPEED, 0.1 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:08:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 70 SPEED, 0.9 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:09:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 75 SPEED, 0.9 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:10:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 78 SPEED, 0.9 DISTANCE FROM DUAL
UNION ALL SELECT TO_DATE('01.01.2018 00:11:28', 'DD.MM.YYYY HH24:MI:SS') SDATE, 50 SPEED, 0.1 DISTANCE FROM DUAL
)
, T AS (
SELECT SDATE, SPEED, DISTANCE
, GROUP_NUMBER(CASE WHEN D.SPEED > 60 THEN 1 ELSE 0 END) OVER (ORDER BY D.SDATE) ГР
,dense_rank()over(ORDER BY D.SDATE, CASE WHEN D.SPEED > 60 THEN 1 ELSE 0 END) ГР2
,CASE WHEN SPEED > 60 THEN 1 ELSE 0 END as FLAG
FROM ALL_DATA D
)
select
*
from t
MATCH_RECOGNIZE (
ORDER by SDATE
MEASURES
speeding.SDATE as speeding_start,
last(sdate) as speeding_end,
count(*) as points,
sum(distance) as distance,
(last(sdate)-first(sdate))*24*60 as TIME_MIN,
sum(distance)/nullif((last(sdate)-first(sdate))*24,0) as AVG_SPEED
PATTERN (speeding+)
DEFINE speeding as (speeding.SPEED>60)
)
И это правильно, иначе попробуйте представить себе что должен был бы тогда возвращать SUM()OVER() в следующем запросе:
with o(c, n) as (
select 'A', 1 from dual union all
select 'A', 2 from dual union all
select 'A', 3 from dual union all
select 'B', 1 from dual union all
select 'C', 1 from dual union all
select 'C', 2 from dual union all
select 'C', 2 from dual union all
select 'C', 3 from dual union all
select 'C', 4 from dual
)
SELECT c,n
,sum(n)over(order by c) n_summ
FROM O;
Если бы мы хотели добавить агрегировать и при изменении N то должны были бы и показать/определить порядок сортировки при этой агрегации, например:
Invoked by Oracle as the last step of aggregate computation.
У такого окна изменение LAST_DDL_TIME и есть последний шаг агрегации. Функция-то все-таки агрегатная, если бы она возвращала каждый раз разные значения, это уже не агрегатной функцией было бы.
Кстати, а чем не подошел dense_rank?
dense_rank()OVER (ORDER BY O.LAST_DDL_TIME,O.OBJECT_TYPE) grp
Профакапил апгрейд СУБД до новой версии — и живи как хочешь. Без данных, без всего.
Это как так надо постараться, чтобы данные потерять при апгрейде? Это ж надо еще умудриться не сделать ни холодного, ни горячего бэкапа, не иметь стендбая, да еще и поменять compatibity…
взяли последнюю актуальную с надеждой что содержит в себе последние обновления.
не забывайте, что помимо исправлений, она содержит в себе и очень много нововведений, из-за которых очень повышается риск на новые доселе невиданные баги.
надо открывать саппорт реквест, а не на sql.ru отераться.
одно другому не мешает, поэтому желательно сделать и то, и другое, т.к. с техподдержкой есть шанс прождать пару месяцев в ожидании патча даже для critical SR или не решить свою проблему вообще, а спецы на форуме есть с уровнем гораздо выше средней у техподдержки
Ни разу не встречал когда нужны функции и сам придумать не можешь?
Я не могу использовать уже определенные представления в других представлениях.
Не понял? Почему не можешь?
SQL> with
2 a(a) as (select 1 from dual)
3 ,b(b) as (select * from a)
4 ,c(c) as (select * from b)
5 select *
6* from a,b,c;
A B C
---------- ---------- ----------
1 1 1
Есть, то он есть, но вот работать с ним нельзя, т.к. убожество полное.
Забавно слышать, т.к. в PG возможностей еще меньше…
И кстати, насчет обычных табличных неконвеерных функций: чуть менее месяца назад, я как раз разбирался с тем, что неконвеерные функции ужасно медленно возвращают результаты в SQL, причем настолько, что даже если у вас уже есть такая функция, то будет быстрее, если просто напишите конвеерную функцию-обертку, в которой будете получать весь результат неконвеерной и возвращать через пайплайн: orasql.org/2017/12/13/collection-iterator-pickler-fetch-pipelined-vs-simple-table-functions
«WITH» есть в Oracle, причем он функционально гораздо шире, чем в PostgreSQL. Там сейчас можно даже процедуры и функции размещать.
ЗЫ. Не истины ради, а холивара для в Oracle исторически многое очень хорошо оптимизировано, включая PL/SQL, причем настолько много, что мало кто знает о таких оптимизациях и как они работают, что потом удивляются почему «то же самое» на других СУБД выполняется очень медленно.
У меня пару вопросов сразу возникло:
1. Почему сразу не создали SR c severity 1 + 24*7, а еще лучше сразу звонком в российскую тех.поддержку?
2. Почему не обратились ни на sql.ru, ни в телеграмм канал RuOUG? Там полно высококлассных спецов, которые зачастую помогают решить сложнейшие проблемы и намного быстрее, чем техподдержка
3. Почему выбрали 12.2, а не гораздо более стабильную 12.1.0.2?
4. Как же вы так тестировали, что упустили даже проблему с версией клиента, да и быстрее было бы просто установить SQLNET.ALLOWED_LOGON_VERSION_CLIENT. Кстати, может вы ошиблись с версией ораклового клиента, т.к. дефолтно на 12.2 стоит 11: docs.oracle.com/en/database/oracle/oracle-database/12.2/netrf/parameters-for-the-sqlnet-ora-file.html#GUID-B2908ADF-0973-44A9-9B34-587A3D605BED
Полностью согласен! Когда я был «молод и горяч», в порывах энтузиазма очень сильно перерабатывал. Так и от поведение «Рика» веет молодостью. В последние же лет 5-6 я очень ценю свое время, поэтому предпочитаю обучить и разъяснить коллегам всё как можно более детально, т.к. мне же самому от этого становится намного легче и интереснее работать: снижаем кол-во вопросов по пустякам, разделяем простую работу на большее кол-во сотрудников. Да даже элементарно интереснее общаться с коллегами, когда делишься опытом и они близки к тебе по уровню знаний
Расскажите чуть подробнее, пожалуйста, что будет в выступлении про интеграционные тесты с Oracle, чтобы знать будет это мне интересно как ораклисту или нет?
1. Можно использовать композитное секционирование, например: интервальное секционирование по датам datetime и подсекции по message. Допустим, каждая секция содержит только одни сутки, и каждая подсекция только свой message. В таком случае индексы вообще будут не нужны, поэтому такой вариант обычно и рекомендуется для логов, т.к. там нагрузка в основном write-only.
2. если лидирующее поле/поля в индексе имеет небольшое количество разных значений и в запросе нет по нему предиката, но есть хороший селективный предикат по второму полю из индекса, то может использоваться Index Skip Scan
Ваше решение работает на моем наборе аж 40 сек.
А на наборе от 0 до 9 оно возвращает аж 670 — что это такое, если даже количество сумм равно 249?
И покажите, пожалуйста, ваше решение для 8-й задачи
В 7-й задаче, я бы лучше предложил решать через PL/SCOPE, как мне кажется это было бы правильнее, чем самому парсить. Нужно было лишь откомпилить объекты с alter session set PLSCOPE_SETTINGS='IDENTIFIERS:ALL' и смотреть где CALL к нужной процедуре и REFERENCE к нужному пакету совпадают dba_identifiers.usage
Еще мне кажется, что после 8-й задачи 9-я становится лишней и не является оптимальной, т.к. оптимальным должно быть сокращение объемов только до сумм и произведений, например так:
C таким вариантом, у меня на такой тестовой табличке:
решается за 0.5сек. Если же начать собирать сами комбинации чисел, то объемы и время расчета существенно вырастут. По идее, есть еще эвристики для уменьшения перебора да и оптимизации, например, автоматическое деление на группы диапазонов, но их делать уже будет сложнее и в условиях спешки я бы не стал их заморачиваться
А что именно вы хотите-то? Ваш пример недетерминирован. А из словесного описания функции как раз напрашивается dense_rank.
Если бы мы хотели добавить агрегировать и при изменении N то должны были бы и показать/определить порядок сортировки при этой агрегации, например:
У такого окна изменение LAST_DDL_TIME и есть последний шаг агрегации. Функция-то все-таки агрегатная, если бы она возвращала каждый раз разные значения, это уже не агрегатной функцией было бы.
Кстати, а чем не подошел dense_rank?
Не понял? Почему не можешь?
Забавно слышать, т.к. в PG возможностей еще меньше…
Но иногда, в крайне редких случаях, по производительности лучше использовать PL/SQL, я писал пару примеров тут: orasql.org/2014/02/28/straight-sql-vs-sql-and-plsql
И кстати, насчет обычных табличных неконвеерных функций: чуть менее месяца назад, я как раз разбирался с тем, что неконвеерные функции ужасно медленно возвращают результаты в SQL, причем настолько, что даже если у вас уже есть такая функция, то будет быстрее, если просто напишите конвеерную функцию-обертку, в которой будете получать весь результат неконвеерной и возвращать через пайплайн: orasql.org/2017/12/13/collection-iterator-pickler-fetch-pipelined-vs-simple-table-functions
ЗЫ. Не истины ради, а холивара для в Oracle исторически многое очень хорошо оптимизировано, включая PL/SQL, причем настолько много, что мало кто знает о таких оптимизациях и как они работают, что потом удивляются почему «то же самое» на других СУБД выполняется очень медленно.
1. Почему сразу не создали SR c severity 1 + 24*7, а еще лучше сразу звонком в российскую тех.поддержку?
2. Почему не обратились ни на sql.ru, ни в телеграмм канал RuOUG? Там полно высококлассных спецов, которые зачастую помогают решить сложнейшие проблемы и намного быстрее, чем техподдержка
3. Почему выбрали 12.2, а не гораздо более стабильную 12.1.0.2?
4. Как же вы так тестировали, что упустили даже проблему с версией клиента, да и быстрее было бы просто установить SQLNET.ALLOWED_LOGON_VERSION_CLIENT. Кстати, может вы ошиблись с версией ораклового клиента, т.к. дефолтно на 12.2 стоит 11:
docs.oracle.com/en/database/oracle/oracle-database/12.2/netrf/parameters-for-the-sqlnet-ora-file.html#GUID-B2908ADF-0973-44A9-9B34-587A3D605BED