SQL Best Coding Practice in PeopleTools 7.x David Kurtz Go-Faster Consultancy Ltd. [email protected] www.go-faster.co.uk Who are you? • Familiar with SQL • not necessarily the DBA • Might be –

Download Report

Transcript SQL Best Coding Practice in PeopleTools 7.x David Kurtz Go-Faster Consultancy Ltd. [email protected] www.go-faster.co.uk Who are you? • Familiar with SQL • not necessarily the DBA • Might be –

SQL Best Coding Practice in
PeopleTools 7.x
David Kurtz
Go-Faster Consultancy Ltd.
[email protected]
www.go-faster.co.uk
1
Who are you?
• Familiar with SQL
• not necessarily the DBA
• Might be
– Application developer
– Team Leader
2
So Where is all the SQL?
•
•
•
•
•
•
•
•
Views
Scrollxxx() PeopleCode
SQLExec() PeopleCode
Mass Change
Application Engine
PS/Query / Crystal
SQR
Stored Statements
3
Views
4
Scrollxxx() PeopleCode
5
SQLExec() PeopleCode
6
Mass Change
7
Application Engine
8
PS/Query / Crystal
9
SQR
10
Stored Statements
11
Simplicity
• As simple as possible
• As complicated as necessary
• Data Model
• Avoid excessive I/O
12
SQL
•
•
•
•
•
Coding Standard
Implicit Type Conversion
Sorts
Indexes
Sub-queries
13
Coding Standards
• Be explicit
– Make it readable
• Indent sub-queries and brackets
– Use table aliases
• Lower parse time
• Less unexpected results without error messages
– Avoid implicit type conversion
– Avoid possible Y2K issue
• Explicitly specify Y2K compliant date formats
14
Readability
CREATE TABLE PS_GEN_JOB_TBL(...) AS SELECT DISTINCT ...
FROM
PS_PERSONAL_DATA A, PS_JOB B, PS_PERS_NID ND,
PS_NID_TYPE_TBL NDT
WHERE
A.EMPLID=B.EMPLID
AND
A.EMPLID=ND.EMPLID
AND
B.EMPLID=ND.EMPLID
AND
ND.NATIONAL_ID_TYPE=NDT.NATIONAL_ID_TYPE
AND
(
B.EFFDT>=%CURRENTDATEIN
OR
(
B.EFFDT=(
SELECT
MAX(B2.EFFDT)
FROM
PS_JOB B2
WHERE
B2.EMPLID=B.EMPLID
AND
B2.EMPL_RCD#=B.EMPL_RCD#
AND
B2.EFFDT<=%CURRENTDATEIN)
AND
B.EFFSEQ=
(SELECT MAX(B3.EFFSEQ)
FROM
PS_JOB B3
WHERE
B3.EMPLID=B.EMPLID
AND
B3.EMPL_RCD#=B.EMPL_RCD#
15
AND
B3.EFFDT=B.EFFDT)))
Minimum table aliases
SELECT COUNT(*)
FROM
PS_JOB B
WHERE (
EFFDT=(
FROM
WHERE
AND
AND
AND
EFFSEQ=
FROM
WHERE
AND
AND
SELECT MAX(B1.EFFDT)
PS_JOB B1
B.EMPLID=EMPLID
B.EMPL_RCD#=EMPL_RCD#
B.EFFDT<=%CURRENTDATEIN)
(SELECT MAX(B2.EFFSEQ)
PS_JOB B2
B.EMPLID=EMPLID
B.EMPL_RCD#=EMPL_RCD#
B.EFFDT=EFFDT))
16
Maximum table aliases
SELECT COUNT(*)
FROM
PS_JOB B
WHERE (
B.EFFDT=(
FROM
WHERE
AND
AND
AND
B.EFFSEQ=
FROM
WHERE
AND
AND
SELECT MAX(B1.EFFDT)
PS_JOB B1
B1.EMPLID=B.EMPLID
B1.EMPL_RCD#=B.EMPL_RCD#
B1.EFFDT<=%CURRENTDATEIN)
(SELECT MAX(B2.EFFSEQ)
PS_JOB B2
B2.EMPLID=B.EMPLID
B2.EMPL_RCD#=B.EMPL_RCD#
B2.EFFDT=B.EFFDT))
17
Wrong table alias
SELECT COUNT(*)
FROM
PS_JOB B
WHERE (
EFFDT=(
FROM
WHERE
AND
AND
AND
EFFSEQ=
FROM
WHERE
AND
AND
SELECT MAX(B1.EFFDT)
PS_JOB B1
B.EMPLID=EMPLID
B.EMPL_RCD#=EMPL_RCD#
B.EFFDT<=%CURRENTDATEIN)
(SELECT MAX(B2.EFFSEQ)
PS_JOB B2
B2.EMPLID=EMPLID
B2.EMPL_RCD#=EMPL_RCD#
B2.EFFDT=EFFDT))
18
Implicit Type Conversion
SELECT *
FROM
PS_JOB
WHERE EMPLID=8001
SELECT *
FROM
PS_JOB
WHERE EMPLID=‘8001’
19
Implicit Type Conversion
SELECT *
FROM
PS_JOB
WHERE EMPLID=8001
SELECT *
FROM
PS_JOB
WHERE EMPLID=‘8001’
TABLE ACCESS (FULL) OF
'PS_JOB’
INDEX (RANGE SCAN) OF
'PSAJOB' (NON-UNIQUE)
why did this not use the index?
20
Implicit Type Conversion
SELECT *
FROM
PS_JOB
WHERE EMPLID=8001
SELECT *
FROM
PS_JOB
WHERE EMPLID=‘8001’
TABLE ACCESS (FULL) OF
'PS_JOB’
INDEX (RANGE SCAN) OF
'PSAJOB' (NON-UNIQUE)
why did this not use the index?
SELECT *
FROM
PS_JOB
WHERE
TO_NUMBER(EMPLID)=8001
21
Sorts
•
•
•
•
•
Updating indexed columns
Distinct
Order by
Group by
Union -v- Union All
22
Indexes
• >~ 200 rows
• <~ 10%
– Very rough guidelines
– Avoid updating indexed columns
23
Distinct
• Sorts whole select list
• Can drive the join order of the tables
• Avoid distinct & order by
– Order one way for the distinct
– Order another way for the order by
24
Distinct
SELECT
FROM
ORDER BY
DISTINCT A,B,C,D
table
A,B,C
• ‘Order by’ clause unnecessary
25
Distinct
• Instead of
SELECT
DISTINCT
A,B,C,D
FROM
table
ORDER BY A,C,B
26
Distinct
• Instead of
SELECT
DISTINCT
A,B,C,D
FROM
table
ORDER BY A,C,B
• Try this
SELECT
FROM
DISTINCT
A,C,B, D
table
27
Group by
• Instead of
SELECT
A,B,C,
SUM(D)
FROM
table
GROUP BY A,B,C
ORDER BY A,C,B
28
Group by
• Instead of
SELECT
A,B,C,
SUM(D)
FROM
table
GROUP BY A,B,C
ORDER BY A,C,B
• Try this
SELECT
A,C,B,
SUM(D)
FROM
table
GROUP BY A,C,B
29
Union -v- Union All
• Union
– Each query is distinct, and so is sorted
– Duplicates are eliminated
• Union All
– One query followed by the next
30
Union -v- Union All
SELECT
FROM
UNION
SELECT
FROM
• Returns
Dummy
----1
1
dual
1
dual
SELECT
1
FROM
dual
UNION ALL
SELECT
1
FROM
dual
• Returns
Dummy
----1
1
31
Union -v- Union All
SELECT
FROM
UNION
SELECT
FROM
• Returns
Dummy
----1
2
2
dual
1
dual
SELECT
2
FROM
dual
UNION ALL
SELECT
1
FROM
dual
• Returns
Dummy
----2
1
32
Disabling Indexes
• Functions on columns
• Index disabled
– TO_CHAR(column,’DD-MM-YYYY’) = :bind
• Index enabled
– column = TO_DATE(:bind, ’DD-MM-YYYY’)
• Oracle syntax, generic principle
33
Use all indexed columns
• Specify all indexed columns
– Cannot exact scan column unless exact scan all
previous columns
34
Use all indexed columns
SELECT
…
FROM
PS_JOB B
WHERE
EMPLID = :1
AND EFFSEQ = (
SELECT
MAX(EFFSEQ)
FROM
PS_JOB B1
WHERE
B1.EMPLID =
B.EMPLID
AND
B1.EFFDT =
B.EFFDT)
SELECT
…
FROM
PS_JOB B
WHERE
EMPLID = :1
AND EFFDT = (
SELECT
MAX(EFFSEQ)
FROM
PS_JOB B1
WHERE
B1.EMPLID =
B.EMPLID
AND
B1.EMPL_RCD#
= B.EMPL_RCD#
AND
B1.EFFDT =
B.EFFDT)
35
High Water Marks (Oracle)
• Oracle specific
• Delete -v- Truncate
DELETE FROM table;
TRUNCATE TABLE table;
– Full Scans - HWM
36
Sub-queries
• Correlated
– executed once per parent row
• Not Correlated
– executed once in advance
37
Sub-queries
– Correlated
– Non-Correlated
DELETE FROM table1 t1
WHERE EXISTS(
SELECT ‘x’
FROM
table2 t2
WHERE
t1.keycolumn
= t2.keycolumn)
DELETE FROM table1 t1
WHERE t1.keycolumn IN(
SELECT t2.keycolumn
FROM
table2 t2)
38
Sub-queries (Oracle)
• Oracle specific
DELETE FROM table1 t1
WHERE (t1.keycolumn1, t1.keycolumn2) IN(
SELECT t2.keycolumn1, t2.keycolumn2
FROM
table2 t2)
39
ROWID (Oracle)
• Oracle specific
• physical address of row
40
Sub-queries (Oracle)
• Oracle specific
DELETE FROM table1 t1
WHERE t1.rowid IN(
SELECT t1b.rowid
FROM
table1 t1b, table2 t2
WHERE t1b.keycolumn1 = t2.keycolumn2
AND
t1b.keycoulmn2 = t2.keycolumn2)
41
Order of ‘From’ clause (Oracle)
• Oracle specific
• Rule Based Optimiser
– backwards
• Cost Based Optimiser
– doesn’t matter
• CBO + Ordered Hint
– forwards
• Distinct tends to override this
42
Summary
• Lots of places to write SQL
• Code should be
–
–
–
–
efficient
simple
readable
explicit
43
SQL Best Coding Practice in
PeopleTools 7.x
David Kurtz
Go-Faster Consultancy Ltd.
[email protected]
www.go-faster.co.uk
44