Professional Documents
Culture Documents
Gavin Soorma,
Senior Oracle DBA, Bankwest
Agenda
• Each partition has its own name, and may optionally have its own storage
characteristics.
Partition Partition
Partition Partition
Partition Partition
Partition Partition
Who Partitions?
Partitioning enables data management operations such data loads, index creation
and rebuilding, and backup/recovery at the partition level, rather than on the entire
table. This results in significantly reduced times for these operations.
• For Performance
Partitioning improves query performance. In many cases, the results of a query can
be achieved by accessing a subset of partitions, rather than the entire table.
Partition Pruning and Partition-wise joins can provide order-of-magnitude gains
in performance.
• For Availability
Partitioning increases the availability of mission-critical databases if critical tables
and indexes are divided into partitions to reduce the maintenance windows,
recovery times, and impact of failures.
Decisions and Challenges
• License cost of Partitioning option (~11,000$ per CPU)
• Number of Partitions.
• Choosing the type of partitioning: Range, Hash-List, Range-Hash, Range-List, List-List, Range-
Range ….
• All partitions, except the first, have an implicit lower bound specified
by the VALUES LESS THAN clause on the previous partition
• List Partitioning is useful for data that has discrete or distinct values.
• Pre 11g new partitions must be created in advance for new data.
PARTITION_NAME
------------------------------
P_FIRST
SQL> insert into order_details
values
(10001,'15-JAN-2009');
1 row created.
SQL> commit;
Commit complete.
PARTITION_NAME
------------------------------
P_FIRST
SYS_P101
REF Partitioning
• Related tables benefit from the same partitioning strategy.
Example:Orders and Line Items table
Child table inherits the same partitioning strategy as the parent table via
PK-FK relationships.
FOREIGN KEY
(order_id)
FOREIGN KEY
(order_id)
SQL> ALTER TABLE mycustomers ADD CONSTRAINT p_cust_id PRIMARY KEY (cust_id);
Table altered.
CREATE TABLE mysales
(cust_id NUMBER NOT NULL, quantity_sold NUMBER(10,2),
amount_sold NUMBER(10,2),
CONSTRAINT fk_sales_01
FOREIGN KEY (cust_id)
REFERENCES mycustomers(cust_id))
PARTITION BY REFERENCE (fk_sales_01);
9i extended to Range/List
Range 11g 9i 8i
Jan 08 …
Feb 08 …
… … …
…
Dec 08 …
… … …
…
Jan 08 Feb 08 Mar 08 Dec 08
Order_date
11g Virtual Column Partitioning
REF Partitioning Partitioning for a child table is (Parent) Orders table range
inherited from the parent table partitioned by order_date
through a primary key – and inherits the partitioning
foreign key relationship. The technique to (child) order
partitioning keys are not stored lines table. Column
in actual columns in the child order_date is only present in
table. the parent orders table
Virtual column based Defined by one of the Orders table has a virtual
Partitioning abovementioned column that derives the sales
partition techniques region based on the first
and the partitioning key is three digits of the customer
based on a virtual column. account number. The orders
Virtual columns are not stored table is then list partitioned
on disk and only exist as by sales region.
metadata.
Partition Data Dictionary Views
• DBA_PART_TABLES
• DBA_TAB_PARTITIONS
• DBA_TAB_SUBPARTITIONS
• DBA_PART_KEY_COLUMNS
• DBA_PART_HISTOGRAMS
• DBA_PART_INDEXES
• DBA_IND_PARTITIONS
DBA_IND_SUBPARTITIONS
Working with Partitions
Index partition
equipartitioned
with table
GLOBAL INDEX
• Cannot explicitly add or drop local index partitions – partitions to the index are
added or dropped based on partitions being added or dropped from base table.
• Most suited for DSS environments - easier to manage during data loads and
during partition-maintenance operations
SQL> select partition_name from user_tab_partitions where
table_name='ORDER_DETAILS';
PARTITION_NAME
---------------
P_FIRST
SYS_P81
SYS_P82
Index created.
PARTITION_NAME TABLESPACE_NAME
--------------- ------------------------------
P_FIRST EXAMPLE
SYS_P102 EXAMPLE
SYS_P103 EXAMPLE
Global Partitioned Index
• Can enable partition pruning to take place at the index level even if
not possible on the underlying partitioned table
CREATE INDEX order_id_ind_global
ON order_details (order_id)
Table Partitioned
GLOBAL PARTITION BY RANGE (order_id)
on order_date
(PARTITION p_ind1 values less than (100001),
PARTITION p_ind2 values less than (200001),
PARTITION p_ind3 values less than (300001)); PARTITION p_ind3
values less than (300001))
*
ERROR at line 6:
ORA-14021: MAXVALUE must be specified for all columns
PARTITION_NAME
------------------------------
SALES_1998 LOCAL Index
SALES_1999
SALES_2000
SALES_2001
P_2009
Table altered.
PARTITION_NAME STATUS
------------------------------ --------
SALES_1998 USABLE
SALES_1999 UNUSABLE
SALES_2000 USABLE
SALES_2001 USABLE
P_2009 USABLE
SQL> ALTER TABLE sales_data TRUNCATE PARTITION sales_1999_h2;
Table truncated.
PARTITION_NAME STATUS
------------------------------ --------
P1 UNUSABLE
P2 UNUSABLE
P_OTHERS UNUSABLE
System altered.
COUNT(*)
----------
310
SQL> EXPLAIN PLAN FOR SELECT COUNT(*) FROM sales_data
WHERE time_id ='01-DEC-1999';
Explained.
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------
Plan hash value: 1021418022
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 342 (26)| 00:00:05 | | |
| 1 | SORT AGGREGATE | | 1 | 9 | | | | |
| 2 | PARTITION RANGE SINGLE| | 276 | 2484 | 342 (26)| 00:00:05 | 2 | 2 |
|* 3 | TABLE ACCESS FULL | SALES_DATA | 276 | 2484 | 342 (26)| 00:00:05 | 2 | 2 |
------------------------------------------------------------------------------------------------------
Index altered.
SQL> EXPLAIN PLAN FOR SELECT COUNT(*) FROM sales_data WHERE time_id
='01-DEC-1999';
Explained.
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------
---------
Plan hash value: 3608419564
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 5 (0)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 9 | | | | |
| 2 | PARTITION RANGE SINGLE| | 310 | 2790 | 5 (0)| 00:00:01 | 2 | 2 |
|* 3 | INDEX RANGE SCAN | SALES_DATA_IND | 310 | 2790 | 5 (0)| 00:00:01 | 2 | 2 |
----------------------------------------------------------------------------------------------------------
Update Global Indexes
• By default, many table maintenance operations on partitioned tables invalidate
(mark UNUSABLE) global indexes.
• We can override this default behaviour if you specify UPDATE GLOBAL INDEXES.
• Partition DDL statement takes longer to execute since indexes which were
previously marked UNUSABLE are updated
• If using global partitioned indexes, can perform partition pruning on the index
partitions by eliminating index partitions even if table partitions cannot be
eliminated
• Range Partitioning
– range, equality and IN-list predicates
• Hash Partitioning
– equality and IN-list predicates
SQL> EXPLAIN PLAN FOR SELECT COUNT(*) FROM sales_data WHERE
time_id='21-JAN-2000';
Explained.
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------
---------
Plan hash value: 1021418022
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 246 (3)| 00:00:03 | | |
| 1 | SORT AGGREGATE | | 1 | 8 | | | | |
| 2 | PARTITION RANGE SINGLE| | 468 | 3744 | 246 (3)| 00:00:03 | 5 | 5 |
|* 3 | TABLE ACCESS FULL | SALES_DATA | 468 | 3744 | 246 (3)| 00:00:03 | 5 | 5 |
------------------------------------------------------------------------------------------------------
The Pstart and Pstop columns indicate that a single partition has been accessed
by the optimizer even though the “TABLE ACCESS FULL” operation is indicated
Partition-wise Joins
• Significantly improve the performance when joining tables with
millions of rows.
• Applies to Merge and Hash joins and not to Nested Loop joins.
Explained.
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------
---------------
Plan hash value: 4232629991
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 839K| 44M| 1158 (10)| 00:00:14 | | |
| 1 | HASH GROUP BY | | 839K| 44M| 1158 (10)| 00:00:14 | | |
| 2 | PARTITION HASH ALL | | 839K| 44M| 1085 (4)| 00:00:14 | 1 | 4 |
|* 3 | HASH JOIN | | 839K| 44M| 1085 (4)| 00:00:14 | | |
| 4 | TABLE ACCESS FULL| CUSTOMERS_HASH | 62069 | 1818K| 61 (2)| 00:00:01 | 1 | 4 |
| 5 | TABLE ACCESS FULL| SALES_DATA_HASH | 839K| 20M| 1012 (3)| 00:00:13 | 1 | 4 |
Statistics
----------------------------------------------------------
7 recursive calls
0 db block gets
4794 consistent gets
296 physical reads
0 redo size
18197 bytes sent via SQL*Net to client
932 bytes received via SQL*Net from client
42 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk) Note the physical reads and consistent
gets using the Partition wise join on Hash
Partitioned versus Non Partitioned tables
Statistics
--------------------------------------------
7 recursive calls
0 db block gets
6039 consistent gets
4100 physical reads
0 redo size
18197 bytes sent via SQL*Net to client
932 bytes received via SQL*Net from client
42 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
608 rows processed
Using DBMS_REDEFINITION
SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SH','SALES_NO_PART');
PARTITION_NAME
------------------------------
SALES_1998
SALES_1999
SALES_2000
SALES_2001
P_2009
COUNT(*)
----------
247945
PARTITION_NAME
------------------------------
SALES_1998
SALES_1999
SALES_2000
COUNT(*)
----------
259418
Table altered.
SQL> select partition_name from user_tab_partitions where table_name='SALES_NO_PART';
PARTITION_NAME
------------------------------
SALES_1998
SALES_1999
SALES_2000
SALES_2001
Table altered.
COUNT(*)
----------
259418
THANKS FOR ATTENDING!
Gavin Soorma
gavin.soorma@bankwest.com.au