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

FBCS, Oracle ACE, performance tuning expert

93
Подписчики
Отправить сообщение
В принципе, PL/SQL Developer использует тот же DBMS_PROFILER (кстати, есть еще иерархический профайлер ).
Для большей автоматизации иногда удобнее пользоваться своими запросами к этим же таблицам. Вот рыба для них:
select r.runid
      ,r.related_run
      ,r.run_owner
      ,r.run_date
      ,r.run_comment
      ,r.run_total_time
      ,r.run_system_info
      ,r.run_comment1
      ,u.unit_number
      ,u.unit_type
      ,u.unit_owner
      ,u.unit_name
      ,d.line#
      ,s.TEXT
      ,u.total_time
      ,d.total_occur
      ,d.total_time
      ,d.min_time
      ,d.max_time      
from plsql_profiler_runs r
     join plsql_profiler_data d
          on  r.runid = d.runid
     join plsql_profiler_units u
          on  d.runid = u.runid
          and d.unit_number = u.unit_number
     left join all_source s
          on  u.unit_owner = s.OWNER
          and u.unit_name  = s.NAME 
          and u.unit_type  = s.TYPE 
          and d.line#      = s.LINE
where 1=1
--  and r.run_owner = user -- запуски от текущей юзера
--  and r.runid = (select max(runid) from plsql_profiler_runs where run_owner=user) -- последний запуск
order by r.runid,r.related_run,u.unit_number,d.line#;
Конечно, не работает. Читать пайпы можно только внутри одной ноды, чтобы читать с другой — надо подключаться и к другой ноде тоже.
Оба этих «инструмента» не подходят ни для отладки, ни для логгирования.
Это будет дикий overkill — логгировать инструментами, рассчитанными на синхронную/полусинхронную работу. Особенно, для каких-нибудь bulk-операций да еще и параллельных, да с высокой скоростью обработки — тут же упретесь в ограничения. Да еще и не дает возможности «заглянуть в прошлое».

Ошибся имел ввиду DBMS_debug

Странный выбор… Это больше похоже на логгирование, а не отладку. Для дебага есть как раз plsql_debug, позволяющий устанавливать breakpoint'ы, получать значения переменных и т.д. Кстати, PL/SQL Developer умеет с ним работать, но только для сессий запущенных в нем самом.
А для логгирования лучше использовать что-то более гибкое и стандартное, например, всяческие аналоги логгеров из Java:
github.com/OraOpenSource/Logger
log4plsql.sourceforge.net
А мне у него FlameGraph нравится — классная штука для визуализации проблем.
mkrupenin, подозрительно хорошие у вас результаты для noinmemory. Можно AWR и этого теста? А в идеале ashdump обоих тестов. Я прямо сейчас решил повторить ваш тест с помощью Benchmark factory (15-и дневная trial версия), с вашей же нагрузкой, так у меня noinmemory адско затыкается на direct path reads, и inmemory в несколько раз быстрее.
Пропустил сообщение выше. Можно и мне на почту AWRы?
А отчет AWR есть? У меня сильное подозрение, что у вас слишком много ушло тупо ожидая процессора (CPU queue length смотрели?), т.к. ноут у вас 4-х ядерный, а нагрузку гнали в 8 пользователей, и помимо оракла еще и сам бенчмарк работал, да и еще что-нибудь, наверное. Попробуйте в 2-3 пользователя
В тему про тормоза, обратите внимание на кол-во реду без триггера и с даже просто пустым триггером — http://orasql.org/2016/09/22/how-even-empty-trigger-increases-redo-generation/
1. Как раз описанная вами задача прекрасно решается с fast refresh on commit. Несмотря на всю брутальную кайтовскую категоричность, тут он прав на все 100% — dml триггеры все-таки все-таки это зло, и применяются они только из компромисса, когда уже «слишком дорого и долго» переделывать изначальные архитектурные ошибки.
2. Кроме того, вы же, наверное, понимаете, что таким триггером как у вас описан вы прямо таки нарываетесь на блокировки? Что если несколько сессий попробуют добавлять строки по одному счету?
3. Триггеры реально очень сильно ухудшают производительность и к тому же заставляют сервер генерить больше реду. Сравните свое приведенное решение и нормальное решение где одна процедура будет и обновлять остаток и вставлять записи в таблицу на паре десятков конкурентных процессов в несколько тысяч вставок
4. И, кстати, если триггер написан так что повторный его вызов изменяет его логику, то проблему с рестартами решить в принципе невозможно. Кроме того, не забывайте про нюансы с вызовом тригера при merge.
5. Больше всего пугает ваше доверие к таким данным… Кто и насколько часто потом перепроверяет ваши остатки? А вдруг вы там с рестартами по 3 раза некоторые операции снижения баланса понапроводили?
У меня так получилось:
   select
      concat(
         ifnull(group_concat(if(id-p=1,'',concat(p+1,if(id-p=2,'',concat('-',id-1)),',')) separator ''),'')
        ,max(id)+1,'...')
      s
   from (
         select @p p
               ,@p := id id
         from (
               select 0 id, @rn:=0 rn from dual
               union all
               select id, @rn:=@rn+1  from test
              ) v1
         ) v2

