Попытка оптимизировать время выполнения этой процедуры Interbase

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

Этот процесс представляет собой просто процедуру инициализации данных, но в настоящее время его выполнение в базе данных этого клиента занимает до 2 дней. Очевидно, что это невозможно, потому что это выведет их из бизнеса на 2 дня ожидания. Функция запускается из PHONENUM_REFRESH_ALL, которая запускает цикл For для таблицы клиентов, а затем вызывает процедуру, которая соответствующим образом обрабатывает каждую запись. Я вставил обе процедуры ниже.

Откровенно говоря, я пытался использовать Interbase PLANAnalyzer, чтобы попытаться сузить круг задач в этом процессе, но если я прогоняю его так, как если бы я обрабатывал одну запись, это было бы очень быстро. Я не могу найти никаких циклов, которые я мог бы замкнуть или выделить, чтобы ускорить процесс, но у нас есть аналогичный процесс для имен клиентов, и он работает невероятно быстрее, но сопоставление обоих вариантов не дает мне ответа. Есть ли здесь какая-то вопиющая проблема, из-за которой он работает так невероятно медленно?

Основная процедура, которая запускает цикл for.

CREATE PROCEDURE PHONENUM_REFRESH_ALL   AS 
declare variable custid varchar(8);
declare variable KEYWORD varchar(30);
declare variable AREACODE VARCHAR(3);
declare variable PRIMARYTEL VARCHAR(8);
declare variable PRIMARYTELID VARCHAR(8);
declare variable configdefault varchar(8);
begin
  /* 2016-03-16 - Creation */

insert into timetracker(time_stamp) values (cast('NOW' as timestamp));
  for select custid, areacode, primarytel, PRIMARYTELID 
    from customers 
    where (primarytelid || '' is null or primarytelid || '' = '')
    and areacode is not null and areacode <> ''
    and primarytel is not null and primarytel <> ''
    into :custid, :AREACODE, :primarytel,:PRIMARYTELID do
  begin
    select primarytelid from PHONENUM_REFRESH(:CUSTID,:AREACODE,:PRIMARYTEL,'') into :primarytelid;
    update customers set primarytelid = :primarytelid where custid = :custid;
  end
insert into timetracker(time_stamp) values (cast('NOW' as timestamp));   
END

Процедура PHONENUM_REFRESH (обрабатывает одну запись, переданную из главной процедуры).

CREATE PROCEDURE PHONENUM_REFRESH (
  CUSTID VARCHAR(8),
  AREACODE VARCHAR(3),
  PRIMARYTEL VARCHAR(8),
  TRIGG VARCHAR(8)
) RETURNS (
  PRIMARYTELID VARCHAR(8)
) AS 
DECLARE VARIABLE NEWTELID INTEGER;
DECLARE VARIABLE FOUNDTELID VARCHAR(6);
DECLARE VARIABLE BRANCHID VARCHAR(2);
DECLARE VARIABLE DBTYPE CHAR(2);
DECLARE VARIABLE CNT INTEGER;
DECLARE VARIABLE TELNOTE VARCHAR(40);
DECLARE VARIABLE GENTELIDPREFIX varchar(2);

