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

Откуда:
Сообщений: 23
В таблице строки:

MK~RU_AR~ZEN_MB~CKONE_CN~ADFORM_CP~3301071970_CI~FY22Q1-RU-CK-CKON-NK-NO_OB~AWA_IT~SOC_OB~AWA_TG~DEMINT_PB~VK_AS~VK_BT~AUCTION_CH~VIDEO_RA~CPM_FM~VID_DT~CROSS_SZ~1X1_TS~ADU_ST~FILGEO_AD~STAND_PK~REA_AV~BEA_PD~PPV-123895_VV~NONE_PI~123895_ID~GLD0009ADF__MB~CKONE_FM~VID_CS~1X1_CV~PPV-123895_FF~CPM__

MK~RU_AR~ZEN_MB~GUCCIFLRA_CN~ADFORM_CP~3301061855_CI~FY22Q1-RU-GU-GUGF-NK-NO_OB~AWA_IT~RON_OB~AWA_TG~DEMINT_PB~MEGOGO_AS~NONE_BT~PROG_CH~VIDEO_RA~CPM_FM~VID_DT~CROSS_SZ~1X1_TS~ADU_ST~FILGEO_AD~ST_PK~REA_AV~BEA_PD~MEGOGO-BRANDING-123118-LE_VV~NONE_PI~123118_ID~GLD00098E1__MB~GUCCIFLRA_FM~VID_CS~1X1_CV~MEGOGO-BRANDING-123118-LE_FF~LETU__

Надо отобрать числа по маске : '(\D|^)(\d{5,6})(\D|$)' записав в строку через разделитель ';' без повторений,

Написал функцию, но она работает медленно на большом колличестве данных.

create or replace FUNCTION get_distinct_dbs (
  p_dbs_list    IN  VARCHAR2
) RETURN varchar2 DETERMINISTIC
AS
  p_result      varchar2(32767);
BEGIN
select listagg(dbs_distinct, ';')  Within Group (Order By dbs_distinct) into p_result
from 
(Select distinct regexp_substr(regexp_replace(upper(p_dbs_list), '(CR\d{6})|(\D)', '__'), '(\D|^)(\d{5,6})(\D|$)', 1, LEVEL, 'i', 2) dbs_distinct
                         From dual
                         Where 1 = 1
                         Connect By LEVEL <= regexp_count(upper(p_dbs_list),'(\D|^)(\d{5,6})(\D|$)'))

;
  RETURN p_result;
END;


Как написать быструю детерминированную функцию используя pl sql ?
11 ноя 21, 19:32    [22394803]     Ответить | Цитировать Сообщить модератору
 Re: Как улучшить детерминированную функцию при парсере строки ?  [new]
Dubanos_II
Member

Откуда:
Сообщений: 6
максим_1991,

если вам необходима именно функция заданной сигнатуры, можно попробовать отказаться от регулярок

Например, так (и это всё еще отнюдь не оптимальный код):
create or replace function my_dbs(
    p_dbs in varchar2
) return varchar2 deterministic as
    c_minlen        integer := 5;
    c_maxlen        integer := 6;
    
    type values_t is table of varchar2(1 char) index by varchar2(10 char);
    
    t_values                values_t := values_t();

    l_ret                   varchar2(4000 char);
    l_char                  varchar2(1 char);
    l_buffer                varchar2(10 char);
    l_idx                   varchar2(10 char);
    l_is_possible_match     boolean := true;
begin
    for i in 1..length(p_dbs)
    loop
        l_char := substr(p_dbs, i, 1);
        if nvl(length(replace(translate(l_char, '0123456789', rpad(chr(1), 10, chr(1))), chr(1))), 0) = 0
        then -- char is number
            if l_is_possible_match and nvl(length(l_buffer),0) < c_maxlen
            then
                l_buffer := l_buffer || l_char;
            else
                l_buffer := '';
                l_is_possible_match := false;
            end if;
        else --char is not number
            if l_is_possible_match and nvl(length(l_buffer),0) >= c_minlen
            then
                t_values(l_buffer) := 'x';
                l_buffer := '';
            elsif l_is_possible_match and nvl(length(l_buffer),0) < c_minlen
            then
                l_buffer := '';
            else
                l_is_possible_match := true;
            end if;
        end if;
    end loop;
    
    if nvl(length(l_buffer),0) >= c_minlen
    then
        t_values(l_buffer) := 'x';
    end if;
    
    l_idx := t_values.first;
    while (l_idx is not null)
    loop
        l_ret := l_ret || ';' || l_idx;
        l_idx := t_values.next(l_idx);
    end loop;
    
    return ltrim(l_ret, ';');
end;


проверил скриптом
declare
    l_start timestamp with local time zone;
    l_ret   varchar2(4000 char);
begin
    l_start := systimestamp;
    
    for i in 1..1000
    loop
        l_ret := my_dbs('MK~RU_AR~ZEN_MB~CKONE_CN~ADFORM_CP~3301071970_CI~FY22Q1-RU-CK-CKON-NK-NO_OB~AWA_IT~SOC_OB~AWA_TG~DEMINT_PB~VK_AS~VK_BT~AUCTION_CH~VIDEO_RA~CPM_FM~VID_DT~CROSS_SZ~1X1_TS~ADU_ST~FILGEO_AD~STAND_PK~REA_AV~BEA_PD~PPV-123895_VV~NONE_PI~123895_ID~GLD0009ADF__MB~CKONE_FM~VID_CS~1X1_CV~PPV-123895_FF~CPM__');
    end loop;
    
    dbms_output.put_line(l_start - systimestamp);
    
    l_start := systimestamp;
    
    for i in 1..1000
    loop
        l_ret := get_distinct_dbs('MK~RU_AR~ZEN_MB~CKONE_CN~ADFORM_CP~3301071970_CI~FY22Q1-RU-CK-CKON-NK-NO_OB~AWA_IT~SOC_OB~AWA_TG~DEMINT_PB~VK_AS~VK_BT~AUCTION_CH~VIDEO_RA~CPM_FM~VID_DT~CROSS_SZ~1X1_TS~ADU_ST~FILGEO_AD~STAND_PK~REA_AV~BEA_PD~PPV-123895_VV~NONE_PI~123895_ID~GLD0009ADF__MB~CKONE_FM~VID_CS~1X1_CV~PPV-123895_FF~CPM__');
    end loop;
    
    dbms_output.put_line(l_start - systimestamp);
end;


получил:
Statement processed.
-000000000 00:00:00.000996000
-000000000 00:00:00.003733000


альтернативный вариант - реализовать обработку всех имеющихся строк в одном SQL-запросе. Выиграете на переключении контекста и за счет внутренних механизмов оптимизации
11 ноя 21, 22:45    [22394857]     Ответить | Цитировать Сообщить модератору
 Re: Как улучшить детерминированную функцию при парсере строки ?  [new]
максим_1991
Member

Откуда:
Сообщений: 23
Dubanos_II, Благодарю Вас )
15 ноя 21, 11:29    [22396087]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить