Sie sind auf Seite 1von 37

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Document Name

Function Name
Title

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

3. SQL Coding Convention


1. Coding Styles
The SQL description style should comply with the following rules in the interest of maintainability.
a. Use upper case capital letters
All description should be written in upper case capital letters including database objects such as the table name, field name, view name and SQL functions.
However, use lower case for variables used in embedded SQL such as bind variables.
* Any field names must not be used as variable names
b. Insert carriage return appropriately to divide lines.
When listing fields, use separate lines for each field and indent appropriately.
Use separate lines for each formula for a WHERE clause
Use separate lines for each table in a FROM clause
Use separate lines for each assignment expression for an UPDATE clause.
However, when there are many lines and the above rules make the program difficult to read, a line saving style can be used.
c.

1/37

Page

Define an alias for each table


However, it is not always necessary in a SQL statement with a single table.
The alias should be defined in the FROM clause. The first table should be called T1 and followed by T2, T3, T4, .etc..
If there are any abbreviation already determined by each application team, those name may be used.

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Document Name

Function Name
Title

Example)
SELECT T1.LASTNAME,
T2.NAME,
MAX(T3.SALARY) BEST_SALARY
FROM EMPLOYEE T1,
COMPANY T2,
SALHISTORY T3
WHERE T1.COMPANYID = T2.COMPANYID
AND T1.EMPID = T3.EMPID
AND T1.HIREDATE > ADD_MONTHS(SYSDATE, -60).....;
UPDATE EMPLOYEE
SET HIREDATE = SYSDATE,
TERMDATE = NULL
WHERE DEPTID = 105;
INSERT INTO EMPLOYEE
(EMPID,.....)
VALUES (105,....);

d.

2/37

Page

The field names should be described as table_name.field_name format.


However, it is not always necessary in a SQL statement with a single table.

e.

Confirm the execution plan to determine the order of the table association.

f.

Reserved words for nodes in DML statements should be aligned to the right.

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Function Name

Document Name

Title

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

2. Coding Rules
2.1. Rules on Inquiry Processing
a.

Obtaining the execution plan


Always obtain and evaluate the execution plan (EXPLAIN) for all SQL used.
Note that the access path may drastically change by the number of rows in a table if the Optimizer is configured on a cost basis.

b.

Prohibition on use of sub-queries


In principle, sub-queries should be replaced by association operations as much as possible. They may only be used when the sub-query returns only a few rows.
- In-line view
A sub-query which describes a SELECT clause within a FROM clause.
In principle, this use is prohibited ; replace with an association.
- Nested query
A sub-query in a WHERE clause. A nested sub-query is prohibited.
- Correlation sub-queries
A sub-query which queries fields on a table which is also queried by the sub-query's parent statement.
In principle, this use is prohibited. Use only for tuning sub-queries.

c.

An ORDER BY and GROUP BY clause should not target any non-key fields.
An ORDER BY and GROUP BY should be carried out on the key fields.
When unavoidable, monitor the performance and request for index configuration if necessary.

d.

Prohibition of complex query syntax


In principle, CONNECT BY, INTERSECT and MINUS should not be used and should be replaced by logics.
When it is unavoidable, consult the database manager (= the DBA in each application team)

e.

3/37

Page

Prohibition on use of SQL statements for complex conditional branching.


* Pro*COBOL R9.2.0 does not support a CASE formula as an embedded SQL statement (supported by Pro*C/C++ R9.2.0)

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Function Name

Document Name
f.

Title

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

HAVING clause
Use a WHERE clause for a selection operation where possible.
Use HAVING only when specifying a selection condition against the result from a set operation such as BY.

g.

Prohibition on use of view association operations


A view should not be associated with other views and tables. Configure a new view when the configuration of an existing view is insufficient.
Also, the use of a view in a sub-query is prohibited.

h.

Prohibition of implicit type conversion


Do not use an implicit type conversion for field value comparison and assignment operations ; always convert explicitly.
Especially for the date type, a TO_DATE/TO_CHAR function should be used and specify and convert the date format explicitly.

i.

The usage of index from a WHERE clause


Note that indexes are not used for the following cases.
- When a function or arithmetic operator is used for the index field.
<Use of index>

WHERE TCFROM = TO_DATE('20030101', 'YYYYMMDD')

<Total table scan>

WHERE TO_CHAR(TCFROM, 'YYYYMMDD') = '20030101'

- Comparison using a NOT condition (!=)


<Total table scan>

WHERE PARTSNUM != 0

- When a NULL is specified for a search condition


<Total table scan>

WHERE STATUS IS NULL

- If anything else but a front concordance is specified in a part concordance search using a LIKE operator
<Use of index>

WHERE ADDRESS LIKE 'FUKU%'

<Total table scan>

WHERE ADDRESS LIKE '%OKA'

Obtain and valuate the execution plan because the usage of indexes changes by various conditions.
j.

Prohibition on use of SELECT *


Always specify field names for the field list in a SELECT statement

4/37

Page

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Document Name
k.

Function Name
Title

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

Restriction on the number of tables for an association


The number of tables for an association operation should be limited to 3.
Associating many tables may impact performance. Consider denormalization and use of the Materialized View.
When it is considered that use of the Materialized View is necessary, consult the database managers.

l.

Range query using a BETWEEN clause.


Use BETWEEN when specifying a search condition (.e. equal and more, equal and less, and less), and it is implicitly understood that there are
an upper limit and lower limit, ,

m. Optimize the path when associating multiple tables.


In a SQL sentences which JOIN multiple tables using different fields for association and search conditions, and also if those conditions can be
specified equally in a multiple JOIN, specify the condition on a table with less rows.
n.

External association
Pro*C/C++ R9.2.0 and Pro*COBOL R9.2.0 do not support ANSI association syntax as an embedded SQL statement.

o.

Restriction on use of hints


In principle, hints should not be used.
When it is considered that the use of hints is necessary, consult the database managers.

p.

Restriction on use of ROWID


A ROWID para-field should only be used when there is a problem in performance.
Also, descriptions which are depending on the ROWID internal format is prohibited.

q.

Use of SQL cache


The following are the rules to re-use SQL statements which are cached in the shared buffer.
- Strictly follow the coding rules.
- Avoid using dynamic SQL. Also avoid SQL statement generation by linking character arrays.
Use PreparedStatement for Java (JDBC)
Use bind variables for an embedded SQL.

5/37

Page

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Document Name
- Frequently used SQL statements should be made into views.

6/37

Page
Function Name
Title

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Document Name

r.

7/37

Page
Function Name
Title

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

Use of the ANSI SQL:1999 association syntax


* Pro*C/C++ R9.2.0 and Pro*COBOL R9.2.0 do not support the ANSI combined syntax in embedded SQL statements.

Phase

Project Name

Block Name

TMAP Standard

TMAP Development Standard

Document Name

Function Name
Title

2.2 Developer Guide

Created

3/9/2006

By

Teguh

2.2.4.3 Coding Convention - SQL

Updated

7/3/2007

By

Dani

2.2. Rules on Update Processing


a.

Acquisition of an execution plan is essential


Obtain the execution plan and carry out the tuning on sub-queries in the INSERT clause and UPDATE clause as well as the SELECT clause.

b.

Field specification in an INSERT clause


Always specify the target fields in INSERT clauses. Avoid using SELECT * FROM in sub-queries and specify the field names.

c.

Deleting entire table


Use a TRUNCATE clause when deleting all rows in a table.

d.

Updatable ResultSet should not be used (JDBC).


Always issue a SQL statement (INSERT/UPDATE/DELETE) for a ResultSet update for better performance.

C.2.3. Transaction Rules


a.

Avoiding explicit locks


It is desirable to regulate competition between applications in order to run processes within the ORACLE default lock mechanism.

b.

Strictly follow the lock order


Reduce the possibility of a deadlock by establishing a rule for the order to lock tables.
However, note that a lock is activated when the table is accessed rather than when it is specified.

c.

NOWAIT for locks


Always specify the NOWAIT option when an explicit lock is used.

d.

8/37

Page

Use of table locks


Table locks should not be used unless most of the data in a table is subject to an update.

PL/SQL & SQL Tips


Rank
***

1. Specify column name in an insert.


INSERT INTO emp VALUES(1, 'abc');
INSERT INTO emp(id, nm) VALUES(1, 'abc');

***

---- NG!
---- OK!

2. Code "ROLLBACK" at first in exception.


EXCEPTION
WHEN OTHERS THEN
Pk_Logger.writeDetailToDB(.....

->

EXCEPTION
WHEN OTHERS THEN
ROLLBACK;

ROLLBACK;

Pk_Logger.writeDetailToDB(.....

END;

END;

3. Do not specify columns, when using "EXISTS" condition.


It's enough by fixed value.
SELECT e.id, e.name
FROM emp e
WHERE EXISTS
(SELECT d.dept_cd -- no need
FROM dept d
WHERE e.dept_cd = d.dept_cd);

4.

->

SELECT e.id, e.name


FROM emp e
WHERE EXISTS
(SELECT 'x'
FROM dept d
WHERE e.dept_cd = d.dept_cd);

Let's use CASE. (new function of Oracle9)


IF rec.ID = 'A'
product_code :=
ELSIF rec.ID = 'B'
product_code :=
ELSIF rec.ID = 'C'
product_code :=
ELSE
product_code :=
END IF;

10;
20;
30;
40;

->

CASE rec.ID
WHEN 'A' THEN product_code := 10;
WHEN 'B' THEN product_code := 20;
WHEN 'C' THEN product_code := 30;
ELSE
product_code := 40;
END CASE;
OR
product_code :=
CASE rec.ID
WHEN 'A' THEN 10
WHEN 'B' THEN 20
WHEN 'C' THEN 30

ELSE
END;

40

***

5. Use Index
<< When index is attached to COL. >>
select .... where COL * 10 = :VAL;
select .... where COL = :VAL / 100;

---- NG!(Does not use index, for using calculation.)


---- OK!(Uses index)

select .... where TO_NUMBER(COL) = :VAL;


select .... where COL = TO_CHAR(:VAL);

---- NG!(Does not use index, for using function.)


---- OK!(Uses index)

select .... where COL != :VAL;

---- NG!(Does not use index, for using "!=".)

select .... where NVL(COL) = :VAL;

---- NG! As much as possible, don't use NVL. Check a specification.


It isn't need absolutely to primary key.

<< When the index consists of the following columns's sequence. >>
1) DEPT_CD
2) NAME
3) AGE

6.

select .... where NAME = 'SMITH';


select .... where NAME = 'SMITH' and AGE = 25;
select .... where DEPT_CD = 1 or NAME = 'SMITH';

---- NG!(Does not use index, for not using first column.)
---- NG!
---- NG!(Does not use index, for using "or".)

select
select
select
select
select

-------------

....
....
....
....
....

where
where
where
where
where

DEPT_CD = 1 and NAME = 'SMITH' and AGE = 25;


NAME = 'SMITH' and AGE = 25 and DEPT_CD = 1;
DEPT_CD = 1 and NAME = 'SMITH' and AGE > 25;
DEPT_CD = 1 and NAME = 'SMITH';
DEPT_CD = 1 and AGE = 25;

OK!(Uses
OK!(Uses
OK!(Uses
OK!(Uses

index)
index)
index)
index)

select .... where DEPT_CD = 1 and NAME IS NULL;


select .... where DEPT_CD IS NULL and NAME = 'SMITH';

---- OK!(Uses index)


---- NG!(Does not use index, for using "IS NULL" to first column.)

select .... where DEPT_CD = 1 and AGE = 25 or AGE = 26;


select .... where DEPT_CD = 1 and AGE = 25 or AGE = 26;

---- NG!(Does not use index, for using "or".)

Do not use 'SELECT *' in your queries to reduce disk I/O and have better performance.
SELECT * FROM emp

->

SELECT

id, name

FROM emp

use * as example like


count(*) --> count(1)

7.

Try to avoid wildcard characters at the beginning of a word while searching using the LIKE keyword.

SELECT
SELECT
8.

id, name FROM emp WHERE dept like '%ASC';


id, name FROM emp WHERE dept like 'T%C';

---- NG!(tendency to use table/index scan )


---- OK!(Uses index seek)

Use 'Derived tables' wherever possible, as they perform better.


SELECT MIN(salary)
FROM emp
WHERE id IN
(
SELECT TOP 10 id
FROM emp
ORDER BY salary DESC
)

->

SELECT MIN(salary)
FROM
(
SELECT TOP 10 salary
FROM emp
ORDER BY salary DESC
) AS A
Note : Text in BLUE font is the derived table

9. Use Temporary Tables to to improve the performance of queries performing complex summarization or comparison

A GLOBAL TEMPORARY table has a persistent definition but data is not persistent and the global temporary table generates no redo or rollback information.
for (j=0; j< arList.size(); j++) {
<some process or computation here>
if (<some process> == <some value>) {
INSERT INTO TB_R_GL
->
(col1, col2col[n]) VALUES
(val1, decode(val2, "Yes", "0", "No", "1", val2), val[n]);
<some process or computation here>
}
}

This kind of processing will have performance problem if TB_R_GL have bulk of data.
Each Insert Transaction will have an overhead specially if there is already a lot
of data or extents, thus performance might be slower than before.

