Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
PranT
Member

Откуда:
Сообщений: 175
Добрый день.

Столкнуля с проблемой относительно медленной работы одной функции, использующей REGEXP_REPLACE.
+
FUNCTION fm(
   pMsg     IN VARCHAR2
  ,p1       IN VARCHAR2
  ,p2       IN VARCHAR2
  ,p3       IN VARCHAR2
  ,p4       IN VARCHAR2
  ,p5       IN VARCHAR2
  ,p6       IN VARCHAR2
  ,p7       IN VARCHAR2
  ,p8       IN VARCHAR2
  ,p9       IN VARCHAR2
) RETURN VARCHAR2
IS
BEGIN
   RETURN
      REGEXP_REPLACE(
         REGEXP_REPLACE(
            REGEXP_REPLACE(
               REGEXP_REPLACE(
                  REGEXP_REPLACE(
                     REGEXP_REPLACE(
                        REGEXP_REPLACE(
                           REGEXP_REPLACE(
                              REGEXP_REPLACE(pMsg,'%s',p1,1,1
                              ),'%s',p2,1,1
                           ),'%s',p3,1,1
                        ),'%s',p4,1,1
                     ),'%s',p5,1,1
                  ),'%s',p6,1,1
               ),'%s',p7,1,1
            ),'%s',p8,1,1
         ),'%s',p9,1,1
      )
   ;      
END fm;


