0% found this document useful (0 votes)
26 views

4.4.tuning SQL Execution-Plan

The document discusses SQL tuning and execution plans. It covers topics like single table access, joins, useful tips and techniques. Execution plans show the steps Oracle takes to run a SQL query and the costs associated with each step. Table scans, index scans, partitioning and hints can impact the performance and efficiency of a query.

Uploaded by

Xoăn BaloBale
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

4.4.tuning SQL Execution-Plan

The document discusses SQL tuning and execution plans. It covers topics like single table access, joins, useful tips and techniques. Execution plans show the steps Oracle takes to run a SQL query and the costs associated with each step. Table scans, index scans, partitioning and hints can impact the performance and efficiency of a query.

Uploaded by

Xoăn BaloBale
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 56

ORACL

E
SQL TUNING
Agend
a
• Introduction
• Single table access
• Joins
• Useful tip & techniques
• Test case/Q&A
INTRODUCTION
SQL
SELECT F. * , D.*
FROM
SB_DTM. FCT_ACCOUNT
F, SB_DTM.DIM_ACCOUNT D
WHERE DAYI D =
TRUNC( SYSDATE) - 1 AND
F.ACCOUNT_ID = D.ACCOUNT
AND D.EXP_DATE IS NOT NULL
ORDER BY 1 , 2 ;

• How to know the SQL is running


effective or not?

5
Execution Plan
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

| 0 | SELECT STATEMENT | | 2928K| 1279M| 208K ( 1 ) | 00:41:43 |


| 1 | MERGE JOIN | | 2928K| 1279M| 208K ( 1 ) | 00:41:43 |
|* 2 | TABLE ACCESS BY INDEX ROWID| DIM_ACCOUNT | 6609K| 1393M| 113K ( 1 ) | 00:22:42 |
| 3 | INDEX FULL SCAN | | 11M| | 481 ( 1 ) | 00:00:06 |
DIM_ACCOUNT_IDX_AC
|* 4 | SORT JOIN | | 1685K| 380M| 95109 ( 1 ) | 00:19:02 |
| 5 | PARTITION RANGE SINGLE | | 1685K| 380M| 8529 ( 6 ) | 00:01:43 |
|* 6 | TABLE ACCESS FULL | FCT_ACCOUNT | 1685K| 380M| 8529 ( 6 ) | 00:01:43 |

Predicate Information ( i d e n t i f i e d by operation i d ) :

2 - filter("D"."EXP_DATE" IS NOT NULL)


