Обновить
79
Sayan Malakshinov@xtender

FBCS, Oracle ACE, performance tuning expert

93
Подписчики
Отправить сообщение
126:
#!/usr/bin/perl -pla0F'\n'

$c=$F[0];$p[0]='Erdos';$_=Inf;for$i(0..@F){@_=grep{"$_~$p[$i]"=~/(\b\w+\b).*~.*\b\1\b/}@F;$p[$i+1]="@_"=~$c?($_=$i)&last:"@_"}
131:
$c=$F[0];$p[0]='Erdos';$r=Inf;for$i(0..@F){@_=grep{"$_~$p[$i]"=~/(\b\w+\b).*~.*\b\1\b/}@F;$p[$i+1]="@_"=~$c?($r=$i)&last:"@_"}$_=$r
Вспомнил про задачку — допилил 1-е решение :)
133 символа:
#!/usr/bin/perl -pla0F'\n'

$c=$F[0];$p[0]='Erdos';for(@F){$i++;@_=grep{"$_~$p[$i-1]"=~/(\b\w+\b).*~.*\b\1\b/}@F;$p[$i]="@_"=~$c?($r=$i)&last:"@_"}$_=$r?$r-1:Inf

потом как-нибудь еще попилю)
Параллелить Exadata не особо выгодно. Дисковое пространство то одно на всех! А если объединить дисковое пространство 2-х стоек (позволяется ли это Exadata — не знаю?), то все упрется в производительность сети 40Гигабит между стойками. Вернее, стойка 1 будет иметь быстрый и широкий доступ к своим винтам, но медленный к винтам стойки 2, и наоборот.