create global temporary table TB_T_GL (


col1 varchar2(20),
col2 number (2,0),

col[n] varchar2(50))

This is how to create global temporary table.


->

The on commit preserve rows clause tells the SQL engine that when a transaction
is committed the table should be cleared but not drop.

on commit preserve rows;


for (j=0; j< arList.size(); j++) {
<some process or computation here>
if (<some process> == <some value>) {
INSERT INTO TB_T_GL
(col1, col2col[n]) VALUES

->

This is a sample way of


above we use the actual
growing table, there is
this actual table would

how to populate temp. tables. If you notice, in the example


TB_R_GL tables. But since this transaction table is a
a possibility that time will come wherein processing on
be slower than it was before. This is because of the growing data.

On the other hand, if we use temporary table, we can

put only the data we really need to

(val1, decode(val2, "Yes", "0", "No", "1", val2), val[n]);


<some process or computation here>

process minus the burden of other data that we dont need. We can also perform other
needed data manipulation or computation before inserting it in the actual table.

}
}
INSERT INTO TB_R_GL (col1, col2 col[n])
SELECT (col1, col2 col[n]) from TB_T_GL

10.

->

Once we are done with the other needed process, we can then transfer the final output
from temp. table to the actual table using the Bulk Insert.

Using Hints to Change Execution Plans

With hints one can influence the optimizer. The usage of hints (with exception of the RULE-hint) causes Oracle to use the Cost Based optimizer.
Optimizer HINT is usually used in those rare cases where the optimizer makes an incorrect decision about the execution plan; or there is a reason
that altering the statistics of execution plan is preferred or needed.
(Note : This is usually used as a last resort only )

The following syntax is used for hints:

An example using the commonly used INDEX hint, forcing execution plan to use index.

select /*+ HINT */ name


from emp
where id =1;

select /*+ index(t2 t2_i1) */ name


from emp
where id =1;

Where HINT is replaced by the hint text.


When the syntax of the hint text is incorrect, the hint text is ignored and will not be used.
There are a lot Oracle Hint Text, some of which are documented, while others are not.
For those non-documented hints, you may find them through the internet.

11.

Avoid using joins that requires the DISTINCT qualifier on the SELECT list in queries
SELECT DISTINCT ar.acc_period,
FROM TB_R_AR_H ar,
TB_R_CUST_INV_H inv
WHERE ar.doc_no = inv.doc_no

ar.doc_no, ar.post_dt

SELECT DISTINCT ar.acc_period, ar.doc_no, ar.post_dt


FROM TB_R_AR_H ar
WHERE EXISTS (
SELECT 'X' FROM TB_R_CUST_INV_H inv
WHERE ar.doc_no = inv.doc_no )

12.

You can obtain commonly used hint text from Oracle documentation.

---- NG!(In this case, DISTINCT have more overhead)

DISTINCT means that results are generated and then sorted


and filter out duplicate values.

---- OK!

EXISTS makes the query faster because when the subquery has been satisfied once,
there is no need to proceed further and the next matching row can be fetched.

Avoid including a HAVING clause in SELECT statements.


SELECT acct_cd, SUM(debit_amt), SUM(credit_amt)
FROM TB_R_GL

---- NG!

GROUP BY acct_cd
HAVING doc_no = 'doc123'

The HAVING clause filters selected rows only after all rows have been fetched.

AND doc_type = 'IN'

SELECT acct_cd, SUM(debit_amt), SUM(credit_amt)


FROM TB_R_GL
WHERE doc_no = 'doc123'
AND doc_type = 'IN'
GROUP BY acct_cd

SELECT header_id
FROM TB_R_SAP_JOURNAL
WHERE biz_scn_cd = 'OEM_EXP_ICS_RGR_GL'
AND post_sts = 'N'
HAVING COUNT(1) = 3

13.

Using a WHERE clause helps reduce overheads like sorting, summing, etc.

---- OK!

HAVING clauses should only be used when columns with summary operations
applied to them are restricted by the clause.

Use NOT EXISTS instead of NOT IN whenever possible.


SELECT id, name
FROM emp
WHERE id NOT IN (
SELECT id FROM dept)

SELECT id, name


FROM emp e
WHERE NOT EXISTS (
SELECT 'X' FROM dept d
WHERE d.id = e.id)

14.

---- OK!

---- NG! (NOT IN does not use a limiting condition.)


In this case, Oracle will perform full table scan on table 'emp'. For each record in 'emp', the subquery will be execute
Since the subquery does not have a 'where' clause, it will perform a full table scan for every record in the full table
scan of 'emp'.

---- OK!
In NOT EXISTS, nested index scans will be used in the subquery for each row in the 'emp' table.

Use multi-table insert if there is a need to insert data from one source to different target table.
INSERT INTO emp (id, name, age)
SELECT id, name, age
FROM tmpTable;
INSERT INTO dept (id, mgr)
SELECT id, mgr
FROM tmpTable;

In conventional way,
we opt to use several
-> Insert statement if we
need to Insert data in
more than 1 table.

INSERT ALL INTO emp(id, name, age)


VALUES (id, name, age)
INTO dept (id, mgr) VALUES (id, mgr)
SELECT id, name, age, mgr
FROM tmpTable

Using multi-table Insert, we can


-> use one SQL statement to Insert
data in several tables from one
source table. This will reduce
table scans.

How to check SQL by PL/SQL Developer


1. Open Explain Window.
[File] - [New] - [Explain Plan Window]
2. Paste SQL to Window

How to check SQL by script


Execute the following script in SQL*Plus
DELETE FROM PLAN_TABLE;
EXPLAIN PLAN FOR
select * from Z_TEST_TBL2
where DEPT_CD = 1 and NAME = 'SMITH' and AGE = 25;
SELECT DECODE(ID,0,'',LPAD(' ',2*(LEVEL-1))||LEVEL||'.'||POSITION)||
' '||OPERATION||
' '||OPTIONS||
' '||OBJECT_NODE||
' '||OBJECT_NAME||
' '||OBJECT_TYPE||
' '||DECODE(ID,0,'COST='||POSITION) QUERY
FROM PLAN_TABLE
CONNECT BY PRIOR ID = PARENT_ID
START WITH ID = 0
ORDER BY ID;

DELETE FROM PLAN_TABLE;


EXPLAIN PLAN FOR

CHECK SQL

->

QUERY
------------------------------------------------------SELECT STATEMENT
COST=
2.1 TABLE ACCESS BY INDEX ROWID Z_TEST_TBL2
3.1 INDEX RANGE SCAN IX_Z_TEST_TBL2 NON-UNIQUE

Inex search

QUERY
------------------------------------------------------SELECT STATEMENT
COST=