но я не спец по mysql
Если так дотошно не показывать-комментировать, то получится очень кратко:
select listagg(id1||decode(id2
                            ,id1 ,null
                            ,null,'...'
                            ,'-'||id2)
              ,',') 
         within group(order by id1)s
from (select max(id)+1                            id1
            ,lead(min(id)) over(order by min(id)) id2
      from (select 0 id, 0 rn from dual
            union all
            select id,row_number()over(order by id) rn from test)
      group by id - rn)
В Oracle все это можно сделать за один скан.
Объединение диапазонов вообще древняя и широкоизвестная задача и делается кучей разных способов, например так:
select
   listagg(decode(id1,id2,to_char(id1),to_char(id1)||'-'||to_char(id2)),',') 
      within group(order by id1)s -- просто форматирование
from (
     select min(id) id1,max(id) id2  -- это у нас и есть схлопнутые диапазоны, т.е. типа (1,3); (4,4); (7,10)
     from (select id,row_number()over(order by id) rn
           from test)
     group by id - rn -- группируем по дельте от ряда
     )

Соответственно, чтобы найти пропущенные/недостающие, достаточно внести небольшое изменение — после «схлопывания» диапазонов группировкой, вывести диапазоны между ними, используя lead или lag и +-1:
select
   listagg(decode(id2
                 ,id1 ,to_char(id1)
                 ,null,to_char(id1)||'...'
                 ,to_char(id1)||'-'||to_char(id2)
                 )
           ,',') 
      within group(order by id1)s -- просто требуемое форматирование
from (
      select
         id2+1 id1 -- конец предыдущего + 1
        ,lead(id1) over(order by id1)-1 id2 --начало следующего - 1
      from (
           select min(id) id1,max(id) id2 -- это у нас и есть схлопнутые диапазоны, т.е. типа (1,3); (4,4); (7,10)
           from (select 0 id, 0 rn from dual -- добавляем "начало"
                 union all
                 select id,row_number()over(order by id) rn
                 from test)
           group by id - rn
           )
)
Вы вообще сложную бизнес-логику когда-нибудь встречали?
Три разных пользователя вставляют клерков в один отдел одновременн — ваши действия?
Попробуйте реализовать хотя бы ту задачу, что делал автор поста, сделать на апп.сервере с учетом многопользовательской системы и все сами поймете.
Обеспечивать полный ACID в коде промежуточного слоя весьма тяжело и затратно, особенно в больших многопользовательских распределенных системах, так не лучше ли делать то, что умеет RDBMS быстро и эффективно прямо там?
Ну во-первых подход древний(кажется еще Кайт его описывал и уже тогда предлагал вариант получше — с mview log+fast refresh) и с кучей недостатков, например, в сложности зависимостей, громоздкости кода, которая провоцирует на трудноуловимые ошибки, ужасная производительность, но даже в этом древнем подходе такую тяжелую жесть обычно не создают. Учтите, что вы таким подходом фактически превращаете систему в однопользовательскую — два пользователя не смогут одновременно поменять хоть что-то у двух разных сотрудников в разных департаментах, т.к. их коммиты будут ждать друг друга из-за блокировок на MVIEW, да и кол-во генерируемого реду будет просто зашкаливать при мельчайших изменениях… И кстати, подход Кайта в вашем примере будет намного проще — просто fast refresh mview c count(*) по клеркам в разрезе департаментов с check constraint (cnt<=2).
Во-вторых, обычно в таких случаях предпочитают не такую размазанную и тяжелую логику с кучей слабых мест, а уменьшение точек входа — в идеале одной процедуры, которая вносит изменения и вызывает процедуры проверок бизнес-логики. Имхо главные правила — блокируй как можно меньше, не создавай бутылочных горлышек, и конечно принцип KISS/бритва Оккама ...

Информация

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