Во-первых, есть такая штука как Exadata storage expansion.
Во-вторых, Оракл вполне разумно параллелит запросы, поэтому не будет передавать все с сервера на сервер при параллельном запросе таком как count(*) from big_table. Будут переданы только готовые агрегаты от каждого parallel slave. Вообще оптимизатор Оракла — это отдельная песня: до сих пор иногда удивляюсь когда гляжу на то, что понапишут разрабы и как прекрасно оракл с этим справляется.
Кроме того вы не учитываете, что в Exadata и SuperCluster сторадж селлы «умные».
И вы нарочно не используете в сравнении возможности Oracle 12.1.0.2?
еще парочка идей в голове вертится, но уже на потом оставлю…
Тесты не проходят :(
только на одном тесте пробовал — сейчас сил нет :) завтра-послезавтра проверю-отлажу
и вместо $#F можно смело писать @F :)
не совсем, но я это сделал буквально через несколько минут)
$c=$F[0];$p[0]='Erdos';for(@F){$i++;@_=grep{"$_~$p[$i-1]"=~/(\b\w+\b).*~.*\1/}@F;$p[$i]="@_"=~$c?($r=$i)&&last:"@_"}$_=$r||Inf
Попытка раз — 126 символов:
#!/usr/bin/perl -pla0F'\n'
$c=$F[0];$p[0]='Erdos';for$i(1..$#F){@_=grep{"$_~$p[$i-1]"=~/(\b\w+\b).*~.*\1/}@F;$p[$i]="@_"=~$c?($r=$i)&&last:"@_"}$_=$r||Inf
1. Какой, к чертям, склад? может сначала таки «въехать в тему» прежде чем писать? кто его уговаривал? да кому нахрен нужно было уговаривать? отца судили вообще без показаний мальчика.

2. не надо бреда. убийство детей в то время «условно-нормальным» не было.

3. вы говорите глупость, связывая разные совершенно вещи, не зная подоплеки. И не пытайтесь оголтело вешать дебильные ярлыки.
1. Отец бросил семью.
Нужно ли детям промывать мозги, чтобы считать «отца» сволочью? Какая доверчивость? Что за ересь…

2. Родственники убили двух маленьких мальчиков
«Отца» помог посадить один сын, а родственники убили и его, и за компанию 8-летнего братишку. Нормально?

он, почему-то, замечает только одну устойчивую связь
Я как раз вижу картину шире, а не «замечаю только одну устойчивую связь» — сдать «отца».
Ну они, наверное, не json отдавать будут, а дампами базы. Должно намного меньше выйти
Сделал бы на готовом во встроенной java
К слову, сейчас я решал бы сооовсем по-другому…
Глянул ддл мельком — всегда индексируйте внешние ключи во избежание tm-блокировок
Странно, что вы не нашли решение от Тима Холла… я в свое время его немного модифицировал: github.com/xtender/xt_soap
Перечитал свой 4-й пункт и понял, что неясно выразился: на самом деле нет никакой 10-кратной разницы и на исходном объеме данных, т.е на 20 тысячах. Наоборот, разница будет проявляться с увеличением кол-ва данных. Проверьте на разных данных: на паре миллионов, на разном кол-ве и распределении записей по клиентам, и тд…
На всякий случай прикладываю, полученные планы:
(в более удобном виде: gist.github.com/xtender/11281007 )
SQL> -- 2 max:
SQL> select/*+ findme 1 */ * from
  2  (
  3      select c.*
  4          , max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
  5      from
  6          (
  7          select t.*
  8          , max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
  9          from habr_test_table t
 10          ) c
 11      where c.m_a = c.amount
 12  ) where m_o = oper_id;

Plan hash value: 673711813

----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
----------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                 |      1 |        |     10 |00:00:01.02 |     392 |   1151 |    775 |       |       |          |         |
|*  1 |  VIEW                 |                 |      1 |  99720 |     10 |00:00:01.02 |     392 |   1151 |    775 |       |       |          |         |
|   2 |   WINDOW BUFFER       |                 |      1 |  99720 |     20 |00:00:01.02 |     392 |   1151 |    775 |  2048 |  2048 | 2048  (0)|         |
|*  3 |    VIEW               |                 |      1 |  99720 |     20 |00:00:01.02 |     392 |   1151 |    775 |       |       |          |         |
|   4 |     WINDOW SORT       |                 |      1 |  99720 |    100K|00:00:00.97 |     392 |   1151 |    775 |  3519K|   815K| 1179K (1)|    5120 |
|   5 |      TABLE ACCESS FULL| HABR_TEST_TABLE |      1 |  99720 |    100K|00:00:00.08 |     381 |    376 |      0 |       |       |          |         |
----------------------------------------------------------------------------------------------------------------------------------------------------------

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

   1 - filter("M_O"="OPER_ID")
   3 - filter("C"."M_A"="C"."AMOUNT")


SQL> -- 2 dense_rank:
SQL> select/*+ findme 2 */ * from
  2  (
  3      select c.*
  4          , dense_rank() over (partition by c.client_id order by c.oper_id desc) as m_o/*max_operation*/
  5      from
  6          (
  7          select t.*
  8          , dense_rank() over (partition by t.client_id order by t.amount desc) as m_a/*max_amount*/
  9          from habr_test_table t
 10          ) c
 11      where c.m_a = 1
 12  ) where m_o = 1;

Plan hash value: 331359864

---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
---------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                 |      1 |        |     10 |00:00:00.87 |     394 |    387 |     11 |       |       |          |         |
|*  1 |  VIEW                      |                 |      1 |  99720 |     10 |00:00:00.87 |     394 |    387 |     11 |       |       |          |         |
|*  2 |   WINDOW SORT PUSHED RANK  |                 |      1 |  99720 |     20 |00:00:00.87 |     394 |    387 |     11 |  2048 |  2048 | 2048  (0)|         |
|*  3 |    VIEW                    |                 |      1 |  99720 |     20 |00:00:00.87 |     394 |    387 |     11 |       |       |          |         |
|*  4 |     WINDOW SORT PUSHED RANK|                 |      1 |  99720 |     30 |00:00:00.87 |     394 |    387 |     11 | 92160 | 92160 | 1123K (2)|    1024 |
|   5 |      TABLE ACCESS FULL     | HABR_TEST_TABLE |      1 |  99720 |    100K|00:00:00.09 |     381 |    376 |      0 |       |       |          |         |
---------------------------------------------------------------------------------------------------------------------------------------------------------------

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

   1 - filter("M_O"=1)
   2 - filter(DENSE_RANK() OVER ( PARTITION BY "C"."CLIENT_ID" ORDER BY INTERNAL_FUNCTION("C"."OPER_ID") DESC )<=1)
   3 - filter("C"."M_A"=1)
   4 - filter(DENSE_RANK() OVER ( PARTITION BY "T"."CLIENT_ID" ORDER BY INTERNAL_FUNCTION("T"."AMOUNT") DESC )<=1)


SQL> -- 2 max + order by:
SQL> select/*+ findme 3 */ * from
  2  (
  3      select c.*
  4          , max(c.oper_id) over (partition by c.client_id) as m_o/*max_operation*/
  5      from
  6          (
  7          select t.*
  8          , max(t.amount) over (partition by t.client_id) as m_a/*max_amount*/
  9          from habr_test_table t
 10          order by t.client_id
 11          ) c
 12      where c.m_a = c.amount
 13  ) where m_o = oper_id;

Plan hash value: 673711813

----------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
----------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                 |      1 |        |     10 |00:00:00.93 |     394 |   1284 |    908 |       |       |          |         |
|*  1 |  VIEW                 |                 |      1 |  99720 |     10 |00:00:00.93 |     394 |   1284 |    908 |       |       |          |         |
|   2 |   WINDOW BUFFER       |                 |      1 |  99720 |     20 |00:00:00.93 |     394 |   1284 |    908 |  2048 |  2048 | 2048  (0)|         |
|*  3 |    VIEW               |                 |      1 |  99720 |     20 |00:00:00.93 |     394 |   1284 |    908 |       |       |          |         |
|   4 |     WINDOW SORT       |                 |      1 |  99720 |    100K|00:00:00.88 |     394 |   1284 |    908 |  3519K|   815K| 1123K (2)|    4096 |
|   5 |      TABLE ACCESS FULL| HABR_TEST_TABLE |      1 |  99720 |    100K|00:00:00.07 |     381 |    376 |      0 |       |       |          |         |
----------------------------------------------------------------------------------------------------------------------------------------------------------

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

   1 - filter("M_O"="OPER_ID")
   3 - filter("C"."M_A"="C"."AMOUNT")

SQL> -- 1 row_number:
SQL> select/*+ findme 4 */ * from
  2  (
  3      select t.*
  4      , row_number() over (partition by t.client_id order by t.amount desc, t.oper_id desc) as rn
  5      from habr_test_table t
  6  ) where rn = 1;

Plan hash value: 19323224

-------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
-------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |                 |      1 |        |     10 |00:00:00.76 |     394 |    387 |     11 |       |       |          |         |
|*  1 |  VIEW                    |                 |      1 |  99720 |     10 |00:00:00.76 |     394 |    387 |     11 |       |       |          |         |
|*  2 |   WINDOW SORT PUSHED RANK|                 |      1 |  99720 |     20 |00:00:00.76 |     394 |    387 |     11 | 92160 | 92160 | 1123K (2)|    1024 |
|   3 |    TABLE ACCESS FULL     | HABR_TEST_TABLE |      1 |  99720 |    100K|00:00:00.07 |     381 |    376 |      0 |       |       |          |         |
-------------------------------------------------------------------------------------------------------------------------------------------------------------

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

   1 - filter("RN"=1)
   2 - filter(ROW_NUMBER() OVER ( PARTITION BY "T"."CLIENT_ID" ORDER BY INTERNAL_FUNCTION("T"."AMOUNT") DESC ,INTERNAL_FUNCTION("T"."OPER_ID") DESC
              )<=1)


Честно говоря, вам еще учиться и учиться. Советую читать почаще оракловые форумы, например 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.
call dbms_stats.gather_table_stats(user,'HABR_TEST_TABLE');

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-кратной разницы.
Вот кусок вывода того скрипта, что я привел выше:
TEXT                 SQL_ID        ELAPSED_TIME   CPU_TIME USER_IO_WAIT_TIME BUFFER_GETS EXECUTIONS
-------------------- ------------- ------------ ---------- ----------------- ----------- ----------
select/*+ findme 1   6swypwnq6kxvy      1052892     920000            120803         454          1
select/*+ findme 2   0dgjzaawppasx       883205     860000             10838         394          1
select/*+ findme 3   am5gh1pxv4d43       940052     840000            103318         394          1
select/*+ findme 4   cyr7z0c7zq24p       764480     750000             11194         394          1

Все отклонения в пределах нормы. Советую еще протрассировать с ивентом 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

Информация

В рейтинге
Не участвует
Дата рождения
Зарегистрирован
Активность