"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" GET DRAMATIC SPEED INCREASES """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" PRODUCT : R:BASE VERSION : 3.1 CATEGORY : PROGRAMMING SUBCATEGORY : TOOLS """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" By modifying your R:BASE 3.1 programs, you may be able to attain phenomenal increases in speed. The Key to Speed """""""""""""""" The key to faster applications is a willingness to experiment. Each new attempt brings new knowledge. That's how we discovered the following tips. Reduce Code - Think Global """""""""""""""""""""""""" Reduce the code by using a global command like INSERT, UPDATE, SELECT, or CREATE VIEW instead of using a program that goes row by row through the data. You may be able to replace an entire program with a single global command. Global commands operate on all the rows in a single pass, so they're faster. If you must use a program, you can still reduce the code by taking full advantage of the SQL SELECT clause in the SELECT, INSERT, CREATE VIEW, and DECLARE CURSOR commands. A single SELECT clause can group rows with GROUP BY, summarize data with SELECT functions, append values together with UNION SELECT, and join tables together. You may not need a program. For example, a single INSERT command can group by department and employee, compute a count and sum, and save the result in another table: INSERT INTO summary + (deptid, empid, totnum, sumcosts) + SELECT deptid, empid, (COUNT(*)), + (SUM(costs)) FROM depts + GROUP BY deptid, empid Optimize DECLARE CURSOR """"""""""""""""""""""" When you must go row by row with a DECLARE CURSOR structure, optimize the DECLARE CURSOR command to do as much of the work as possible. Even if you fold just one of the WHILE-loop commands into the SELECT clause on the DECLARE CURSOR, you'll eliminate hundreds of commands - for example, if you have 1,000 rows, you'll eliminate 1,000 commands. See "Get More Out of a Single DECLARE CURSOR Command" in this issue for an example. Correct DECLARE CURSOR Format """"""""""""""""""""""""""""" Never put DECLARE CURSOR in a WHILE loop. To use a multi-level DECLARE CURSOR structure, put the OPEN command in the WHILE loop, and put all DECLARE CURSORs above the WHILE loop, as in this example: SET VAR vcustid INTEGER = 0 DECLARE c1 CURSOR FOR + SELECT custid FROM customer + ORDER BY custid DECLARE c2 CURSOR FOR + SELECT transid FROM transmaster + WHERE custid = .vcustid OPEN c1 FETCH c1 INTO vcustid IND ivcustid WHILE SQLCODE <> 100 THEN OPEN c2 FETCH c2 INTO vtransid WHILE SQLCODE <> 100 THEN *( ...Commands using VTRANSID...) FETCH c2 INTO vtransid ENDWHILE CLOSE c2 *( ...Commands using VCUSTID...) FETCH c1 INTO vcustid IND ivcustid ENDWHILE DROP CURSOR c1 DROP CURSOR c2 Make sure all your multi-level DECLARE CURSORs are built like this. Add SQL to Converted Applications """"""""""""""""""""""""""""""""" If you converted an application from an earlier version of R:BASE, optimize it. The converter that came with your new R:BASE version didn't optimize your code. To speed up your converted applications, eliminate SET POINTER routines. Replace them with global SQL commands if you can. If you must continue to go row by row, convert all SET POINTERs and R:BASE 2.11 DECLARE CURSORs to R:BASE 3.1 DECLARE CURSOR structures. Use Indexes to Find a Few Rows """""""""""""""""""""""""""""" Indexes can quickly find a few rows in a table that has thousands of rows. For example, to use a form to edit five rows in a table (CUST) that has 6,000 rows, you might use this command: EDIT USING custform WHERE cid IN (3557, 3560, 3472, 3545, 3556) But R:BASE doesn't use indexes with the IN or OR operator. Instead, R:BASE searches row by row through the table sequentially. If the table had 100 rows and you wanted 10 of them, a sequential search would be fast, so you'd want to use the IN operator. But if you only want a few rows out of thousands, an indexed search is faster, so use UNION SELECT to find the rows: DECLARE c1 CURSOR FOR + SELECT cid FROM cust WHERE cid = 3557 + UNI SEL cid FROM cust WHERE cid = 3560 + UNI SEL cid FROM cust WHERE cid = 3472 + UNI SEL cid FROM cust WHERE cid = 3545 + UNI SEL cid FROM cust WHERE cid = 3556 OPEN c1 FETCH c1 INTO vcid WHILE SQLCODE <> 100 THEN EDIT USING custform WHERE cid = .vcid FETCH c1 INTO vcid ENDWHILE DROP CURSOR c1 This may be up to 10 times faster, but there is a disadvantage; you can't press [F8] and [F7] to move from row to row. You must exit from the form before R:BASE will bring up the next row. But if you can live with this limitation, you may be able to get dramatic speed increases (up to 10 times faster) with UNION SELECT.