Boost Select Performance by Clustering Data

Boost Select Performance by
Clustering Data
DOAG 2016
Martin Widlake
Database Performance, Architecture & Training
Ora600 Limited
[email protected]
http://mwidlake.wordpress.com/
http://mwidlake.wordpress.com/
Oh, and that twitter thing - @MDWidlake
ORA00 Ltd
Abstract
Everyone knows how to design a database:
Create a few tables, add primary keys, build some extra indexes and
maybe add on some referential integrity. The database engine will
take care of accessing the actual data for you.
This will NOT get you the best performance you can obtain.
Very few people consider clustering the data anymore, how it is
ordered and stored. Doing so can reap huge gains in select
performance and reduced memory use. This presentation will cover
Index Organized Tables, single table Hash Clusters, Partitioning and
simply ordering your data to boost select performance.
Suitable for beginners and intermediate.
ORA600 Ltd
Who am I and why am I doing this
Talk?
•
I’ve been working with Oracle since I was small. Over half my life in fact.
Duration is no guarantee of capability though.
•
I’ve designed, built & fixed VLDBs most of my working life, moving
huge data volumes (“huge” relative to the decade) in and out of them.
Size of your VLDB is no guarantee of capability though.
•
Like many old oracle hacks, I started with Forms V3, fell into using
PL/SQL, went to the DBA dark side, back to being a Duh-veloper and
cycled between them for all sorts of bad companies. Experience is no
guarantee of capability though.
•
I like cats, genetics, beer, drinking tea in the garden (which I do a lot more
of now) and User Groups – even you lot. I present a lot. Presenting is no
guarantee of capability though.
•
I’ve helped write a book.
Writing books is no guarantee of capability though.
Should you physically organise your
data?
This used to be known as “Physical Implementation”. After the
logical design of what tables relate to what and normalisation,
you would look at how to place your data.
Back in 1995 this consisted of what tablespaces to place objects
in, size of extents, whether to split objects, should you use
clusters, IOTs and then, come 1997 or so, should you use
partitions.
Despite people like Tom Kyte, Christian Antognini, Jonathan
Lewis, saying if you are not physically placing data you are
probably doing it wrong - it has died out as a practice.
ORA600 Ltd
When Oracle fetches a record from
Disc to the SGA – what does it
Actually fetch?
ORA600 Ltd
Block Buffer Cache
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
To collect a row, a
whole block is
fetched from disk
8K Database Block
Other Row
Other Row
Other Row
Other Row
Other Row
Other Row
Relevant Row
Other Row
Other Row
Other Row
Other Row
Other Row
Other Row
Other Row
Other Row
Other Row
Other Row
Other Row
Often, most if not all of the
other rows in the block are
not relevant to the query
95%Collateral data
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
Only a small percentage of the data is relevant
ORA600 Ltd
In Collecting the IOT block
holding the first required
row, the rest of the block
holds relevant data
Block Buffer Cache
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
8K Database Block
Other Row
Other Row
Other Row
Relevant Row
Relevant Row
Relevant Row
Relevant Row
Relevant Row
Relevant Row
8K Database Block
Relevant Row
Relevant Row
Relevant Row
Relevant Row
8K Database Block
Relevant Row
Relevant
Relevant
Row Row
Relevant
Relevant Row Row
Relevant
Relevant
Row Row
Other
Relevant Row Row
Other Row
Other Row
Other Row
Other Row
Other Row
The next two IOT
blocks are full and
partially full of
relevant data
High percentage of the data is relevant
ORA600 Ltd
ORA600 Ltd
ORA600 Ltd
Normal ‘B’ Tree index lookup
Index
Table
Unique Key column(s) and Rowid, format
OOOOOOFFFBBBBBBRR
OOOOOO
FFF
BBBBBB
RRR
= Database Object No
= tablespace relative file No
= datafile relative block No
= Row in block
ORA600 Ltd
Index
Index Range Scan:
Oracle reads the root node of the index (1), and a
block in each of the branch levels (2&3) to find the
starting point of the range scan. The first relevant
record in the leaf block is identified (4) and for each
index entry the relevant table blocks are located via
the rowid. Further leaf blocks (5) are scanned and the
identified table blocks read until the end of the range
is encountered.
Table
ORA600 Ltd
Normal Index Lookup
• Looking up a single record via a *selective* index is
efficient as soon as you have more than a small number
(6?) of table blocks.
• The larger the table, the higher the efficiency of an index
lookup compared to a table scan.
• However, a range scan be far less efficient, especially as
the percentage of the table scanned increases and the
table size increases.
• A key consideration in respect of the efficiency of an index
range scan is the index Cardinality and Clustering Factor
ORA600 Ltd
OWNER
TABLE_NAME
NUM_ROWS
BLOCKS AVG_L GLS ULS LST_ANL
SAMP_SIZ
-------- -------------- ------------- ---------- ----- --- --- ------------ ------MDW
PERSON
1376,688
90,677
447 YES NO 180413 16:41 137668
INDEX_NAME
--------------PERS_DOB
PERS_PK
PERS_SNFNDOB
TYP
--NOR
NOR
NOR
PRT
--NO
NO
NO
INDEX_NAME
---------------------------PERS_DOB
PERS_PK
PERS_SNFNDOB
PERS_SNFNDOB
PERS_SNFNDOB
UNQ BL
L_BLKS
DIST_KEYS
CLUSTF
LB_KEY DB_KEY
--- -- ---------- ----------- ------------ ------- -------29,322
1375,881
1
46
NON 2
3,643
UNI 2
2,929
1376,688
93,104
1
1
NON 2
6,139
1346,683
1350,247
1
TABLE_NAME
---------------PERSON
PERSON
PERSON
PERSON
PERSON
PSN
--1
1
1
2
3
COL_NAME
-----------------------------DOB
PERS_ID
SURNAME
FIRST_FORENAME
DOB
OWNER
COLUMN_NAME
NUM_DISTINCT
N_NULLS LOW_V
-------- -------------------- ------------ --------- ------------1,373,312
0 12385
MDW
PERS_ID
SURNAME
111
0 ADAMS
217
0 AALIYAH
FIRST_FORENAME
217
274,950 AALIYAH
SECOND_FORENAME
PERS_TITLE
4
0 MASTER
2
0 46
SEX_IND
DOB
29,322
0 1924-05-19
ADDR_ID
398,272
0 6397
ORA600 Ltd
HI_V
----------1389072
YOUNG
ZACHARY
ZACHARY
MRS
4D
2013-04-01
1006390
BKTS
---1
1
1
1
1
1
254
1
Cardinality of columns and indexes
• The cardinality of a column is how many distinct values
there are compared to the number of rows.
• Unless column Histograms are available (and histograms
have issues) oracle assumes that if there are 100 values
for a column, each one will identify 1% of the data.
• If more than one column is filtered on, Oracle by default
assumes the columns are not correlated and calculates
the cardinality based on each column. (this is often not true)
• For indexes Oracle holds the number of distinct keys and
so knows the average cardinality of the index.
ORA600 Ltd
Clustering Factor of Indexes
• The Cluster Factor of an index lets the optimizer know how ordered
the index is compared to the table. The figure needs interpreting.
• It actually says that, as you scan the whole index, how often does the
table block being examined change.
• If the number is close to the number of blocks in the table, the index
order closely matches the order of the table.
• If the number is close to the number of rows in the table, oracle thinks
the index order does not match the order of the table.
• However, Oracle does not keep track of if it is swapping between
blocks close to each other in the table, so it can get the wrong
impression.
ORA600 Ltd
Index
Scan
ORA600 Ltd
Index
Scan
ORA600 Ltd
Index
Scan
ORA600 Ltd
12c Clustering Factor Improvements
• In 12C you can now set a stats gathering preference to say “increase
the clustering factor only if the block swapped to was not in the last
TABLE_CACHED_BLOCKS visited blocks
SQL> exec dbms_stats.set_table_prefs(ownname=>user,
tabname=>'BOWIE',
pname=>'TABLE_CACHED_BLOCKS', pvalue=>42);
PL/SQL procedure successfully completed.
SQL> EXEC dbms_stats.gather_index_stats(ownname=>user,
indname=>'BOWIE_ID_I', estimate_percent=> null);
ORA600 Ltd
Index Organized Table
• The table is created in the standard index structure, with a
root node, zero one or more branch nodes and the leaf
nodes.
• Whole rows (see later) are inserted into this structure, in
the order of the indexed columns.
• This order is maintained whenever new records are
inserted or modified.
• The IOT must be organized on the Primary Key
• In effect, the Primary Key is created and the table segment
is not. {I’d prefer IOTs to be called “Data Hosting Indexes”
or something}
ORA600 Ltd
Normal ‘B’ Tree index lookup
Index Organized Table
NO ROWID
Rest of the columns are stored
in the index entry, after the Primary
Key column(s)
ORA600 Ltd
Normal ‘B’ Tree index lookup
Index
Table
Unique Key column(s) and Rowid, format
OOOOOOFFFBBBBBBRR
OOOOOO
FFF
BBBBBB
RRR
= Database Object No
= tablespace relative file No
= datafile relative block No
= Row in block
ORA600 Ltd
Index Organized
Table
Index Range Scan of an IOT: Oracle
reads the root node of the index (1),
and a block in each of the branch levels
(2&3) to find the starting point of the
range scan. As the row data is in the
IOT Oracle needs only scan the leaf
blocks (4,5&6) until all the rows in the
range have been found. NB this will
probably be more leaf blocks than is
the case with a normal index but less
block reads overall.
ORA600 Ltd
Index
Index Range Scan:
Oracle reads the root node of the index (1), and a
block in each of the branch levels (2&3) to find the
starting point of the range scan. The first relevant
record in the leaf block is identified (4) and for each
index entry the relevant table blocks are located via
the rowid. Further leaf blocks (5) are scanned and the
identified table blocks read until the end of the range
is encountered.
Table
ORA600 Ltd
Creation Statement
create table child_iot
(pare_id
number(10)
not null
,cre_date date
not null
,vc_1
varchar2(100) not null
,date_1
date
,num_1
number(2)
,num_2
number(2)
,constraint chio_pk primary key(pare_id,cre_date)
-- using index tablespace index_01 CANNOT STATE for IOT.
-- State in table definition
)
ORGANIZATION INDEX
tablespace data_01
/
{test_iot1}
ORA600 Ltd
Selecting One Row by PK
select * from child_HEAP
where PARE_ID=1234
AND cre_date='24-JUN-11 20:13:21'
PARE_ID CRE_DATE VC_1
DATE_1
NUM_1 NUM_2
-------- --------- --------------------- --------- ----- ----1234 24-JUN-11 LUTFHOCIJNYNORREAJOV 25-JUN-11
11
16
ORA600 Ltd
Selecting One Row by PK
HEAP
-------------------------------------------------------------------------------| Id | Operation
| Name
|Rows |Bytes|Cost | Time
|
-------------------------------------------------------------------------------|
0 | SELECT STATEMENT
|
|
1 | 83 | 3 (0)| 00:00:01 |
|
1 | TABLE ACCESS BY INDEX ROWID| CHILD_HEAP |
1 | 83 | 3 (0)| 00:00:01 |
|* 2 |
INDEX UNIQUE SCAN
| CHHE_PK
|
1 |
| 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------Statistics 0 recursive calls
0 db block gets
4
consistent gets
IOT
----------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
----------------------------------------------------------------------------|
0 | SELECT STATEMENT |
|
1 |
83 |
2
(0)| 00:00:01 |
2
(0)| 00:00:01 |
|* 1 | INDEX UNIQUE SCAN| CHIO_PK |
1 |
83 |
----------------------------------------------------------------------------Statistics 0 recursive calls
0 db block gets
3
consistent gets
ORA600 Ltd
Selecting Range
select sum(num_1) from child_heap where pare_id = 234;
864
Execution Plan
------------------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
------------------------------------------------------------------------------------------|
0 | SELECT STATEMENT
|
|
1 |
7 |
103
(0)| 00:00:02 |
|
1 | SORT AGGREGATE
|
|
1 |
7 |
|
|
|
2 |
TABLE ACCESS BY INDEX ROWID| CHILD_HEAP |
100 |
700 |
103
(0)| 00:00:02 |
|* 3 |
INDEX RANGE SCAN
| CHHE_PK
|
100 |
|
3
(0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Statistics 88
consistent gets
select sum(num_1) from child_iot where pare_id = 234;
1048
Execution Plan
----------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
----------------------------------------------------------------------------|
0 | SELECT STATEMENT |
|
1 |
7 |
5
(0)| 00:00:01 |
|
1 | SORT AGGREGATE
|
|
1 |
7 |
|
|
|* 2 |
INDEX RANGE SCAN| CHIO_PK |
100 |
700 |
5
(0)| 00:00:01 |
-----------------------------------------------------------------------------
Statistics
5
consistent gets
ORA600 Ltd
Physical Ordering of Heap
• An alternative to IOTs to gain physical clustering of data is
to rebuild the HEAP via an ordered select:
insert into CHILD_HEAP_ORD
(pare_id,cre_date,vc_1,date_1,num_1,num_2)
select pare_id,cre_date,vc_1,date_1,num_1,num_2
from CHILD_HEAP
ORDER BY 1,2
• This is intrusive, it prevents proper access to the table
during the copy and indexes need to be rebuilt, stats
gathered...
• Is a “One Shot” physical ordering. Updates and inserts will
mess it up.
• Use of partition swap can make this a usable technique.
ORA600 Ltd
Selecting Range from Ordered Heap
select sum(num_1) from child_heap where pare_id=321;
851
------------------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
------------------------------------------------------------------------------------------|
0 | SELECT STATEMENT
|
|
1 |
7 |
48
(0)| 00:00:02 |
|
1 | SORT AGGREGATE
|
|
1 |
7 |
|
|
|
2 |
TABLE ACCESS BY INDEX ROWID| CHILD_HEAP |
100 |
700 |
48
(0)| 00:00:02 |
|* 3 |
INDEX RANGE SCAN
| CHHE_PK
|
100 |
|
3
(0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Statistics
23
consistent gets
select sum(num_1) from child_heap_ord where pare_id=321;
851
----------------------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
----------------------------------------------------------------------------------------------|
0 | SELECT STATEMENT
|
|
1 |
7 |
5
(0)| 00:00:01 |
|
1 | SORT AGGREGATE
|
|
1 |
7 |
|
|
|
2 |
TABLE ACCESS BY INDEX ROWID| CHILD_HEAP_ORD |
100 |
700 |
5
(0)| 00:00:01 |
|* 3 |
INDEX RANGE SCAN
| CHO_PK
|
100 |
|
3
(0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Statistics 5
consistent gets
ORA600 Ltd
12c CLUSTERING_BY clause
• Oracle 12.1.0.2 introduced the new Attribute Clustering
feature whereby you can partially order heap tables when
you bulk direct insert into them.
SQL> create table ziggy2 (id number, code number, name
varchar2(30))
clustering by linear order (code)
without materialized zonemap;
Then bulk insert into the table and add indexes
OR
alter table ziggy add clustering by linear order(code)
without materialized zonemap;
Then move the table and rebuild the index
ORA600 Ltd
Intersection Entities and IOTs
• It is not unusual to have tables that exists almost
exclusively to act as an index.
• The ultimate is an Intersection Entity that exists simply to
resolve the many:many relationship between two tables:
PERSON
PERSON
ACCOUNT
INTERSECT
ACCOUNT
• The intersection only holds the PKs of the two tables. You
create two indexes, both of which include the primary keys
of the two tables - but in opposite order, to support the two
directions of traversing the intersect.
• The actual table is a waste of space – so create an IOT and
lose it.
ORA600 Ltd
Intersection Entities and IOTs
create table int_heap
(acco_type number(2) not null
,acco_id
varchar2(10) not null
,pers_id
varchar2(8) not null)
alter table int_heap add constraint inhe_pk primary key (acco_type,acco_id,pers_id)
create index inhe_uq on int_heap(pers_id,acco_type,acco_id) tablespace index_01
Blocks used
----------OBJECT
HEAP
IOT
IOT
compress 2
----------- ------ ------ ---------TABLE
80
zero
zero
PRIMARY KEY 90
133
109
UNIQUE KEY
93
95
92
------------ ------ ------ ---------TOTAL
263
228
201
ORA600 Ltd
shrunk Shrunk
IOT
IOT comp2
------- --------zero
73
60
95
92
------ --------168
152
Oracle Table Clusters
• No one ever uses Table Clusters in Oracle. Ever.
• You create a cluster on, in effect, a column {say a number(8) }and then
create an index on that cluster key.
• You create one or more tables in the cluster saying which column in
the table as the cluster key.
• Oracle puts all records with the same cluster key in the same block or
blocks.
• When you select the data back for that key, for example joining two
tables, oracle can collect all the data from the same block(s)
• They are very slow to populate and damned wasteful of space. And did
I mention that no one uses them?
ORA600 Ltd
Creating Table Clusters
create cluster pers_clu
(pers_id number(8));
-- ****
create index pers_clu_idx on cluster pers_clu;
-- ****
create table person_clu
cluster pers_clu (pers_id)
as select * from person
where pers_id < 50000
/
Elapsed: 00:00:21.66
-- 5.68 seconds for same insert into a heap
-- table with a PK
create table person_name_clu
cluster pers_clu (pers_id)
as select * from person_name
where pers_id < 50000
/
Elapsed: 00:02:27.93 -- 43.70 seconds into a heap table + IDXS
ORA600 Ltd
Normal Table Execution Plan
-----------------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
-----------------------------------------------------------------------------------------|
0 | SELECT STATEMENT
|
|
1 |
54 |
6
(0)| 00:00:0
|
1 | NESTED LOOPS
|
|
1 |
54 |
6
(0)| 00:00:0
|
2 |
TABLE ACCESS BY INDEX ROWID| PERSON
|
1 |
21 |
3
(0)| 00:00:0
|* 3 |
INDEX UNIQUE SCAN
| PERS_PK
|
1 |
|
2
(0)| 00:00:0
|
4 |
TABLE ACCESS BY INDEX ROWID| PERSON_NAME |
1 |
33 |
3
(0)| 00:00:0
|* 5 |
INDEX RANGE SCAN
| PENA_PERS_ID |
1 |
|
2
(0)| 00:00:0
------------------------------------------------------------------------------------------
16
consistent gets
Cluster Table Execution Plan
-----------------------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
-----------------------------------------------------------------------------------------|
0 | SELECT STATEMENT
|
|
361 | 40432 |
3
(0)| 00:00:01 |
|
1 | MERGE JOIN CARTESIAN |
|
361 | 40432 |
3
(0)| 00:00:01 |
|
2 |
TABLE ACCESS CLUSTER | PERSON_CLU
|
1 |
47 |
2
(0)| 00:00:01 |
|* 3 |
INDEX UNIQUE SCAN
| PERS_CLU_IDX
|
1 |
|
1
(0)| 00:00:01 |
|
4 |
BUFFER SORT
|
|
361 | 23465 |
1
(0)| 00:00:01 |
|* 5 |
TABLE ACCESS CLUSTER| PERSON_NAME_CLU |
361 | 23465 |
1
(0)| 00:00:01 |
------------------------------------------------------------------------------------------
6
consistent gets
ORA600 Ltd
No One Uses Clusters – Except SYS ☺
ora113> @clu_lst
Enter value for clu_name: %
CLUSTER_NAME
--------------CLU_1
CLU_2
C_COBJ#
C_FILE#_BLOCK#
C_MLOG#
C_OBJ#
C_OBJ#_INTCOL#
C_RG#
C_TOID_VERSION#
C_TS#
C_USER#
SMON_SCN_TO_TIM
E_AUX
OWNER
CLUST FUNCTION
KEY_SZ
HASHKEYS SIN_T
---------- ----- --------- ---------- ---------- ----MDW
HASH DEFAULT2
50
10007
Y
HASH DEFAULT2
32
10007
Y
SYS
INDEX
300
0
N
INDEX
225
0
N
INDEX
0
N
INDEX
800
0
N
INDEX
0
N
INDEX
0
N
INDEX
0
N
INDEX
0
N
INDEX
372
0
N
INDEX
0
N
12 rows selected.
ORA600 Ltd
Do we have time for a quick
diversion on single table hash
clusters?
ORA600 Ltd
Single Table Hash Clusters
• A Single Table Hash Cluster is cluster of one table
organised by the hash of a unique key.
• As a hash value is calculated there is no IO and only a
small amount of CPU to calculate it.
• The hash gives the block that oracle needs to visit to find
the record.
• So long as you *designed the STHC to be at least large
enough to hold all the rows* this one buffer get will fetch
the row.
• If you undersized the cluster, you will have too many
records being allocated to each block and they will chain.
ORA600 Ltd
Creating a STHC
-- create a single table hash cluster to hold rows approx
-- 50 bytes in size and 10000 keys
create cluster clu_1
(cl_id number)
size 50 single table hashkeys 10000;
-create table clu_tab1
(id number
,id2 number
,date_1 date
,vc_1 varchar2(10)
,vc_2 varchar2(10)
)
cluster clu_1(id);
insert into clu_tab1
select rownum,10000-rownum
,(sysdate-10) +(rownum*0.01)
,'AAAAAAAAAA','BBBBBBBBBB'
from dual connect by level <10000;
ORA600 Ltd
Selecting One Row in a STHC
select * from clu_tab1 where id=1234;
ID
ID2 DATE_1
VC_1
VC_2
---------- ---------- ----------------- ---------- ---------1234
8766 16-SEP-2014 20:05 AAAAAAAAAA BBBBBBBBBB
Execution Plan
-----------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
-----------------------------------------------------------------------------|
0 | SELECT STATEMENT |
|
1 |
33 |
1
(0)| 00:00:01 |
|* 1 | TABLE ACCESS HASH| CLU_TAB1 |
1 |
33 |
1
(0)| 00:00:01 |
-----------------------------------------------------------------------------Statistics
---------------------------------------------------------0 recursive calls
0 db block gets
1
0
consistent gets
physical reads
ORA600 Ltd
STHC – sizing it wrong
If you get the sizing info wrong:
create cluster clu_2 (cl_id number)
size 50 single table hashkeys 1000 – wrong, should be 10,000
-----------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
-----------------------------------------------------------------------------|
0 | SELECT STATEMENT |
|
1 |
33 |
8
(0)| 00:00:01 |
|* 1 | TABLE ACCESS HASH| CLU_TAB2 |
1 |
33 |
8
(0)| 00:00:01 |
-----------------------------------------------------------------------------9 consistent gets
size 32 single table hashkeys 10000 – wrong, should be size 50
-----------------------------------------------------------------------------| Id | Operation
| Name
| Rows | Bytes | Cost (%CPU)| Time
|
-----------------------------------------------------------------------------|
0 | SELECT STATEMENT |
|
1 |
33 |
2
(0)| 00:00:01 |
|* 1 | TABLE ACCESS HASH| CLU_TAB2 |
1 |
33 |
2
(0)| 00:00:01 |
-----------------------------------------------------------------------------3 consistent gets
ORA600 Ltd
STHC data clustering
• STHCs are relatively well known (though rarely used in
anger) to get the fastest single row lookup possible – 1CG
• Sizing is important and you generally “waste” space to
ensure the single consistent get lookup.
• But there is also the clustering consideration. You are
ensuring sequential values are *spread* across the
segment.
• This can avoid ITL issues with small but highly active
tables, such as lock tables or summary records that are
constantly updated or checked.
ORA600 Ltd
Partitioning
Index
Scan
ORA600 Ltd
01/2015
Partitioning
• It is all about working data set:
02/2015
03/2015
04/2015
ORA600 Ltd
05/2015
06/2015
Partitioning
• The most common form of data clustering, you probably all know
about it and there is lots of information “out there”
• Partitioning is often more about managing a large data set than data
access – it is key to fast data load, data lifecycle management (DLM),
archiving and purging.
• Most often partition by date, either monthly or daily. Beware daily
partitioning, you will need to think about your partition stats!!!
• Partitioning hardly ever helps with OLTP-type data access - indexes
and constraints support that.
• For Data Warehousing, partitioning allows you to limit data access to a
working set, eg a day of data or a month or a year. Ie you keep in the
Buffer Cache only the data you need to support business processing.
ORA600 Ltd
Partitioning
• Consider your data access and design partitioning (and subpartitioning) to support that, as well as DLM. Your aim should be to
avoid full table scans and replace with full partition scans.
• Be wary of over partitioning, especial when some access is not via the
partition key eg daily partitions but access via CUSTOMER_ID. I have
seen many systems crippled by this (see next slide)
• Your aim should be to be able to identify and only work on your active
data set.
• You may have partitioned by eg ORDER_ID but you process data by
day. You can still partition exclude by keeping track of the min and
max ORDER_ID for each day and include those limits in your WHERE
clause – I call this correlated partition exclusion
ORA600 Ltd
Partitions – Good or Bad?
Ora 600 Ltd
IOT & Partitioning P.O.C.
Comparison of Oracle Database Consistent GETs
# of GETs to read Customer Data
250
200
150
100
50
0
Test1
Test2
Test3
Test4
Test5
Test6
Test7
Normal table w ith a normal b-tree index
54
70
70
61
60
63
69
daily partitioned table, local index
196
203
202
226
190
197
196
IOT table w ith monthly partitions
16
14
14
14
13
11
13
ORA600 Ltd
IOT & Partitioning P.O.C.
Physcial Reads
Reads to satisfy query
160
140
120
100
80
60
40
20
0
Test1
Test2
Test3
Test4
Normal table with a b-tree index
61
60
63
69
daily partitioned table, local index
134
132
137
133
2
3
4
2
IOT table with monthly partitions
ORA600 Ltd
Working Data Set kept in SGA
• Physically clustering your data allows Oracle to fetch the data your
applications need with far fewer disc reads and consistent gets.
• Thus all queries supported by the clustering are much faster. This
does come at the cost of maintaining the clustering.
• The previous two slides show the benefits in the reduced consistent
gets and subsequent disc reads for a Proof of Concept. The real
system was not quite this good…
• … It was a lot better! As the while working data set fitted into the SGA
and mostly stayed there from day to day.
• Clustered data means a much more efficient use of your
Buffer Cache and thus an even greater reduction in
physical IO and thus better performance.
ORA600 Ltd
Monitoring – Nothing to See!
ORA600 Ltd
Boost Select Performance by
Clustering Data
DOAG 2016
Martin Widlake
Database Performance, Architecture & Training
Ora600 Limited
[email protected]
http://mwidlake.wordpress.com/
http://mwidlake.wordpress.com/
Oh, and that twitter thing - @MDWidlake
ORA00 Ltd
ORA600 Ltd
Template Slide
• Point one
• Point two
• Point Three
• Point Four
• Point Five
ORA600 Ltd