Trying to optimize the runtime of this Interbase Procedure

57 views Asked by At

The point of this procedure is to refresh and generates ID's per customer in order to speed up the lookup process on the point of sale side of things by adding these ID's into some type of index table called PHONENUMS.

This proc is just a data initialization procedure, but currently takes up to 2 days to run at this client's database. Obviously that's a no-go, because that would put them out of business of 2 days while waiting. The function is run from PHONENUM_REFRESH_ALL, which runs a For loop on the customers table, then calls the procedure that handles each record accordingly. I've pasted both procedures below.

Frankly, I tried using the Interbase PLANAnalyzer to try and narrow down what is the heavy part in this process, but if I run it through as if I was handling a single record, it's really fast. I can't find any loops I can close or single out to speed up the process, but we have a similar process for customer names and it works incredibly faster, yet juxtaposing both side by side does not give me the answer. Is there some glaring issue here that would cause it to run so incredibly slowly?

Master procedure that runs the for loop.

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 procedure (handles a single record passed from the master procedure).

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

There are 1 answers

1
john McTighe On

Seems a bit daft inserting the records into PHONENUMS one-by-one. Can't you just write a bit of SQL to read the records that you need from CUSTOMERS and insert them in one pass along with some form of ID generation? You can update the CTRL file afterwards in one pass too. Or what am I missing?