select * from Z_TEST_TBL2


where DEPT_CD = 1 and NAME = 'SMITH' or AGE = 25;

CHECK SQL

2.1 TABLE ACCESS FULL

SELECT DECODE(ID,0,'',LPAD(' ',2*(LEVEL-1))||LEVEL||'.'||POSITION)||


' '||OPERATION||
' '||OPTIONS||
' '||OBJECT_NODE||
' '||OBJECT_NAME||
' '||OBJECT_TYPE||
' '||DECODE(ID,0,'COST='||POSITION) QUERY
FROM PLAN_TABLE
CONNECT BY PRIOR ID = PARENT_ID
START WITH ID = 0
ORDER BY ID;
*

->

UPDATE EMP SET sal = sal * 1.2


WHERE ID = id;

***

Table full scan!

6. Use ROWID
SELECT empno, sal FROM EMP
WHERE id = :id
FOR UPDATE NOWAIT;
:
:

SELECT empno, sal, rowid FROM EMP


WHERE id = :id
FOR UPDATE NOWAIT;
:
:
UPDATE EMP SET sal = sal * 1.2
WHERE rowid = :rowid;

7. Use CURRENT OF
DECLARE
CURSOR c1 IS SELECT empno, job, sal
FROM emp FOR UPDATE;
:
:
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO rec ...
...
UPDATE emp SET sal = new_sal
WHERE empno = rec.empno;
END LOOP;

->

Z_TEST_TBL2

->

DECLARE
CURSOR c1 IS SELECT empno, job, sal
FROM emp FOR UPDATE;
:
:
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO rec ...
...
UPDATE emp SET sal = new_sal
WHERE CURRENT OF c1;
END LOOP;

8. BULK BIND INSERT

CREATE TABLE TEST_TBL(


C1 NUMBER(4),
C2 VARCHAR2(10)
)

DECRARE
TYPE TYP_C1 IS TABLE OF TEST_TBL.C1%TYPE INDEX BY BINARY_INTEGER;
TYPE TYP_C2 IS TABLE OF TEST_TBL.C2%TYPE INDEX BY BINARY_INTEGER;

DECRARE
:
:
:
:

tbl_c1 TYP_C1;
tbl_c2 TYP_C2;
BEGIN
FOR i IN 1..10000 LOOP
tbl_c1(i) := i;
tbl_c2(i) := 'name-' || TO_CHAR(i);
END LOOP;

BEGIN
:
:
:

->

-- NORMAL INSERT ----------------------FOR i IN tbl_c1.FIRST..tbl_c1.LAST LOOP


INSERT INTO TEST_TBL(c1, c2) VALUES(tbl_c1(i), tbl_c2(i));
END LOOP;

-- BULK BIND INSERT ---------------------FORALL i IN tbl_c1.FIRST..tbl_c1.LAST


INSERT INTO TEST_TBL(c1, c2) VALUES(tbl_c1(i), tbl_c2(i));

COMMIT;

COMMIT;

END;

END;
22 second

1 second

9. MERGE
Use "MERGE", when insert or update to table from other table.
ex) By emp_no TOTAL_SALE is inserted or updated.
TODAY_SALES
EMP_NO
1
2

SALES
10,000
20,000

->

MONTH_SALES
EMP_NO
1
2

SALES
210,000
100,000

->

MONTH_SALES
EMP_NO
1
2

SALES
220,000
120,000

<-- 210,000 + 10,000


<-- 100,000 + 20,000

30,000

340,000

3
4

340,000
30,000

<-- INSERT

CURSOR LOOP
CURSOR c1 IS SELECT * FROM TODAY_SALES;
BEGIN
FOR rec IN c1 LOOP
BEGIN
INSERT INTO MONTH_SALES
(EMP_NO, SALES)
VALUES(rec.EMP_NO, rec.SALES);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
UPDATE MONTH_SALES
SET SALES = SALES + rec.SALES
WHERE EMP_NO = rec.EMP_NO;
END;
END LOOP;

->

MERGE
MERGE INTO MONTH_SALES m
USING TODAY_SALES t
ON (m.EMP_NO = t.EMP_NO)
WHEN
MATCHED THEN UPDATE SET m.SALES = m.SALES + t.SALES
WHEN NOT MATCHED THEN INSERT (EMP_NO, SALES)
VALUES (t.EMP_NO, t.SALES);

Phase

MA

Project Name

TMT Application Maintenance

Block Name

ICS
Action Sheet

Document Name

Page

Function Name

Stock Movement Report

Title

25/37

Created

4/3/2007

By

FSBT) Ado

Updated

4/23/2007

By

FSBT) Ado

A20061215_01 DB Connection

Problem
Explanation

SQL Query takes too long to finish its execution. It takes more than 5 hours.

Action
Explanation

Modified and optimized the SQL Query. The execution time, from more than 5 hours, is now 6 - 7 seconds. Avoided, as much as possible, the joining of
multiple tables. Used a column-referencing individual query.
Bad / Not Recommended Sample

SELECT PARTMOD.POSTING_DATE,

Recommended Sample
SELECT X.POSTING_DATE,

PARTMOD.ORDER_TYPE,

X.ORDER_TYPE,

PARTMOD.MVMT_TYPE,

X.MVMT_TYPE,

PARTMOD.SHIPMENT_MODULE_NO,

X.SHIPMENT_MODULE_NO,

SUM(PARTMOD.PART_QTY) PART_QTY,

SUM(X.PART_QTY) PART_QTY,

SUM(PARTMOD.STD_COST) STD_COST

SUM(X.STD_COST) STD_COST

FROM (SELECT OEMEXPSDOC.ORDER_TYPE,

FROM (SELECT (SELECT OEMEXPSDOC.ORDER_TYPE

OEMEXPMOD.SHIPMENT_MODULE_NO,

FROM TB_B_OEM_EXP_SDOCS OEMEXPSDOC

OEMEXPSDOC.MVMT_TYPE,

WHERE OEMEXPMOD.OEM_SDOC_ID = OEMEXPSDOC.ID

OEMEXPSDOC.POSTING_DATE,

AND OEMEXPSDOC.IS_COMMERCIAL = 'Y'

OEMEXPITEM.PART_QTY,

AND EXISTS (SELECT 0

OEMEXPITEM.STD_COST,

FROM TB_B_AC_PERIODS ACPRD

OEMEXPITEM.PARENT_PART_ID,

WHERE ACPRD.ID = 173 AND

OEMEXPITEM.PART_ID,

ACPRD.TYPE_CD = 2 AND

OEMLOC.LOC_ID

OEMEXPSDOC.POSTING_DATE BETWEEN ACPRD.START_DATE AND


ACPRD.END_DATE)
AND ROWNUM = 1) ORDER_TYPE,

Phase

MA

Block Name
Document Name

Project Name

TMT Application Maintenance


ICS
Action Sheet

Page

Function Name
Title

Stock Movement Report

26/37

Created

4/3/2007

By

FSBT) Ado

Updated

4/23/2007

By

FSBT) Ado

Phase

MA

Project Name

TMT Application Maintenance

Block Name

ICS

Function Name

Action Sheet

Document Name

FROM TB_B_OEM_EXP_SDOCS

TB_B_OEM_EXP_SDOC_MODULE_ITEMS OEMEXPITEM,
TB_B_AC_PERIODS

Stock Movement Report

Title

OEMEXPSDOC,

TB_B_OEM_EXP_SDOC_MODULE_ITEMS OEMEXPITEM,
TB_B_OEM_LOCATIONS

Page

OEMLOC,

27/37

Created

4/3/2007

By

FSBT) Ado

Updated

4/23/2007

By

FSBT) Ado

OEMEXPMOD.SHIPMENT_MODULE_NO,
avoid using
multiple tables for
joining, especially
large tables

ACPRD

(SELECT OEMEXPSDOC.MVMT_TYPE
FROM TB_B_OEM_EXP_SDOCS OEMEXPSDOC
WHERE OEMEXPMOD.OEM_SDOC_ID = OEMEXPSDOC.ID

use column
referencing
from smaller
tables

AND OEMEXPSDOC.IS_COMMERCIAL = 'Y'


AND EXISTS (SELECT 0

WHERE ACPRD.ID = 173 AND


ACPRD.TYPE_CD = 2 AND

FROM TB_B_AC_PERIODS ACPRD

OEMEXPMOD.PACK_LOC_ID = OEMLOC.ID AND

WHERE ACPRD.ID = 173 AND

OEMEXPMOD.OEM_SDOC_ID = OEMEXPSDOC.ID AND

ACPRD.TYPE_CD = 2 AND

OEMEXPITEM.SDOC_MOD_ID = OEMEXPMOD.ID AND

OEMEXPSDOC.POSTING_DATE BETWEEN ACPRD.START_DATE AND

OEMEXPSDOC.POSTING_DATE BETWEEN ACPRD.START_DATE AND

ACPRD.END_DATE)
AND ROWNUM = 1) MVMT_TYPE,

ACPRD.END_DATE AND
OEMEXPMOD.PACK_LOC_ID IN

(SELECT OEMEXPSDOC.POSTING_DATE

(SELECT ID

FROM TB_B_OEM_EXP_SDOCS OEMEXPSDOC

FROM TB_B_OEM_LOCATIONS OEMLOC1


WHERE OEMLOC1.LOC_ID = OEMLOC.LOC_ID) AND
OEMEXPSDOC.IS_COMMERCIAL = 'Y') PARTMOD,

avoid using "IN"


clause

WHERE OEMEXPMOD.OEM_SDOC_ID = OEMEXPSDOC.ID


AND OEMEXPSDOC.IS_COMMERCIAL = 'Y'
AND EXISTS (SELECT 0

TB_B_PARTS PART,

FROM TB_B_AC_PERIODS ACPRD

TB_B_PART_MINV PMINV

WHERE ACPRD.ID = 173 AND

WHERE PARTMOD.PART_ID = PART.ID AND


PMINV.PART_ID = PARTMOD.PARENT_PART_ID AND
PMINV.ACPRD_ID = 173 AND
PMINV.STATUS = 'FGO'
GROUP BY
PARTMOD.POSTING_DATE,
PARTMOD.ORDER_TYPE,
PARTMOD.MVMT_TYPE,
PARTMOD.SHIPMENT_MODULE_NO

use "EXIST"
clause

ACPRD.TYPE_CD = 2 AND
OEMEXPSDOC.POSTING_DATE BETWEEN ACPRD.START_DATE AND
ACPRD.END_DATE)
AND ROWNUM = 1) POSTING_DATE,
OEMEXPITEM.PART_QTY,
OEMEXPITEM.STD_COST
FROM TB_B_OEM_EXP_SDOC_MODULES

OEMEXPMOD,

TB_B_OEM_EXP_SDOC_MODULE_ITEMS OEMEXPITEM
WHERE OEMEXPITEM.SDOC_MOD_ID = OEMEXPMOD.ID) X
WHERE X.POSTING_DATE IS NOT NULL

minimal joining
tables

Phase

MA

Block Name
Document Name

Project Name

TMT Application Maintenance


ICS
Action Sheet

Page

Function Name
Title

Stock Movement Report

28/37

Created

4/3/2007

By

FSBT) Ado

Updated

4/23/2007

By

FSBT) Ado

Phase

MA

Block Name
Document Name

Project Name

TMT Application Maintenance


ICS
Action Sheet

Page

Function Name

Stock Movement Report

Title

AND X.ORDER_TYPE IS NOT NULL


AND X.MVMT_TYPE IS NOT NULL
GROUP BY X.POSTING_DATE,
X.ORDER_TYPE,
X.MVMT_TYPE,
X.SHIPMENT_MODULE_NO

29/37

Created

4/3/2007

By

FSBT) Ado

Updated

4/23/2007

By

FSBT) Ado

Phase

MA

Project Name

TMT Application Maintenance

Block Name

FISM

Function Name

Action Sheet

Document Name

30/37

Page
Aggregation

Title

Created

6/18/2007

By

FSBT) Rhose

Updated

6/18/2007

By

FSBT) Rhose

A20070618_01 DB Connection

Problem
Explanation

Action
Explanation

ORA-01795: maximum number of expressions in a list is 1000


During the time this exception occurred, String 'sAccPeriod' in example contains almost 1200 concatenated parameters.

Modified and optimized the SQL Query. If you have to compare String values with the field values, if you are not sure on how long the length of your String
value will be, use EXISTS instead of IN clause.
Bad / Not Recommended Sample

Recommended Sample
create global temporary table TB_T_ACC_PERIOD
(
ACC_PERIOD

VARCHAR2(20))

on commit preserve rows;

String sAccPeriod = new String();


for (int j = 0; j < arrAcctPeriod.size(); j++)

INSERT INTO TB_T_ACC_PERIOD(ACC_PERIOD)

VALUES (?)
if (j == 0)
{
sAccPeriod = "'" + arrAcctPeriod.get(j) + "'";
} else {

shows how the


String parameters
are concatenated or
formed

this is the query of


keepAccPeriod method
where '?' is substituted by
the parameter
'arrAcctPeriod' value

if (arrAcctPeriod.size() > 0)
{

sAccPeriod += ", '" + arrAcctPeriod.get(j) + "'";


}

shows how to create


global temporary table.
Note that on global
temporary table, records
will be deleted upon
commit or rollback

dao.keepAccPeriod(conn, arrAcctPeriod);
}

this shows how to


populate the temporary
table

Phase

MA

Block Name
Document Name

Project Name

TMT Application Maintenance


FISM
Action Sheet

Page

Function Name
Title

Aggregation

31/37

Created

6/18/2007

By

FSBT) Rhose

Updated

6/18/2007

By

FSBT) Rhose

Phase

MA

Project Name

TMT Application Maintenance

Block Name
Document Name

FISM

Function Name

Action Sheet

Aggregation

Title

Created

6/18/2007

By

FSBT) Rhose

Updated

6/18/2007

By

FSBT) Rhose

UPDATE TB_R_GL

UPDATE TB_R_GL GL_TB

SET STS = 1 ,

SET STS = 1 ,

OUTBOUND_IF_NAME = 'GL_OEM_EXP_ICS_RGR_JV_20070607181026_D' ,

OUTBOUND_IF_NAME = 'GL_OEM_EXP_ICS_RGR_JV_20070607181026_D' ,

UPDATE_DT = sysdate ,

UPDATE_DT = sysdate ,

UPDATE_BY = 'uusfi00'

UPDATE_BY = 'uusfi00'

WHERE BIZ_SCN_CD = 'OEM_EXP_ICS_RGR_GL'

WHERE GL_TB.BIZ_SCN_CD = 'OEM_EXP_ICS_RGR_GL'

AND PART_RECEIVED_DT = '05/26/2007'

AND GL_TB.PART_RECEIVED_DT = '05/26/2007'

AND COMPANY_CD = 'F4775'

AND GL_TB.COMPANY_CD = 'F4775'

AND ACCOUNT_CD = '5161110'

AND GL_TB.ACCOUNT_CD = '5161110'

AND COST_CENTER = '00000000'

AND GL_TB.COST_CENTER = '00000000'

AND BIZ_CD = '000'

AND GL_TB.BIZ_CD = '000'

AND PROJECT_CD = '0000'

AND GL_TB.PROJECT_CD = '0000'

AND INTER_COMPANY_CD = '00000'

AND GL_TB.INTER_COMPANY_CD = '00000'

AND BUDGET_NO = '00000'

AND GL_TB.BUDGET_NO = '00000'

AND FUTURE1 = '00000'


AND FUTURE2 = '00000'
AND ACC_PERIOD IN (sAccPeriod.trim());

32/37

Page

avoid using the 'IN' clause or


'INSTR' clause if you are not
sure what will be the
maximum length or number of
your String parameter.

AND GL_TB.FUTURE1 = '00000'


AND GL_TB.FUTURE2 = '00000'
AND EXISTS (SELECT 0 FROM TB_T_ACC_PERIOD
WHERE ACC_PERIOD = GL_TB.ACC_PERIOD);

use "EXIST" clause on


temporary table
instead

Phase

External Design

Block name
Document name

Project name
C Common
SQL Standards

GSPS/A-TOP
Function name

Title

Common
SQL Standards

Created
Updated

2003/5/14
2003/11/05

Page
By
By

33 / 37
FJCL) Ishikawa
FJ Tsukamoto

2. SQL Standards
SQL standards are defined in the following table. In cases where it is not possible to adhere to the GSPS/A-TOP standards, the impact on areas such as response time should be investigated
and approval obtained from CIT.
TMC details of DB2 standards are provided in the document "Revised DB2 Standards.doc".
No. GSPS/A-TOPS standards
1 EXPLAIN check results

Revised DB2 Standards.doc


EXPLAIN access path check (standard)
Where SQL has been chosen, EXPLAIN must be obtained in the stand-alone test phase to check
the access path.
Where the following conditions are met on the basis of the EXPLAIN check, an SQL review is
normally required.
ACCESSTYPE=I and MATCHCOLS=0
ACCESSTYPE=R (except for very small tables and external tables)
Where PLAN/PACKAGE is bound in the actual environment, the EXPLAIN(YES) option must be

Where SQL has been chosen, EXPLAIN must be obtained in the stand-alone test phase to check
the access path.
The results of the EXPLAIN check should satisfy the following conditions.
<1> ACCESSTYPE=I (or I1)ACCESSTYPE=N requires DBA approval)
<2> MATCHCOLS0
<3> METHOD3 must conform to ORDER BY conventions (A-TOP standard No.11)
SQL is normally modified in order to change PREFETCH=L to either PREFETCH=S or 'None'.
<4> Any JOIN other than METHOD=1 (Nested Loop Join) must be approved by DBA
Where PLAN/PACKAGE is bound in the actual environment, the EXPLAIN(YES) option
must be used for BIND processing, to obtain and store access path information.
As per right-hand column

As per right-hand column

SQL statement descriptions should be no larger than 25 KB including blank portions.

If there is only one applicable record (or less) and exclusion is not required following extraction

If there is only one applicable row (or less), use a single SELECT rather than FETCH.

used for BIND processing, to obtain and store access path information.

Where the same SQL statement is used more than one time in a program, rather than writing

multiple SQL statement descriptions, the same statement should be re-used.

(deletion/update not performed), use stand-alone SELECT.


5

UPDATE processing when there is only one applicable record (or less) should be performed directly
using single UPDATE.

Where UPDATE processing does not require cursor positioning, update directly using
a single UPDATE.

As per right-hand column

For read-only processes, specify 'FETCHONLY' in the cursor declaration.

Where update can be performed based on the cursor, specify the 'FORUPDATEOF' in the
cursor declaration.
The COLUMN name for the UPDATE should be specified after the 'OF'.
The cursor used for DELETE is FOR UPDATE OF COL name 1

Where update can be performed based on the cursor, specify 'FORUPDATEOF'


in the cursor declaration.

As per right-hand column

To obtain some rather than all applicable rows, specify OPTIMIZE for n ROWS.

Where column functions are used, these must be coordinated among individual applications
beforehand and CIT approval must be obtained.
Normally, only restricted column functions such as MIN, MAX and COUNT should be used.
MIN, MAX may only be used in the following cases:
<1> Where MIN, MAX can be obtained using ACCESSTYPE=I1
<2> Where DB2 searches 10 records or less in order to identify MIN, MAX
(e.g.: When finding the "latest data validity start time", all KEY items should be specified as

The use of column functions should be well considered and thoroughly discussed beforehand
among individual application development teams.

(COL name 1 is not an index item. An arbitrary item is specified.)

equal sign conditions in the WHERE clause, and there should be no more than 10
records with "different data validity start times".)
If COUNT is used, convention 1 must be satisfied.

External Design
Block name
Document name
Phase