4 - access("F"."ACCOUNT_ID"="D"."ACCOUNT")
f i l t er ( " F" . " ACCOUNT_I D" =" D" . " ACCOU
NT" )
6 - filter("DAYID"=TRUNC(SYSDATE@!)-1)

6
Execution Plan

• Generated by Oracle SQL engine


• Extremely complicated algorithms - CBO based
• The way Oracle process/retrieves data
• The more blocks accessed, the higher cost
(esp. OLTP)
Generate execution plan process

Query

Query
Transformations

Costing and Access


Paths

Execution Plan

8
Query transformation

• SUBQUERY into JOIN


• Predicate pushing
• View merging
• …
• Behind the scene

9
Costing and Access Paths

• Table/index/column statistics
• Number of rows, distinct values, number of nulls
• Min/Max
• Column histogram
• Index: Blevel; distinct keys, clustering factor
• …
• System statistics
• Multi-block read count
• Single-block/Multi-block read time
• CPU time
• …
• Optimizer parameters
• V$SES_OPTIMIZER_ENV

10
Statistic – Where does it come from?

• Automatic Scheduler Job


• Start at 10PM every day – by default
• Gather for tables with change >10%
• Package: DBMS_STATS
• Customize for complex & large database

11
View Execution Plan
• Oracle SQL Developer (F10)
• PL/SQL Developer
• Toad (Ctrl+E)
• Oracle supplied package DBMS_XPLAN (*)
• DISPLAY
• DISPLAY_CURSOR
• DISPLAY_AWR
• SQL Plus (SET AUTOTRACE ON|TRACEONLY) (*)
• SQL Monitoring (DBMS_SQLTUNE)
Reading Execution Plan
SELECT * FROM SCOTT.EMP
WHERE DEPTNO IN DEPTNO FROM SCOTT.DEPT WHERE DNAME='RESEARCH')
(SELECT AND ENAME LIKE
'C%';
Plan hash value: 351108634

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

| 0 | SELECT STATEMENT | | 1 | 109 | 4 (0)| 00:00:01 |


| 1 | NESTED LOOPS | | 1 | 109 | 4 (0)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | EMP | 1 | 87 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 22 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |

Predicate Information (identified by operation id):

2 - filter("ENAME" LIKE 'C%')


3 - filter("DNAME"='RESEARCH') Inside out – Top to bottom
4 - access("DEPTNO"="DEPTNO")
1st Table/idx without a child
Plan changes

14
SINGLE TABLE ACCESS
Heap table structure

16
Table Access Methods

• Tablescan (Full scan)


• Read every block
• Up to high water mark
• Multi-block read
• Consider parallel if SQL is called infrequently
• Index scan
• Tree traversal
• Single block read
• Cache
Oracle B*Tree index

18
Index scan

• Range scan
• WHERE NAME = :1
• WHERE LASTUPDATE BETWEEN :1 AND :2
• WHERE NAME <> :1 ?
• Unique scan – Only for Unique index
• WHERE ID= :1
• Skip scan
• Index on (col1, col2); WHERE COL2 = :1
• Full scan (should be avoided)
• Output row is sorted
• Fast full scan
• Output is not sorted
Table scan vs Index scan

• Table scan
• “most” table data. 80/20 90/10
• How many rows really need to query?
• Report/aggregate SQL
• DSS/Data warehouse
• Index scan
• Selective query
• OLTP
• Histogram (data skew)
Histogram – Data distribution

Hà Nội TP.Hồ Chí Minh Quảng Ninh Hà Giang … Total


100.000 150.000 30.000 500 500.000

SELECT * FROM TBL_ACCOUNT WHERE PROVINCE=‘HANOI’;

SELECT * FROM TBL_ACCOUNT WHERE PROVINCE=?;


con.prepareStatement()
Selective index
• SELECT ID FROM MT_LIST WHERE PROCESS=‘N’;
• MT_LIST: 100.000.000 rows, PROCESS=‘N’: 100
• CREATE INDEX MT_LIST_PROCESS_N_I ON
MT_LIST(CASE WHEN PROCESS=‘N’ THEN ‘N’
ELSE NULL END);
• SELECT ID FROM MT_LIST WHERE (CASE WHEN
PROCESS=‘N’ THEN ‘N’ ELSE NULL END)=‘N’;
• Oracle does not index NULL value in B*Tree index
(except composite index)
• Index small
• Small overhead when update PROCESS=‘N’ to ‘Y’

22
Forcing Tablescan or Index - Hint
• Hint
• Looks like comment: /* */
• Placement: directly after SELECT, INSERT, UPDATE,
DELETE
• Format: /*+ */
• Can be appeared in various places in a SQL
• Combine multiple keyword
• Example
• SELECT /*+ FULL(A) INDEX(B(COL1)) PARALLEL(8) */
COL1 FROM A, B WHERE …
• Full list: SQL Reference
• Only use Hint when Oracle failed to produce good
plan

23
Forcing Tablescan or Index - Hint

• /*+ FULL(table alias) */


• /*+ INDEX(table alias(column)) */
• /*+ INDEX(table alias, index) */
• /*+ INDEX_FFS(table alias, index) */
Partition Pruning
CREATE TABLE quarterly _regional_s ales
(deptno number, item_no varchar2(20),
txn_date d a t e , txn_amount number, s t a t e v archar2(2))
PARTITION BY RANGE ( t x n _ d a t e )
SUBPARTITION BY LIST ( s t a t e )
(PARTITION q1_1999 VALUES LESS THAN (TO_DATE('1-APR-1999','DD-MON-YYYY'))
(SUBPARTITION q1_1999_northwest VALUES ( ' O R ' , ' WA ' ) ,
SUBPARTITION q1_1999_southwest VALUES ( ' A Z ' , ' U T ' , ' N M ' ) ,
SUBPARTITION q1_1999_northeast VALUES ( ' N Y ' , ' V M ' , ' N J ' ) ,
SUBPARTITION q1_1999_southeast VALUES ( ' F L ' , ' G A ' ) ,
SUBPARTITION q1_1999_northcentral VALUES ( ' S D ' , ' W I ' ) ,
SUBPARTITION q1_1999_southcentral VALUES ( ' O K ' , ' T X ' ) ) ,
PARTITION q2_1999 VALUES LESS THAN ( TO_DATE('1-JUL-1999','DD-MON-YYYY'))
(SUBPARTITION q2_1999_northwest VALUES ( ' O R ' , ' WA ' ) ,
SUBPARTITION q2_1999_southwest VALUES ( ' A Z ' , ' U T ' , ' N M ' ) ,
SUBPARTITION q2_1999_northeast VALUES ( ' N Y ' , ' V M ' , ' N J ' ) ,
SUBPARTITION q2_1999_southeast VALUES ( ' F L ' , ' G A ' ) ,
SUBPARTITION q2_1999_northcentral VALUES ( ' S D ' , ' W I ' ) ,
SUBPARTITION q2_1999_southcentral VALUES ( ' O K ' , ' T X ' ) ) ,
PARTITION q3_1999 VALUES LESS THAN (TO_DATE('1-OCT-1999','DD-MON-
YYYY'))
(SUBPARTITION q3_1999_northwest VALUES ( ' O R ' , ' WA ' ) ,
SUBPARTITION q3_1999_southwest VALUES ( ' A Z ' , ' U T ' , ' N M ' ) ,
SUBPARTITION q3_1999_northeast VALUES ( ' N Y ' , ' V M ' , ' N J ' ) ,
SUBPARTITION q3_1999_southeast VALUES ( ' F L ' , ' G A ' ) ,
SUBPARTITION q3_1999_northcentral VALUES ( ' S D ' , ' W I ' ) ,
SUBPARTITION q3_1999_southcentral VALUES ( ' O K ' , ' T X ' ) ) ,
PARTITION q4_1999 VALUES LESS THAN ( TO_DATE('1-JAN-2000','DD-MON-YYYY'))
(SUBPARTITION q4_1999_northwest VALUES ( ' O R ' , ' WA ' ) ,
SUBPARTITION q4_1999_southwest VALUES ( ' A Z ' , ' U T ' , ' N M ' ) ,
SUBPARTITION q4_1999_northeast VALUES ( ' N Y ' , ' V M ' , ' N J ' ) ,
SUBPARTITION q4_1999_southeast VALUES ( ' F L ' , ' G A ' ) ,
SUBPARTITION q4_1999_northcentral VALUES ( ' S D ' , ' W I ' ) ,
SUBPARTITION q4_1999_southcentral VALUES ( ' O K ' , ' T X ' ) ) ) ;

25
Partition Pruning

• Partition Range/List/Hash All


• SELECT * FROM QUARTERLY_REGIONAL_SALES WHERE txn_amount>100000;

• Partition Range/List/Hash Iterator

• SELECT * FROM QUARTERLY_REGIONAL_SALES WHERE TXN_DATE Between :B1 and :B2;


• SELECT * FROM QUARTERLY_REGIONAL_SALES WHERE TXN_DATE >:B1 AND STATE='NY';
• Avoid TXN_DATE <= (>=) TO_DATE(’01/03/2018’,’DD/MM/YYYY’) – uncertain
partitions to be scanned
But TXN_DATE >= TO_DATE(’01/03/2014’,’DD/MM/YYYY’) and TXN_DATE <
TO_DATE(’01/04/2014’,’DD/MM/YYYY’)

• Partition Range/List/Hash Single


• SELECT * FROM QUARTERLY_REGIONAL_SALES WHERE TXN_DATE =:B1 AND STATE =
'NY';
Partition Pruning not used

• Do not apply function/expression on column (same as


index)
• SELECT * FROM QUARTERLY_REGIONAL_SALES WHERE
TXN_DATE + 30 = :B1 > ?
• TXN_DATE = :B1 - 30
• SELECT * FROM QUARTERLY_REGIONAL_SALES
WHERE TO_CHAR(TXN_DATE,’MM/YYYY’) = :B1

27
Summary

• When to use Full table scan/Index scan?


• Find FT with values > 100M
• Sum total loan of a company

29
Workshop – Info

IP: 10.0.1.107
Port: 1521
DB: oracle
SID: orcl
User/pass: hr/ admin#123
Workshop – Histogram – Data
distribution

Hà Nội TP.Hồ Chí Minh Quảng Ninh Hà Giang … Total


100.000 150.000 30.000 500 500.000

SELECT * FROM TBL_ACCOUNT WHERE PROVINCE=‘HANOI’;

SELECT * FROM TBL_ACCOUNT WHERE PROVINCE=?;


con.prepareStatement()
Workshop – Skip Scan

• Skip scan
• Index on (col1, col2); WHERE COL2 = :1
Workshop – Index Function
• SELECT ID FROM MT_LIST WHERE PROCESS=‘N’;
• MT_LIST: 100.000.000 rows, PROCESS=‘N’: 100
• CREATE INDEX MT_LIST_PROCESS_N_I ON MT_LIST(CASE WHEN
PROCESS=‘N’ THEN ‘N’ ELSE NULL END);
• SELECT ID FROM MT_LIST WHERE (CASE WHEN PROCESS=‘N’ THEN
‘N’ ELSE NULL END)=‘N’;
• Oracle does not index NULL value in B*Tree index (except composite
index)
• Index small
• Small overhead when update PROCESS=‘N’ to ‘Y’

29
JOINS
Join

• Retrieve data from more than 1


table
• Only join 2 tables at a time
• Join types
• Nested loop
• Hash join
• Merge join
• Merge join cartesian (*)
Nested loop
SELECT A1.*, A2.* FROM SB_DTM.DIM_ACCOUNT A1, SB_DTM.FCT_ACCOUNT A2
WHERE A1.ACCOUNT_SK=A2.ACCOUNT_SK AND A1.OPENING_DATE BETWEEN :B1 AND
:B2
-
| Id | Operation | Name | Rows | Bytes | Cost
-
| 0 | SELECT STATEMENT | | 8852K| 3866M| 907K
|* 1 | FILTER | | | |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| FCT_ACCOUNT | 327 | 77499 | 30
| 3 | NESTED LOOPS | | 8857K| 3866M| 907K
|* 4 | TABLE ACCESS FULL | DIM_ACCOUNT | 27086 | 5845K| 100K
| 5 | PARTITION RANGE ALL | | 327 | | 27
|* 6 | INDEX RANGE SCAN | IDX_FCT_ACCOUNT_SK_I | 327 | | 27
-

Predicate Information (identified by operation id):

1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
4 - filter("A1"."OPENING_DATE">=:B1
AND "A1"."OPENING_DATE"<=:B2)
6 - access("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")
Merge join
SELECT /*+ USE_MERGE(A1, A2) LEADING(A1) */ A1.*, A2.*
FROM SB_DTM.DIM_ACCOUNT A1, SB_DTM.FCT_ACCOUNT A2
WHERE A1.ACCOUNT_SK=A2.ACCOUNT_SK
AND A1.OPENING_DATE BETWEEN :B1 AND :B2

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

| Id | Operation | Name | Rows | Bytes |TempSpc| Cost


| 0 | SELECT STATEMENT | | 8852K| 3866M| | 126M (1)|
(%CPU)|
|* 1 | FILTER | | | | | |
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
- 2 | MERGE JOIN | | 8852K| 3866M| | 126M (1)|
| 3 | SORT JOIN | | 27086 | 5845K| 16M| 102K (2)|
|* 4 | TABLE ACCESS FULL | DIM_ACCOUNT | 27086 | 5845K| | 100K (2)|
|* 5 | SORT JOIN | | 2249M| 496G| 1634G| 126M (1)|
| 6 | PARTITION RANGE ALL| | TABLE 2249M| 496G| | 11M (5)|
| 7 | ACCESS FULL | FCT_ACCOUNT | 2249M| 496G| | 11M (5)|
- - - - - - - - - - - - - - - - - - - - - - - - - - -

Predicate Information (identified by operation id):


1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
4 - filter("A1"."OPENING_DATE">=:B1 AND "A1"."OPENING_DATE"<=:B2)
5 - access("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")
filter("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")
Merge join (continue)
Hash join
SELECT /*+ USE_HASH(A1, A2) LEADING(A1) */ A1.*, A2.*
FROM SB_DTM.DIM_ACCOUNT A1, SB_DTM.FCT_ACCOUNT A2
WHERE A1.ACCOUNT_SK=A2.ACCOUNT_SK
AND A1.OPENING_DATE BETWEEN :B1 AND :B2
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost

| 0 | SELECT STATEMENT | | 8852K| 3866M| | 37M


|* 1 | FILTER | | | | |
|* 2 | HASH JOIN | | 8852K| 3866M| 6168K| 37M
|* 3 | TABLE ACCESS FULL | DIM_ACCOUNT | 27086 | 5845K| | 100K
| 4 | PARTITION RANGE ALL| | 2249M| 496G| | 11M
| 5 | TABLE ACCESS FULL | FCT_ACCOUNT | 2249M| 496G| | 11M

Predicate Information

1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
2 - access("A1"."ACCOUNT_SK“
="A2"."ACCOUNT_SK")
3 - filter("A1"."OPENING_DATE">=:B1
AND "A1"."OPENING_DATE"<=:B2)
Choosing the Join Method
• Nested-loop
• Joins involving a relatively small subset
of table data and where the join is supported
by an index
• No memory overhead
• Hash/Merge join
• More suitable when a large proportion of the tables
are being joined or if there is no suitable index.
• Hash join consume less memory
• Merge join is suitable when result needed to be
sorted
• Merge join Cartesian *
Join order (Driving table)
SELECT A1.*, A2.* FROM
SB_DTM.DIM_ACCOUNT
A1,
SB_DTM.FCT_ACCOUNT A2
WHERE A1.ACCOUNT_SK=A2.ACCOUNT_SK AND
A1.OPENING_DATE BETWEEN :B1 AND :B2
AND A2.CO_CODE = :B3

Start with DIM_ACCOUNT or


FCT_ACCOUNT?
Join order (Driving table)
- - - - - - - - - - - - - - - -- - - - - - - - -
| I d | Operation | Name | Rows |
- - - - - - - - - - - - - - - -- - - - - - - - -
| 0 | SELECT STATEMENT | | 56698 |
| * 1 | FILTER | | |
|* 2 | TABLE ACCESS BY LOCAL INDEX ROWID| FCT_ACCOUNT | 2 |
| 3 | NESTED LOOPS | | 8857K|
|* 4 | TABLE ACCESS FULL | DIM_ACCOUNT | 27086 |
| 5 | PARTITION RANGE ALL | | 327 |
|* 6 | INDEX RANGE SCAN | IDX_FCT_ACCOUNT_SK_I | 327 |
- - - - - - - - - - - - - - - -- - - - - - - - -

P redicate I n f o r m a t i o n ( i d e n t i f i e d by o p e r a t i o n i d ) :
- - - - - - - - - - - - - - - --
1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
2 - filter("A2"."CO_CODE"=:B3)
4 - filter("A1"."OPENING_DATE">=:B1 AND "A1"."OPENING_DATE"<=:B2)
6 - access("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")

39
Join order (Driving table)
- - - - - - - - - - - - - - - -- --
| I d | Oper at i on | Name | Rows |
- - - - - - - - - - - - - - - -- --
| 0 | SELECT STATEMENT | | 56698 |
| * 1 | FILTER | | |
|* 2 | HASH JOIN | | 56698 |
| 3 | PARTITION RANGE ALL| | 11M|
|* 4 | TABLE ACCESS FULL | FCT_ACCOUNT | 11M|
|* 5 | TABLE ACCESS FULL DIM_ACCOUNT | 27086 |
- - - - - - - - - - - - - - - -- --
|

P redicate I n f o r m a t i o n ( i d e n t i f i e d by o p e r a t i o n i d ) :
- - - - - - - - - - - - - - - --

1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
2 - access("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")
4 - filter("A2"."CO_CODE"=:B3)
5 - filter("A1"."OPENING_DATE">=:B1 AND "A1"."OPENING_DATE"<=:B2)

40
Join order (Driving table)
• The table that returns the fewest number of rows
should be the driving table
• Filter as many rows as possible early
• nPr(n,n) possible combinations
• THE MORE TABLE JOIN, THE MORE CHANCE
ORACLE WILL PRODUCE SUB-OPTIMAL PLAN

• KISS
Forcing Join types, Order
• /*+ USE_NL(tbl1 tbl2) */
• /*+ USE_HASH(tbl1 tbl2) */
• /*+ USE_MERGE(tbl1 tbl2) */
• /*+ LEADING(tbl1 tbl2) */
Help Oracle determine best plan

• Gather statistics (much like AV defs)


• Use SQL as simple as possible
• Einstein: “Everything should be as simple as it can be, but not
simpler”
• Use hint only when Oracle failed
USEFUL TIP & TECHNIQUES
Use index effectively
• The more indexes – the slower INSERT / UPDATE / DELETE
• Create index that really speedup queries
• More indexes > more suboptimal plans
• Do not apply function/calculation on column which has index
• TRUNC(LAST_UPDATE)=TRUNC(SYSDATE)-1
• (LAST_UPDATE >= TRUNC(SYSDATE)-1) AND (LAST_UPDATE <
TRUNC(SYSDATE))
• SAL+1000>:X => SAL >: X-1000
• Avoid using NOT, <>
• STATUS NOT IN (1,2,3)=> STATUS in (5)
• COL1 <> VALUE1
• Do not use LIKE ‘%STRING’ with % at first (esp bind
variable)

46
Index with multiple column

• INDEX SKIP SCAN


• Terrible if leading column has high distinct values (eg.
ID)

47
Bind variable

• Statement with string literals:


• SELECT NAME FROM USERS
WHERE ID = 100;
• SELECT NAME FROM USERS
WHERE ID = 110;
• Statement with bind
variables:
• SELECT NAME FROM USERS
WHERE ID = ?;
• Effects
• Parsing
• Oracle Memory fragment

48
Bind variable

• Prevent SQL Injection


• Faster to execute
• May produce sub-optimal plan
• SELECT * FROM PROCESS_QUEUE WHERE STATUS=:1
• SELECT * FROM PROCESS_QUEUE WHERE STATUS=0

49
SELECT * vs. SELECT COLUMN

• SELECT * FROM ACCT WHERE EFFDATE=:1;


• SELECT EFFDATE FROM ACCT WHERE
EFFDATE=:1;
• Reduce network traffic
• Oracle stores data by column order, the rest are skip
when not needed
• Coding best practice: explicitly, do not rely on implicit
• SQL is clear for later review
• INSERT INTO (COLUMN LIST) VALUES ()
• Not INSERT INTO VALUES()
• Add column => Insert Failed – Not enough values

50
Real life test case

• Take top SQL from a database & review


NO RUNABLE SQL

BUT COST EFFECTIVE SQL


References

• Oracle® Database Performance Tuning Guide


• Troubleshooting Oracle Performance 2008 - Christian
Antognini (2nd 2014)
• Cost-Based Oracle Fundamentals 2006 - Jonathan
Lewis

• Group chat
h.ma_so_thue mst,
Practice
_char(dk.ngay_dangky,'dd/mm/yyyy hh24:mi:ss') ngay,
01-CA06',
ase when csh.so_cmnd is not null and csh.ma_so_thue is null then 1 -- ca nhan
when ( csh.so_cmnd is null and csh.ma_so_thue is not null )then 5 -- to chuc
when(csh.so_cmnd is not null and csh.ma_so_thue is not null) then 5
end) cn
om BCA_prod.diem_dang_ki ddk , BCA_prod.oto_portal@oto p, BCA_prod.oto oto,
CA_prod.oto_dang_ky dk , BCA_prod.oto_chu_so_huu csh,
CA_prod.dia_danh_hanh_chinh@oto hc
here ddk.id = dk.DIEM_DK_ID
nd ddk.dia_danh_cap_cuoi = hc.id
nd ddk.dia_danh_cap_cuoi in (select id from bca_prod.dia_danh_hanh_chinh )
nd dk.chu_so_huu_id = csh.id
nd oto.so_khung not in (select p.so_khung from BCA_prod.oto_portal@oto
here p.ngay_tao between to_date('10/11/2022', 'dd/MM/yyyy') and to_date('10/12/2022',
d/MM/yyyy'))
nd oto.id = dk.oto_id
nd dk.trangthai_dangky in('01','03','04','06','07','10','12')
nd dk.ngay_dangky between to_date('10/11/2022', 'dd/MM/yyyy') and to_date('10/12/2022',
d/MM/yyyy')
nd (ddk.ten not like '%Test%' or ddk.ten not like '%test%' ) ORDER BY madd, caphc, loaidk
Q&A
Thank you!

You might also like