Если "реализовать" код функции напрямую, то работает в 10-12 раз быстрее, чем если делать перевызов. Написал упрощённый вариант данной функции, чтобы сравнить производительность.
+
DECLARE
   vSrcStr1s   VARCHAR2(1000) := 'Arg [%s]';
   vSrcStr1n   VARCHAR2(1000) := 'Arg [%1]';
   --
   vStr     VARCHAR2(1000);
   vCnt     PLS_INTEGER := 10000000;
   -- Переменные учёта времени
   ts       NUMBER;
   te       NUMBER;
   --
   FUNCTION repl(
      pMsg  IN VARCHAR2
      ,p1   IN VARCHAR2
   ) RETURN VARCHAR2 IS
   BEGIN
      RETURN REPLACE(pMsg,'%1',p1);
   END repl;
   --
   FUNCTION xrepl(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN REGEXP_REPLACE(pMsg,'%s',p1,1,1);
   END xrepl;
BEGIN
   DBMS_OUTPUT.put_line('-- REPLACE --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := REPLACE(vSrcStr1n,'%1','001');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   DBMS_OUTPUT.put_line('-- REPL --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := repl(vSrcStr1n, '001');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   DBMS_OUTPUT.put_line('-- REGEXP_REPLACE --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := REGEXP_REPLACE(vSrcStr1s,'%s','001',1,1);
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   DBMS_OUTPUT.put_line('-- XREPL --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := xrepl(vSrcStr1s, '001');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
END;
/


Результаты:
+
-- REPLACE --
Str: Arg [001]
Time: 124
-- REPL --
Str: Arg [001]
Time: 1412
-- REGEXP_REPLACE --
Str: Arg [001]
Time: 123
-- XREPL --
Str: Arg [001]
Time: 8653


Как видно, вызов строкой функции напрямую явно быстрее, чем тот же вызов, обёрнутый другой функцией. Но для REPLACE замедленее не так существенно, как для REGEXP_REPLACE. Если вызывать напрямую, то REPLACE и REGEXP_REPLACE работают примерно одинаково, в то же время "обёрнутые" функции замедляются соотвественно в 10 и 70 раз.

В чём может быть проблема, и как её избежать или хотя бы ослабить?
5 сен 12, 10:07    [13115512]     Ответить | Цитировать Сообщить модератору
 Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
publexus
Member

Откуда: Москва
Сообщений: 955
А зачем regexp_replace, если маска константная? Реализуй последовательно через instr,replace.
5 сен 12, 10:14    [13115551]     Ответить | Цитировать Сообщить модератору
 Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
-2-
Member

Откуда:
Сообщений: 15330
var m varchar2(20)
exec :m := UTL_LMS.FORMAT_MESSAGE('p1=%d and p2=%s', 123, 'абв')
print m

M
-----------------
p1=123 and p2=абв
5 сен 12, 10:55    [13115866]     Ответить | Цитировать Сообщить модератору
 Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
PranT
Member

Откуда:
Сообщений: 175
Нужно заменить первое вхождение маски '%s', а обычный REPLACE такое не умеет. Поэтому и возникла идея использоваться REGEXP_REPLACE.

Попробовал несколько подходов, в том числе обычный REPLACE (только тут пришлось подменить плейс-холдеры на цифровые), REGEXP_REPLACE и подход с использованием INSTR и SUBSTR. Последние два уступают в производительности обычному REPLACE, особенно это касается REGEXP_REPLACE.

Пример:
+
DECLARE
   vSrcStr9s   VARCHAR2(1000) := 'Arg1 [%s] Arg2 [%s] Arg3 [%s] Arg4 [%s] Arg5 [%s] Arg6 [%s] Arg7 [%s] Arg8 [%s] Arg9 [%s]';
   vSrcStr9n   VARCHAR2(1000) := 'Arg1 [%1] Arg2 [%2] Arg3 [%3] Arg4 [%4] Arg5 [%5] Arg6 [%6] Arg7 [%7] Arg8 [%8] Arg9 [%9]';
   --
   vStr     VARCHAR2(1000);
   vCnt     PLS_INTEGER := 1000000;
   --
   -- Переменные учёта времени
   ts       NUMBER;
   te       NUMBER;
   --
   FUNCTION replace_first(pSourceStr IN VARCHAR2, pSearchStr IN VARCHAR2, pReplStr IN VARCHAR2)
   RETURN VARCHAR2
   IS
      vPos  PLS_INTEGER;
   BEGIN
      vPos := INSTR(pSourceStr, pSearchStr);
      IF vPos > 0 THEN
         RETURN SUBSTR(pSourceStr, 1, vPos-1) || pReplStr || SUBSTR(pSourceStr, vPos + LENGTH(pSearchStr));
      ELSE
         RETURN pSourceStr;
      END IF;
   END replace_first;
   --
   FUNCTION fm_replace(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
     ,p2       IN VARCHAR2
     ,p3       IN VARCHAR2
     ,p4       IN VARCHAR2
     ,p5       IN VARCHAR2
     ,p6       IN VARCHAR2
     ,p7       IN VARCHAR2
     ,p8       IN VARCHAR2
     ,p9       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN
         REPLACE(
            REPLACE(
               REPLACE(
                  REPLACE(
                     REPLACE(
                        REPLACE(
                           REPLACE(
                              REPLACE(
                                 REPLACE(pMsg,'%1',p1
                                 ),'%2',p2
                              ),'%3',p3
                           ),'%4',p4
                        ),'%5',p5
                     ),'%6',p6
                  ),'%7',p7
               ),'%8',p8
            ),'%9',p9
         )
      ;      
   END fm_replace;
   --
   FUNCTION fm_regexp_replace(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
     ,p2       IN VARCHAR2
     ,p3       IN VARCHAR2
     ,p4       IN VARCHAR2
     ,p5       IN VARCHAR2
     ,p6       IN VARCHAR2
     ,p7       IN VARCHAR2
     ,p8       IN VARCHAR2
     ,p9       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN
         REGEXP_REPLACE(
            REGEXP_REPLACE(
               REGEXP_REPLACE(
                  REGEXP_REPLACE(
                     REGEXP_REPLACE(
                        REGEXP_REPLACE(
                           REGEXP_REPLACE(
                              REGEXP_REPLACE(
                                 REGEXP_REPLACE(pMsg,'%s',p1,1,1
                                 ),'%s',p2,1,1
                              ),'%s',p3,1,1
                           ),'%s',p4,1,1
                        ),'%s',p5,1,1
                     ),'%s',p6,1,1
                  ),'%s',p7,1,1
               ),'%s',p8,1,1
            ),'%s',p9,1,1
         )
      ;      
   END fm_regexp_replace;
   --
   FUNCTION fm_replace_first(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
     ,p2       IN VARCHAR2
     ,p3       IN VARCHAR2
     ,p4       IN VARCHAR2
     ,p5       IN VARCHAR2
     ,p6       IN VARCHAR2
     ,p7       IN VARCHAR2
     ,p8       IN VARCHAR2
     ,p9       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN
         replace_first(
            replace_first(
               replace_first(
                  replace_first(
                     replace_first(
                        replace_first(
                           replace_first(
                              replace_first(
                                 replace_first(pMsg,'%s',p1
                                 ),'%s',p2
                              ),'%s',p3
                           ),'%s',p4
                        ),'%s',p5
                     ),'%s',p6
                  ),'%s',p7
               ),'%s',p8
            ),'%s',p9
         )
      ;      
   END fm_replace_first;
BEGIN
   DBMS_OUTPUT.put_line('-- fm_replace --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := fm_replace(vSrcStr9n, '001', '002', '003', '004', '005', '006', '007', '008', '009');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   DBMS_OUTPUT.put_line('-- fm_regexp_replace --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := fm_regexp_replace(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   DBMS_OUTPUT.put_line('-- fm_replace_first --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := fm_replace_first(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
END;
/


Результаты:
+
-- fm_replace --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 1158
-- fm_regexp_replace --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 22723
-- fm_replace_first --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 2806


Что интересно, если "напрямую" прописать REPLACE и REGEXP_REPLACE, без обкладки в виде функции, оба подхода дают одинаковую производительность даже на 9 аргументах.

Пример:
+
DECLARE
   vSrcStr4s   VARCHAR2(1000) := 'Arg1 [%s] Arg2 [%s] Arg3 [%s] Arg4 [%s]';
   vSrcStr4n   VARCHAR2(1000) := 'Arg1 [%1] Arg2 [%2] Arg3 [%3] Arg4 [%4]';
   vSrcStr9s   VARCHAR2(1000) := 'Arg1 [%s] Arg2 [%s] Arg3 [%s] Arg4 [%s] Arg5 [%s] Arg6 [%s] Arg7 [%s] Arg8 [%s] Arg9 [%s]';
   vSrcStr9n   VARCHAR2(1000) := 'Arg1 [%1] Arg2 [%2] Arg3 [%3] Arg4 [%4] Arg5 [%5] Arg6 [%6] Arg7 [%7] Arg8 [%8] Arg9 [%9]';
   --
   vStr     VARCHAR2(1000);
   vCnt     PLS_INTEGER := 10000000;
   --
   -- Переменные учёта времени
   ts       NUMBER;
   te       NUMBER;
BEGIN
   DBMS_OUTPUT.put_line('-- REPLACE (9) --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr :=
         REPLACE(
            REPLACE(
               REPLACE(
                  REPLACE(
                     REPLACE(
                        REPLACE(
                           REPLACE(
                              REPLACE(
                                 REPLACE(vSrcStr9n, '%1', '001'
                                 )  , '%2', '002'
                              )  , '%3', '003'
                           )  , '%4', '004'
                        )  , '%5', '005'
                     )  , '%6', '006'
                  )  , '%7', '007'
               )  , '%8', '008'
            )  , '%9', '009'
         )
      ;
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   DBMS_OUTPUT.put_line('-- REGEXP_REPLACE (9) --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr :=
         REGEXP_REPLACE(
            REGEXP_REPLACE(
               REGEXP_REPLACE(
                  REGEXP_REPLACE(
                     REGEXP_REPLACE(
                        REGEXP_REPLACE(
                           REGEXP_REPLACE(
                              REGEXP_REPLACE(
                                 REGEXP_REPLACE(vSrcStr9s, '%s', '001', 1, 1
                                 )  , '%s', '002', 1, 1
                              )  , '%s', '003', 1, 1
                           )  , '%s', '004', 1, 1
                        )  , '%s', '005', 1, 1
                     )  , '%s', '006', 1, 1
                  )  , '%s', '007', 1, 1
               )  , '%s', '008', 1, 1
            )  , '%s', '009', 1, 1
         )
      ;
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
END;
/


Результаты:
+
-- REPLACE (9) --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 144
-- REGEXP_REPLACE (9) --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 141


Не понимаю, с чем может быть связано такое замедление REGEXP_REPLACE?
5 сен 12, 11:38    [13116261]     Ответить | Цитировать Сообщить модератору
 Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
PranT
Member

Откуда:
Сообщений: 175
UTL_LMS.FORMAT_MESSAGE медленнее REPLACE всего в два раза. Похоже, это самый оптимальный вариант. :)

-- fm_replace --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 12157
-- fm_replace_first --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 28362
-- fm_lms --
Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
Time: 25190


Для примера:
+
DECLARE
   vSrcStr9s   VARCHAR2(1000) := 'Arg1 [%s] Arg2 [%s] Arg3 [%s] Arg4 [%s] Arg5 [%s] Arg6 [%s] Arg7 [%s] Arg8 [%s] Arg9 [%s]';
   vSrcStr9n   VARCHAR2(1000) := 'Arg1 [%1] Arg2 [%2] Arg3 [%3] Arg4 [%4] Arg5 [%5] Arg6 [%6] Arg7 [%7] Arg8 [%8] Arg9 [%9]';
   --
   vStr     VARCHAR2(1000);
   vCnt     PLS_INTEGER := 10000000;
   --
   -- Переменные учёта времени
   ts       NUMBER;
   te       NUMBER;
   --
   FUNCTION replace_first(pSourceStr IN VARCHAR2, pSearchStr IN VARCHAR2, pReplStr IN VARCHAR2)
   RETURN VARCHAR2
   IS
      vPos  PLS_INTEGER;
   BEGIN
      vPos := INSTR(pSourceStr, pSearchStr);
      IF vPos > 0 THEN
         RETURN SUBSTR(pSourceStr, 1, vPos-1) || pReplStr || SUBSTR(pSourceStr, vPos + LENGTH(pSearchStr));
      ELSE
         RETURN pSourceStr;
      END IF;
   END replace_first;
   --
   FUNCTION fm_replace(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
     ,p2       IN VARCHAR2
     ,p3       IN VARCHAR2
     ,p4       IN VARCHAR2
     ,p5       IN VARCHAR2
     ,p6       IN VARCHAR2
     ,p7       IN VARCHAR2
     ,p8       IN VARCHAR2
     ,p9       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN
         REPLACE(
            REPLACE(
               REPLACE(
                  REPLACE(
                     REPLACE(
                        REPLACE(
                           REPLACE(
                              REPLACE(
                                 REPLACE(pMsg,'%1',p1
                                 ),'%2',p2
                              ),'%3',p3
                           ),'%4',p4
                        ),'%5',p5
                     ),'%6',p6
                  ),'%7',p7
               ),'%8',p8
            ),'%9',p9
         )
      ;      
   END fm_replace;
   --
   FUNCTION fm_regexp_replace(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
     ,p2       IN VARCHAR2
     ,p3       IN VARCHAR2
     ,p4       IN VARCHAR2
     ,p5       IN VARCHAR2
     ,p6       IN VARCHAR2
     ,p7       IN VARCHAR2
     ,p8       IN VARCHAR2
     ,p9       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN
         REGEXP_REPLACE(
            REGEXP_REPLACE(
               REGEXP_REPLACE(
                  REGEXP_REPLACE(
                     REGEXP_REPLACE(
                        REGEXP_REPLACE(
                           REGEXP_REPLACE(
                              REGEXP_REPLACE(
                                 REGEXP_REPLACE(pMsg,'%s',p1,1,1
                                 ),'%s',p2,1,1
                              ),'%s',p3,1,1
                           ),'%s',p4,1,1
                        ),'%s',p5,1,1
                     ),'%s',p6,1,1
                  ),'%s',p7,1,1
               ),'%s',p8,1,1
            ),'%s',p9,1,1
         )
      ;      
   END fm_regexp_replace;
   --
   FUNCTION fm_replace_first(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
     ,p2       IN VARCHAR2
     ,p3       IN VARCHAR2
     ,p4       IN VARCHAR2
     ,p5       IN VARCHAR2
     ,p6       IN VARCHAR2
     ,p7       IN VARCHAR2
     ,p8       IN VARCHAR2
     ,p9       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN
         replace_first(
            replace_first(
               replace_first(
                  replace_first(
                     replace_first(
                        replace_first(
                           replace_first(
                              replace_first(
                                 replace_first(pMsg,'%s',p1
                                 ),'%s',p2
                              ),'%s',p3
                           ),'%s',p4
                        ),'%s',p5
                     ),'%s',p6
                  ),'%s',p7
               ),'%s',p8
            ),'%s',p9
         )
      ;      
   END fm_replace_first;
   --
   FUNCTION fm_lms(
      pMsg     IN VARCHAR2
     ,p1       IN VARCHAR2
     ,p2       IN VARCHAR2
     ,p3       IN VARCHAR2
     ,p4       IN VARCHAR2
     ,p5       IN VARCHAR2
     ,p6       IN VARCHAR2
     ,p7       IN VARCHAR2
     ,p8       IN VARCHAR2
     ,p9       IN VARCHAR2
   ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN UTL_LMS.FORMAT_MESSAGE(REPLACE(REPLACE(pMsg, '%', '%%'), '%%s', '%s'), p1, p2, p3, p4, p5, p6, p7, p8, p9);
   END fm_lms;
BEGIN
   DBMS_OUTPUT.put_line('-- fm_replace --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := fm_replace(vSrcStr9n, '001', '002', '003', '004', '005', '006', '007', '008', '009');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   /*DBMS_OUTPUT.put_line('-- fm_regexp_replace --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := fm_regexp_replace(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));*/
   --
   DBMS_OUTPUT.put_line('-- fm_replace_first --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := fm_replace_first(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
   --
   DBMS_OUTPUT.put_line('-- fm_lms --');
   ts := DBMS_UTILITY.get_Time;
   FOR i IN 1 .. vCnt LOOP
      vStr := fm_lms(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
   END LOOP;
   te := DBMS_UTILITY.get_Time;
   DBMS_OUTPUT.put_line('Str: '||vStr);
   DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
END;
/
5 сен 12, 12:18    [13116695]     Ответить | Цитировать Сообщить модератору
 Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
PranT
..

Не понимаю, с чем может быть связано такое замедление REGEXP_REPLACE?

а я не понимаю, чего вы не понимаете.
уровень функционала отличается как кирпич от самолёта
5 сен 12, 13:44    [13117582]     Ответить | Цитировать Сообщить модератору
 Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
PranT
Member

Откуда:
Сообщений: 175
Я не понимаю, почему дёргание REPLACE и REGEXP_REPLACE напрямую работает с одинаковой производительностью, а то же самое, завёрнутое внутрь именованного PL/SQL-блока (внутрь функции) работает в 10 раз медленее для REGEXP_REPLACE.
6 сен 12, 06:15    [13121437]     Ответить | Цитировать Сообщить модератору
 Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
Вячеслав Любомудров
Member

Откуда: Владивосток
Сообщений: 18484
Как минимум:
  • переключение контекста
  • разная реализация SQL и PL/SQL функций
  • 6 сен 12, 06:47    [13121446]     Ответить | Цитировать Сообщить модератору
     Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
    -2-
    Member

    Откуда:
    Сообщений: 15330
    PranT
    Я не понимаю
    Отключи дебаг в сессии и включи нативную компиляцию.
    6 сен 12, 08:12    [13121511]     Ответить | Цитировать Сообщить модератору
     Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
    PranT
    Member

    Откуда:
    Сообщений: 175
    -2-, подскажите, пожалуйста, какими командами?
    6 сен 12, 09:15    [13121636]     Ответить | Цитировать Сообщить модератору
     Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
    -2-
    Member

    Откуда:
    Сообщений: 15330
    PranT
    подскажите, пожалуйста, какими командами?
    зависит от версии
    alter session set plsql_debug=false;
    alter session set plsql_optimize_level=3;
    alter session set plsql_code_type=native;
    
    Есть вероятость что как раз при отключенном debug и включенной оптимизации твои тесты не выполняют часть кода на каждый цикл, так как вызов deterministic и параметры не зависят от цикла.
    6 сен 12, 09:44    [13121755]     Ответить | Цитировать Сообщить модератору
     Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
    PranT
    Member

    Откуда:
    Сообщений: 175
    +
    alter session set plsql_debug=false;
    alter session set plsql_optimize_level=2;
    alter session set plsql_code_type=native;
    
    DECLARE
       vSrcStr9s   VARCHAR2(1000) := 'Arg1 [%s] Arg2 [%s] Arg3 [%s] Arg4 [%s] Arg5 [%s] Arg6 [%s] Arg7 [%s] Arg8 [%s] Arg9 [%s]';
       vSrcStr9n   VARCHAR2(1000) := 'Arg1 [%1] Arg2 [%2] Arg3 [%3] Arg4 [%4] Arg5 [%5] Arg6 [%6] Arg7 [%7] Arg8 [%8] Arg9 [%9]';
       --
       vStr     VARCHAR2(1000);
       vCnt     PLS_INTEGER := 1000000;
       --
       -- Переменные учёта времени
       ts       NUMBER;
       te       NUMBER;
       --
       FUNCTION replace_first(pSourceStr IN VARCHAR2, pSearchStr IN VARCHAR2, pReplStr IN VARCHAR2)
       RETURN VARCHAR2
       IS
          vPos  PLS_INTEGER;
       BEGIN
          vPos := INSTR(pSourceStr, pSearchStr);
          IF vPos > 0 THEN
             RETURN SUBSTR(pSourceStr, 1, vPos-1) || pReplStr || SUBSTR(pSourceStr, vPos + LENGTH(pSearchStr));
          ELSE
             RETURN pSourceStr;
          END IF;
       END replace_first;
       --
       FUNCTION fm_replace(
          pMsg     IN VARCHAR2
         ,p1       IN VARCHAR2
         ,p2       IN VARCHAR2
         ,p3       IN VARCHAR2
         ,p4       IN VARCHAR2
         ,p5       IN VARCHAR2
         ,p6       IN VARCHAR2
         ,p7       IN VARCHAR2
         ,p8       IN VARCHAR2
         ,p9       IN VARCHAR2
       ) RETURN VARCHAR2
       IS
       BEGIN
          RETURN
             REPLACE(
                REPLACE(
                   REPLACE(
                      REPLACE(
                         REPLACE(
                            REPLACE(
                               REPLACE(
                                  REPLACE(
                                     REPLACE(pMsg,'%1',p1
                                     ),'%2',p2
                                  ),'%3',p3
                               ),'%4',p4
                            ),'%5',p5
                         ),'%6',p6
                      ),'%7',p7
                   ),'%8',p8
                ),'%9',p9
             )
          ;      
       END fm_replace;
       --
       FUNCTION fm_regexp_replace(
          pMsg     IN VARCHAR2
         ,p1       IN VARCHAR2
         ,p2       IN VARCHAR2
         ,p3       IN VARCHAR2
         ,p4       IN VARCHAR2
         ,p5       IN VARCHAR2
         ,p6       IN VARCHAR2
         ,p7       IN VARCHAR2
         ,p8       IN VARCHAR2
         ,p9       IN VARCHAR2
       ) RETURN VARCHAR2
       IS
       BEGIN
          RETURN
             REGEXP_REPLACE(
                REGEXP_REPLACE(
                   REGEXP_REPLACE(
                      REGEXP_REPLACE(
                         REGEXP_REPLACE(
                            REGEXP_REPLACE(
                               REGEXP_REPLACE(
                                  REGEXP_REPLACE(
                                     REGEXP_REPLACE(pMsg,'%s',p1,1,1
                                     ),'%s',p2,1,1
                                  ),'%s',p3,1,1
                               ),'%s',p4,1,1
                            ),'%s',p5,1,1
                         ),'%s',p6,1,1
                      ),'%s',p7,1,1
                   ),'%s',p8,1,1
                ),'%s',p9,1,1
             )
          ;      
       END fm_regexp_replace;
       --
       FUNCTION fm_replace_first(
          pMsg     IN VARCHAR2
         ,p1       IN VARCHAR2
         ,p2       IN VARCHAR2
         ,p3       IN VARCHAR2
         ,p4       IN VARCHAR2
         ,p5       IN VARCHAR2
         ,p6       IN VARCHAR2
         ,p7       IN VARCHAR2
         ,p8       IN VARCHAR2
         ,p9       IN VARCHAR2
       ) RETURN VARCHAR2
       IS
       BEGIN
          RETURN
             replace_first(
                replace_first(
                   replace_first(
                      replace_first(
                         replace_first(
                            replace_first(
                               replace_first(
                                  replace_first(
                                     replace_first(pMsg,'%s',p1
                                     ),'%s',p2
                                  ),'%s',p3
                               ),'%s',p4
                            ),'%s',p5
                         ),'%s',p6
                      ),'%s',p7
                   ),'%s',p8
                ),'%s',p9
             )
          ;      
       END fm_replace_first;
       --
       FUNCTION fm_lms(
          pMsg     IN VARCHAR2
         ,p1       IN VARCHAR2
         ,p2       IN VARCHAR2
         ,p3       IN VARCHAR2
         ,p4       IN VARCHAR2
         ,p5       IN VARCHAR2
         ,p6       IN VARCHAR2
         ,p7       IN VARCHAR2
         ,p8       IN VARCHAR2
         ,p9       IN VARCHAR2
       ) RETURN VARCHAR2
       IS
       BEGIN
          RETURN UTL_LMS.FORMAT_MESSAGE(REPLACE(REPLACE(pMsg, '%', '%%'), '%%s', '%s'), p1, p2, p3, p4, p5, p6, p7, p8, p9);
       END fm_lms;
    BEGIN
       DBMS_OUTPUT.put_line('-- fm_replace --');
       ts := DBMS_UTILITY.get_Time;
       FOR i IN 1 .. vCnt LOOP
          vStr := fm_replace(vSrcStr9n, '001', '002', '003', '004', '005', '006', '007', '008', '009');
       END LOOP;
       te := DBMS_UTILITY.get_Time;
       DBMS_OUTPUT.put_line('Str: '||vStr);
       DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
       --
       DBMS_OUTPUT.put_line('-- fm_regexp_replace --');
       ts := DBMS_UTILITY.get_Time;
       FOR i IN 1 .. vCnt LOOP
          vStr := fm_regexp_replace(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
       END LOOP;
       te := DBMS_UTILITY.get_Time;
       DBMS_OUTPUT.put_line('Str: '||vStr);
       DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
       --
       DBMS_OUTPUT.put_line('-- fm_replace_first --');
       ts := DBMS_UTILITY.get_Time;
       FOR i IN 1 .. vCnt LOOP
          vStr := fm_replace_first(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
       END LOOP;
       te := DBMS_UTILITY.get_Time;
       DBMS_OUTPUT.put_line('Str: '||vStr);
       DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
       --
       DBMS_OUTPUT.put_line('-- fm_lms --');
       ts := DBMS_UTILITY.get_Time;
       FOR i IN 1 .. vCnt LOOP
          vStr := fm_lms(vSrcStr9s, '001', '002', '003', '004', '005', '006', '007', '008', '009');
       END LOOP;
       te := DBMS_UTILITY.get_Time;
       DBMS_OUTPUT.put_line('Str: '||vStr);
       DBMS_OUTPUT.put_line('Time: '||TO_CHAR(te-ts));
    END;
    /
    


    REGEXP_REPLACE работает медленнее. :)

    session SET altered.
    session SET altered.
    session SET altered.
    anonymous block completed
    
    
    -- fm_replace --
    Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
    Time: 1265
    -- fm_regexp_replace --
    Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
    Time: 22781
    -- fm_replace_first --
    Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
    Time: 3030
    -- fm_lms --
    Str: Arg1 [001] Arg2 [002] Arg3 [003] Arg4 [004] Arg5 [005] Arg6 [006] Arg7 [007] Arg8 [008] Arg9 [009]
    Time: 2469
    
    7 сен 12, 06:46    [13127506]     Ответить | Цитировать Сообщить модератору
     Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
    orawish
    Member

    Откуда: Гадюкино-2 (City)
    Сообщений: 15487
    PranT
    Я не понимаю, почему дёргание REPLACE и REGEXP_REPLACE напрямую работает с одинаковой производительностью, а то же самое, завёрнутое внутрь именованного PL/SQL-блока (внутрь функции) работает в 10 раз медленее для REGEXP_REPLACE.

    кроме того, что вам уже ответили -
    неправда ваша. одинаковой производительности там рядом не лежало.
    регулярусом не только сессию можно уканать, но нередко бывает, что и базу уронить - попробуйте ка это сделать реплейсом
    7 сен 12, 12:35    [13129050]     Ответить | Цитировать Сообщить модератору
     Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
    PranT
    Member

    Откуда:
    Сообщений: 175
    В общем случае, возможно, это так, как вы описываете.

    Для моих простеньких константных выражений аля '%s' времена выполнения циклов с REPLACE и REGEXP_REPLACE примерно совпадают, см. результаты запусков выше. Скрипты я запускал на разных БД, на двух тестовых, на продакшене, и соотношения были всегда одинаковые.
    7 сен 12, 14:46    [13130315]     Ответить | Цитировать Сообщить модератору
     Re: REGEXP_REPLACE тормозит, если обернуть его функцией  [new]
    Vint
    Member

    Откуда: Москва
    Сообщений: 4564
    PranT,
    ты сравни еще забивание гвоздей молотком и микроскопом.. время тоже примерно одно будет...
    7 сен 12, 14:51    [13130353]     Ответить | Цитировать Сообщить модератору
    Все форумы / Oracle Ответить