BEGIN
  /* 2013-07-13 V1.0  - Creation. Procedure is binding customer to an existing phonenum (if not bound), creates it if none is matching.
     2015-05-04 V1.1  - If matching primarytel is found, update customer's primarytelid
     2015-07-22 V1.2 - Not updating CUSTOMERS table if called from trigger (TRIGG = 'trIgg')
     2015-08-20 - To add GENTELIDPREFIX for fixing conversion string error with TELID
  */    
  /* CustId mandatory */
  IF ((CUSTID <> '') AND (CUSTID IS NOT NULL)) THEN
  BEGIN
    IF ((TRIGG = '') OR (TRIGG IS NULL)) THEN
      TRIGG = 'SYSDBA';
    /* PRIMARYTELID NOT SET, TRY TO GET ONE */
    IF ((AREACODE <> '') AND (PRIMARYTEL <> '')) THEN
    BEGIN
      SELECT MIN(TELID) FROM PHONENUMS WHERE AREACODE=:AREACODE AND PRIMARYTEL=:PRIMARYTEL AND CUSTID=:CUSTID INTO :PRIMARYTELID;

      SELECT F_LEFT(config_value,1) FROM branch_config WHERE branchid = '00' and config_name = 'GEN_TELID_PREFIX' into :GENTELIDPREFIX;

      /* No PRIMARYTELID found. Go create one with 'PR' */
      IF (PRIMARYTELID IS NULL) THEN 
        PRIMARYTELID = '';

      IF (PRIMARYTELID = '') THEN
      BEGIN
        /* If SF, we force it to use the generators */
        SELECT MIN(DBTYPE) FROM DATABASEID INTO :DBTYPE;
        IF (DBTYPE = 'SF') THEN
        BEGIN
          FOUNDTELID='X';
          BRANCHID='00';
        END
        ELSE
        BEGIN
          SELECT TELID, BRANCHID FROM CTRLFILE WHERE BRANCHID = (SELECT MIN(DBID) FROM DATABASEID) ROWS 1 INTO  :FOUNDTELID,:BRANCHID;
        END

        IF (FOUNDTELID = 'X') THEN
        BEGIN
          SELECT GEN_ID(GENTELID,1) FROM RDB$DATABASE INTO :NEWTELID;

          if ((GENTELIDPREFIX is not null) AND (GENTELIDPREFIX <> '')) then
          BEGIN
            PRIMARYTELID = GENTELIDPREFIX || CAST(NEWTELID AS VARCHAR(7));
          END
          ELSE
          BEGIN
            PRIMARYTELID = BRANCHID || CAST(NEWTELID AS VARCHAR(6));
          END
          TELNOTE = '';
          select count(*) from phonenums where telid = :PRIMARYTELID into :cnt;

          IF (CNT = 1) THEN
          BEGIN
            /* Whaaaaaat? Twilight zone glitch, gotta save the moment! */
            TELNOTE = '(Shifted from telid ' || PRIMARYTELID || ')';
            SELECT GEN_ID(GENTELID,1) FROM RDB$DATABASE INTO :NEWTELID;

            if ((GENTELIDPREFIX is not null) AND (GENTELIDPREFIX <> '')) then
            BEGIN
              PRIMARYTELID = GENTELIDPREFIX || CAST(NEWTELID AS VARCHAR(7));
            END
            ELSE
            BEGIN
              PRIMARYTELID = BRANCHID || CAST(NEWTELID AS VARCHAR(6));
            END
          END
          INSERT INTO PHONENUMS (TELID,PRIMARYTEL,AREACODE,TELTYPE,CUSTID,EDU_,TELNOTE) VALUES(:PRIMARYTELID,:PRIMARYTEL,:AREACODE,'PR',:CUSTID,:TRIGG,:TELNOTE);
        END
        ELSE
        BEGIN
          NEWTELID = CAST(FOUNDTELID AS INTEGER) + 1;
          if ((GENTELIDPREFIX is not null) AND (GENTELIDPREFIX <> '')) then
          BEGIN
            PRIMARYTELID = GENTELIDPREFIX || CAST(NEWTELID AS VARCHAR(7));
          END
          ELSE
          BEGIN
            PRIMARYTELID = BRANCHID || CAST(NEWTELID AS VARCHAR(6));
          END
          INSERT INTO PHONENUMS (TELID,PRIMARYTEL,AREACODE,TELTYPE,CUSTID,EDU_) VALUES(:PRIMARYTELID,:PRIMARYTEL,:AREACODE,'PR',:CUSTID,:TRIGG);
          UPDATE CTRLFILE SET TELID = :NEWTELID WHERE BRANCHID = :BRANCHID;
        END

      END
      ELSE IF (TRIGG <> 'trIgg') THEN
      BEGIN
        UPDATE CUSTOMERS SET PRIMARYTELID = :PRIMARYTELID WHERE CUSTID = :CUSTID;
      END
    END

  END

  SUSPEND;
  END

person Denis    schedule 23.12.2016    source источник


Ответы (1)


Кажется немного глупым вставлять записи в PHONENUMS одну за другой. Разве вы не можете просто написать немного SQL, чтобы прочитать нужные вам записи из CUSTOMERS и вставить их за один проход вместе с некоторой формой генерации идентификатора? Вы также можете обновить файл CTRL за один проход. Или что мне не хватает?

person john McTighe    schedule 23.12.2016
comment
Ага, жир можно порезать, CTRL файл на ВЕТКУ, там 50 веток, но 2.5м клиентов, это лишнее. Однако как мне сделать вставку в PHONENUMS за один проход? Каждая вставка имеет идентификатор, который генерируется генератором. Как я могу сохранить потенциально 2,5 миллиона идентификаторов еще до их вставки? Тогда id нужно создать вызов динамической вставки, который передает в него все эти значения? Я понимаю, что вы говорите, но, возможно, не так, как я могу этого добиться - person Denis; 23.12.2016