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
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?