Попытка оптимизировать время выполнения этой процедуры 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

1 ответ

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

Другие вопросы по тегам