Project name
GSPS/A-TOP
C Common
SQL Standards

Function name

Title

Common
SQL Standards

No. GSPS/A-TOP standards


10 Where JOIN is used, EXPLAIN results must be obtained and submitted beforehand.
The following standards are normally used for join processing:
N:M join in non-unique columns can be used for up to two tables
1:1 joins for unique columns can be used for up to three tables
Joined columns must be index columns.
Conditions for Joined columns must be specified.
INNER JOIN should be normally used.
LEFT OUTER is normally not allowed.
RIGHT-OUTER/FULL-OUTER is never allowed.

Created
Updated

2003/5/14
2003/11/05

Page 34 / 37
By
FJCL) Ishikawa
By
FJ Tsukamoto

Revised DB2 standards.doc


The following standards are normally applied to join processing:
N:M join in non-unique columns can be used for up to two tables
1:1 joins for unique columns can be used for up to three tables
Joined columns must be index columns.
Conditions for Joined columns must be specified.
All join types may be used (FULL,LEFT,RIGHT-OUTER,INNER).

11

ORDER BY is normally used in accordance with the following standards.


<1> ORDER BY on cluster index columns, where DB2 internal SORT (METHOD) does not occur
<2> Online ORDER BY usage standards where cluster index is not used
- Sum of column sizes for extracted data -- maximum 200 bytes
- Sum of column sizes for SORT key items -- maximum 200 bytes
- Number of records sorted maximum 100 records
(Note that the number of records sorted is the ANSERSET (searched rows) number, not the
FETCH record.)
<3> ORDER BY in BATCH prohibited except for <1> above

ORDER BY is normally used in accordance with the following standards:


ORDER BY on cluster index columns
BATCH and online ORDER BY usage standards where cluster index is not used
Sum of column sizes for extracted data -- maximum 200 bytes
Sum of column sizes for SORT key items -- maximum 200 bytes
Number of records sorted maximum 100 records

12

As per right-hand column

13

As per right-hand column

Holding FETCH cursor across commit should be implemented using the SQL WITHHOLD clause
rather than by application program logic.
Use UNCOMMITEDREAD for read-only processes where practicable.

14

UNION processing allowed where necessary.

15

The UNION processing is not normally allowed. Where UNION is used, EXPLAIN results
must be obtained and submitted beforehand.
As per right-hand column

16

As per right-hand column

When joining multiple conditions using AND, start with conditions that have a higher filtering ratio.

17

As per right-hand column

When joining multiple conditions using OR, start with conditions that have a lower filtering ratio.

18

As per right-hand column


However, the SQL obtained as a result of rewrite using "JOIN" clause must conform to JOIN rules

'IN(sub-query)' must be performed using JOIN.


SELECT A FROM TB1 WHERE B IN
(SELECT C FROM TB2 WHERE D=:HOSTVAR)

SELECT A FROM TB1,TB2


WHERE TB1.B=TB2.C AND TB2.D=:HOSTVAR

(A-TOP standard No. 10).

The column name must be explicitly stated for INSERT process.

External Design
Block name
Document name
Phase

Project name
GSPS/A-TOP
C Common
SQL Standards

Function name

Title

Common
SQL Standards

Created
Updated

2003/5/14
2003/11/05

No. GSPS/A-TOP standards


19 As per right-hand column

Revised DB2 standards.doc

20

UNION processing is not normally allowed. Where UNION is used, EXPLAIN results must be
obtained and submitted beforehand.

OR join for non-equal sign predicate in same row is written with UNION.
SELECT * FROM TB1
WHERE A:HOSTVAR1 OR A:HOSTVAR2
-SELECT * FROM TB1
WHERE A:HOSTVAR1
UNION
SELECT * FROM TB1 WHERE A:HOSTVAR2

21

Same as right-hand column when rewriting with UNION ALL


Submission required for rewriting with UNION (A-TOP standard No.14

UNION is used for OR join of index rows and non-index rows.


SELECT * FROM TB1
WHERE A=:HOSTVAR1 OR B=:HOSTVAR2
-SELECT * FROM TB1
WHERE A=:HOSTVAR1
UNION
SELECT * FROM TB1
WHERE B=:HOSTVAR2

For UNION, DISTINCT is performed within DB2 to prevent duplicate rows being returned.
This should be avoided because SORT is executed for DISTINCT, increasing SQL costs.
For UNION ALL, DISTINCT is not performed, so where return of duplicate rows is not a problem,
UNION ALL is used.

Page 35 / 37
By
FJCL) Ishikawa
By
FJ Tsukamoto

OR join for equal sign predicate in same row is written with IN.
SELECT COUNT(*) FROM TB1
WHERE A='10' OR A='20' OR A='30'

SELECT COUNT(*) FROM TB1


WHERE A IN('10','20','30')

22

As per right-hand column

LIKE description should be replaced with IN predicate or BETWEEN predicate wherever possible.
SELECT COUNT(*) FROM TB1
WHERE A LIKE 'IBM%'
-(where final part is between '1' and '9')
SELECT COUNT(*) FROM TB1
WHERE A IN('IBM1','IBM2','IBM3',
'IBM4','IBM5','IBM6','IBM7','IBM8',
'IBM9')
or
SELECT COUNT(*) FROM TB1
WHERE A BETWEEN 'IBM1' AND 'IBM9'

23

As per right-hand column

BETWEEN is used for range predicate; AND join of non-equal sign conditions is not used.
SELECT COUNT() FROM TB1
WHERE (A'100' AND A'200'

SELECT COUNT() FROM TB1


WHERE A BETWEEN '100' AND '200'
When the search condition is '> OR <', apply '<>' using the BETWEEN search results.

External Design
Block name
Document name
Phase

Project name
GSPS/A-TOP
C Common
SQL Standards

Function name

Title

Common
SQL Standards

No. GSPS/A-TOP standards


24 Where UPDATE or INSERT is used, the department, user ID, and time of update (TIMESTAMP) must be updated.
TIMESTAMP update is performed using CURRENT TIMESTAMP as follows:
UPDATE tablename SET MTTMSP = CURRENT TIMESTAMP WHERE
(MTTIME is COLUMNNAME for time of update)
(Either BLANK or UNDERSCORE ('_') may be used between CURRENT and TIMESTAMP.)

25

The cursor used to extract records selected with SQL should be closed immediately when no longer required.
(This releases LOCKs where possible, and allows other programs waiting for LOCK to begin processing.)

26

Error checking should be performed on all SQL statements, including OPEN and CLOSE as well as FETCH and UPDATE/INSERT/SELECT.

27

The column name must be explicitly stated for SELECT process (SELECT * not allowed).
Specify only necessary fetch items to be obtained by the program using SELECT and UPDATE.

28

During batch updating, commit should be performed every 1000 records.


Online updates are normally restricted to up to 100 records.

29

Column and host variable attributes must match.

30

NOT may not be used in conditional statements.

31

BETWEEN low-val AND high-val may not be used in 1st MATCHCOLS item.

32

SUBSTR and COLUMN CONCAT should be avoided in predicate.

33

KEY-UPDATE for cluster index and type keys should not be permitted -- DELETE/INSERT used instead.

34

NULL may not be used. If there is no data, a SPACE consisting of at least 1 BLANK should be inserted.

35

DISTINCT is normally not allowed.

36

TABLE ACCESS order must be followed.

37

Update order for RECORDs in TABLE is as per CLUSTER order within each UOW.
Necessary for exclusion control, and also to prevent DEADLOCK.
Applies to all BATCH/ONLINE DELETE/INSERT/UPDATE operations.
CLUSTER order us updated when updating RECORD after searching with secondary index.

38

DELETE/UPDATE for multiple rows is not performed using direct DELETE/UPDATE.


Select rows using SELECT FOR UPDATE, then perform DELETE/UPDATE CURRENT OF CURSOR.
<1> Main KEY must be used to designate rows for exclusion control and to prevent DEADLOCK.
<2> The above rules must be followed in order to adhere to the 1000 records COMMIT requirement.
Using direct DELETE/UPDATE for multiple row DELETE/UPDATE can cause the number of updates to exceed 1,000 records without warning.
In the worst-case scenario, the DB2 system control value (NUMLKUS = 10,000 records) is exceeded, causing ABEND.
LOCK for update rows is held in DB2 REGION MEMORY.
NUMLKUS is the limit value used to prevent applications from obtaining excessively large LOCK quantities, thus ensuring concurrency among applications.
The 1000 records COMMIT rule is a gentlemen's agreement built into applications as a means of ensuring that the NUMLKUS value is not accidentally exceeded.
Applications that do not observe the 1000 records COMMIT rule put pressure on shared DB2 MEMORY resources, which affects other applications.

39

Sub-queries are not normally allowed. DBA approval is required before using sub-queries.

Created
Updated

2003/5/14
2003/11/20

Page 36 / 37
By
FJCL) Ishikawa
By
IBM Shimizu

Phase

External Design

Block name
Document name

Project name
GSPS/A-TOP
C Common
SQL Standards

Function n

Title

Common
SQL Standards

No. GSPS/A - TOP standard


1 Results of EXPLAIN check

11

Where SQL has been chosen, EXPLAIN must be obtained in the stand-alone test phase to check
the access path.
Based on the results of the EXPLAIN check, the following conditions should be satisfied.
<1> Must be Index SCAN
<2> #Key Columns0
<3> If SORT is generated, ORDER BY conventions (A-TOP standard No.11) must be satisfied
SQL is normally modified in order to change list PREFETCH to either sequential PREFETCH
or None.
<4> Any JOIN other than Nested Loop Join must be approved by DBA
Where PLAN/PACKAGE is bound in the actual environment, the EXPLAIN(YES) option must be
used for BIND processing, to obtain and store access path information.
Where column functions are used, these must be coordinated among individual applications
beforehand and CIT approval must be obtained.
Normally, only restricted column functions such as MIN, MAX and COUNT must be used.
MIN, MAX may only be used in the following cases:
<1> Where MIN, MAX can be limited using Index SCAN
<2> Where DB2 searches 10 records or less in order to determine MIN, MAX
(e.g.: When finding the "latest data validity start time", all KEY items should be specified as
equal sign conditions in the WHERE clause, and there should be no more than 10 records with
"different data validity start times".)
If COUNT is used, convention 1 must be satisfied.
The following standards are normally used for ORDER BY.
<1> Where DB2 internal SORT (determined by Insert Into Sorted Temp Table keywords in Explain)

is not generated for ORDER BY on cluster index columns


<2> Online ORDER BY usage standards where cluster index is not used
- Sum of column sizes for extracted data -- maximum 200 bytes
- Sum of column sizes for SORT key items -- maximum 200 bytes
- Number of records sorted maximum 100 records

Created
Updated

Page 37 / 37
By
FJCL) Ishikawa
By
IBM Shimizu

EXPLAIN access path check (standard)


Where SQL has been chosen, EXPLAIN must be obtained in the stand-alone test phase to check
the access path.
Where the following conditions are met on the basis of the EXPLAIN check, an SQL review is
normally required.
Index SCAN and #Key Columns = 0
Table SCAN (except for very small tables and external tables)
Where PLAN/PACKAGE is bound in the actual environment, the EXPLAIN(YES) option must be

used for BIND processing, to obtain and store access path information.

Where column functions are used, these must be coordinated among individual
applications beforehand.

The following standards are normally used for ORDER BY:


ORDER BY for cluster index columns
BATCH and online ORDER BY usage standards where cluster index is not used
Sum of column sizes for extracted data -- maximum 200 bytes
Sum of column sizes for SORT key items -- maximum 200 bytes
Number of records sorted maximum 100 records

(Note that the number of SORTs is the ANSERSET (searched rows) number, not the FETCH number.

38

2003/5/14
2003/11/20

<3> ORDER BY in BATCH prohibited except for above


DELETE/UPDATE for multiple rows is not performed using direct DELETE/UPDATE.
Define the rows using SELECT FOR UPDATE, then execute DELETE/UPDATE CURRENT OF CURSOR.
<1> Main KEY must be used to designate rows for exclusion control and to prevent DEADLOCK.
<2> The above rules must be followed in order to adhere to the 1000 records COMMIT requirement.
LOCK for update rows is held in Database Global Memory.
The LOCK for the entire database holds up to 10,000 records (the maximum number of records is 1,500 per application).
LOCK restrictions are specified in the database configuration parameters LOCKLIST and MAXLOCKS.
- LOCKLIST: number of LOCKs that can be held in the database (number of pages @ 4 KB per page), standard value = 100/150 (32/64 bit UDB)
- MAXLOCKS: Percentage of LOCKs per application that can be acquired within the LOCKLIST limit, standard value = 15
When applications attempt to acquire more LOCKs than the MAXLOCKS limit, a lock escalation occurs and locks are assigned to individual tables (the LOCKLIST is released).
Applications should be designed to prevent lock escalation and preserve application concurrency.
If an investigation determines that a lock escalation has occurred, the lock range should be coordinated among applications (including SQL review).
The 1000 COMMIT rule is considered a gentlemen's agreement between applications designed to avoid the possibility of lock escalation due to simple errors.
An application that does not conform to the 1000 records COMMIT rule puts pressure on shared DB2 MEMORY resources, which affects other applications.

Das könnte Ihnen auch gefallen