Параллелить Exadata не особо выгодно. Дисковое пространство то одно на всех! А если объединить дисковое пространство 2-х стоек (позволяется ли это Exadata — не знаю?), то все упрется в производительность сети 40Гигабит между стойками. Вернее, стойка 1 будет иметь быстрый и широкий доступ к своим винтам, но медленный к винтам стойки 2, и наоборот.
Во-первых, есть такая штука как Exadata storage expansion.
Во-вторых, Оракл вполне разумно параллелит запросы, поэтому не будет передавать все с сервера на сервер при параллельном запросе таком как count(*) from big_table. Будут переданы только готовые агрегаты от каждого parallel slave. Вообще оптимизатор Оракла — это отдельная песня: до сих пор иногда удивляюсь когда гляжу на то, что понапишут разрабы и как прекрасно оракл с этим справляется.
Кроме того вы не учитываете, что в Exadata и SuperCluster сторадж селлы «умные».
И вы нарочно не используете в сравнении возможности Oracle 12.1.0.2?
1. Какой, к чертям, склад? может сначала таки «въехать в тему» прежде чем писать? кто его уговаривал? да кому нахрен нужно было уговаривать? отца судили вообще без показаний мальчика.
2. не надо бреда. убийство детей в то время «условно-нормальным» не было.
3. вы говорите глупость, связывая разные совершенно вещи, не зная подоплеки. И не пытайтесь оголтело вешать дебильные ярлыки.
1. Отец бросил семью.
Нужно ли детям промывать мозги, чтобы считать «отца» сволочью? Какая доверчивость? Что за ересь…
2. Родственники убили двух маленьких мальчиков
«Отца» помог посадить один сын, а родственники убили и его, и за компанию 8-летнего братишку. Нормально?
он, почему-то, замечает только одну устойчивую связь
Я как раз вижу картину шире, а не «замечаю только одну устойчивую связь» — сдать «отца».
Перечитал свой 4-й пункт и понял, что неясно выразился: на самом деле нет никакой 10-кратной разницы и на исходном объеме данных, т.е на 20 тысячах. Наоборот, разница будет проявляться с увеличением кол-ва данных. Проверьте на разных данных: на паре миллионов, на разном кол-ве и распределении записей по клиентам, и тд…
Честно говоря, вам еще учиться и учиться. Советую читать почаще оракловые форумы, например OTN и SQL.RU. Там вы научитесь делать правильные и удобные тест-кейсы и, самое главное, правильно их анализировать.
Полный разбор сейчас делать мне некогда, поэтому пробегусь бегло по некоторым наиболее важным вещам. Потом если захотите задать какие-либо вопросы — можете написать мне на почту.
1. Старайтесь избегать создания лишних объектов (а триггеры вообще старайтесь никогда не создавать) и максимально упрощать тест-кейс.
Например, можно было бы сделать так:
drop table habr_test_table purge;
/*создаем табличку*/
create table habr_test_table
(
oper_id
,client_id
,input_date
,amount
,constraint habr_test_table_pk primary key (oper_id)
)
as
select
rownum
,trunc(dbms_random.value (1, 11))
,to_date(trunc(dbms_random.value(to_char(date '2013-01-01','j'),to_char(date '2013-12-31','j'))),'j')
,trunc (dbms_random.value (1, 100000))
from dual
connect by level<=50000;
-- Добавим дубли
insert into habr_test_table(oper_id,client_id,input_date,amount)
select rownum+50000,client_id,input_date,amount from habr_test_table;
commit;
call dbms_stats.gather_table_stats(user,'HABR_TEST_TABLE');
2. Собирайте всегда статистику, чтобы на выполнение запросов не влиял dynamic_sampling.
3. Реальные планы не надо показывать через DBMS_SQLTUNE.REPORT_TUNING_TASK. Лучше показывать через dbms_xplan.display_cursor с параметром 'allstats last', или отчет dbms_sqltune.report_sql_monitor, ну или трассировку(что немного более геморройно). И лучше в текстовом виде.
А в идеале, готовить тестовый скрипт для sql*plus(командное окно PL/SQL developer`а в принципе это тоже умеет).
Например:
set echo on serverout off feed on timing on;
spool tests_habr.sql
-- ! on test db only !
alter system flush shared_pool;
alter session set "_optimizer_use_feedback"=false;
alter session set statistics_level=all;
-- 2 max:
select/*+ findme 1 */ * from
(
select c.*
, max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
from
(
select t.*
, max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
from habr_test_table t
) c
where c.m_a = c.amount
) where m_o = oper_id;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
-- 2 dense_rank:
select/*+ findme 2 */ * from
(
select c.*
, dense_rank() over (partition by c.client_id order by c.oper_id desc) as m_o/*max_operation*/
from
(
select t.*
, dense_rank() over (partition by t.client_id order by t.amount desc) as m_a/*max_amount*/
from habr_test_table t
) c
where c.m_a = 1
) where m_o = 1;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
-- 2 max + order by:
select/*+ findme 3 */ * from
(
select c.*
, max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
from
(
select t.*
, max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
from habr_test_table t
order by t.client_id
) c
where c.m_a = c.amount
) where m_o = oper_id;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
-- 1 row_number:
select/*+ findme 4 */ * from
(
select t.*
, row_number() over (partition by t.client_id order by t.amount desc, t.oper_id desc) as rn
from habr_test_table t
) where rn = 1;
select * from table(dbms_xplan.display_cursor('','','allstats last'));
select
substr(sql_text,1,18) as text
,sql_id
,elapsed_time
,s.cpu_time
,s.user_io_wait_time
,s.BUFFER_GETS
,s.executions
from v$sql s
where s.sql_text like 'select/*+ findme %'
order by 1;
spool off;
set echo off timing off;
4. У вас сомнительные данные с сомнительными выводами. Вообще для такого типа запросов очень важен объем данных. Например, на 100 тысячах записей нет никакой 10-кратной разницы.
Вот кусок вывода того скрипта, что я привел выше:
Все отклонения в пределах нормы. Советую еще протрассировать с ивентом 10032 — это sort trace. Там вы увидите разницу в кол-ве сравнений и используемой для этого памяти.
5. На самом деле, достаточно было одной аналитической функции, а так как у вас еще и уникальный oper_id, то лучше вообще row_number(в моем скрипте это пример №4)
-- 1 row_number:
select/*+ findme 4 */ * from
(
select t.*
, row_number() over (partition by t.client_id order by t.amount desc, t.oper_id desc) as rn
from habr_test_table t
) where rn = 1;
Ну не надо необоснованной категоричности. Мартин все-таки не профессиональный психолог, и излагает лишь свое мнение, неподкрепленное серьезными всесторонними исследованиями. Почитайте лучше по ссылкам с википедии: en.wikipedia.org/wiki/Flow_(psychology)
Забавный минус :)
Удаляй пакет и делаю мвью просто по запросу:
select
connect_by_root id as object_id
,connect_by_root name as object_name
,connect_by_root type as object_type
,id as parent_id
,name as parent_name
,type as parent_type
,level-1 as nesting_level
from object o
connect by PRIOR parent_id = id
order by id, nesting_level
133 символа:
потом как-нибудь еще попилю)
Во-первых, есть такая штука как Exadata storage expansion.
Во-вторых, Оракл вполне разумно параллелит запросы, поэтому не будет передавать все с сервера на сервер при параллельном запросе таком как count(*) from big_table. Будут переданы только готовые агрегаты от каждого parallel slave. Вообще оптимизатор Оракла — это отдельная песня: до сих пор иногда удивляюсь когда гляжу на то, что понапишут разрабы и как прекрасно оракл с этим справляется.
Кроме того вы не учитываете, что в Exadata и SuperCluster сторадж селлы «умные».
И вы нарочно не используете в сравнении возможности Oracle 12.1.0.2?
не совсем, но я это сделал буквально через несколько минут)
2. не надо бреда. убийство детей в то время «условно-нормальным» не было.
3. вы говорите глупость, связывая разные совершенно вещи, не зная подоплеки. И не пытайтесь оголтело вешать дебильные ярлыки.
Нужно ли детям промывать мозги, чтобы считать «отца» сволочью? Какая доверчивость? Что за ересь…
2. Родственники убили двух маленьких мальчиков
«Отца» помог посадить один сын, а родственники убили и его, и за компанию 8-летнего братишку. Нормально?
Я как раз вижу картину шире, а не «замечаю только одну устойчивую связь» — сдать «отца».
(в более удобном виде: gist.github.com/xtender/11281007 )
Полный разбор сейчас делать мне некогда, поэтому пробегусь бегло по некоторым наиболее важным вещам. Потом если захотите задать какие-либо вопросы — можете написать мне на почту.
1. Старайтесь избегать создания лишних объектов (а триггеры вообще старайтесь никогда не создавать) и максимально упрощать тест-кейс.
Например, можно было бы сделать так:
2. Собирайте всегда статистику, чтобы на выполнение запросов не влиял dynamic_sampling.
3. Реальные планы не надо показывать через DBMS_SQLTUNE.REPORT_TUNING_TASK. Лучше показывать через dbms_xplan.display_cursor с параметром 'allstats last', или отчет dbms_sqltune.report_sql_monitor, ну или трассировку(что немного более геморройно). И лучше в текстовом виде.
А в идеале, готовить тестовый скрипт для sql*plus(командное окно PL/SQL developer`а в принципе это тоже умеет).
Например:
4. У вас сомнительные данные с сомнительными выводами. Вообще для такого типа запросов очень важен объем данных. Например, на 100 тысячах записей нет никакой 10-кратной разницы.
Вот кусок вывода того скрипта, что я привел выше:
Все отклонения в пределах нормы. Советую еще протрассировать с ивентом 10032 — это sort trace. Там вы увидите разницу в кол-ве сравнений и используемой для этого памяти.
5. На самом деле, достаточно было одной аналитической функции, а так как у вас еще и уникальный oper_id, то лучше вообще row_number(в моем скрипте это пример №4)
делаюделай мвью просто по запросу:Удаляй пакет и делаю мвью просто по запросу: