Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 13 ■ PARTITIONING 607 On many occasions, I’ve seen that the implementation team will see they have a large table, say of 10 million rows. Now, 10 million sounds like an incredibly large number (and five or ten years ago, it would have been, but time changes all things). The team decides to partition the data. But in looking at the data, there are no logical attributes that make sense for RANGE partitioning. There are no sensible attributes for that. Likewise, LIST partitioning doesn’t make sense. Nothing pops out of this table as being the “right thing” to partition by. So, the team opts for hash partitioning on the primary key, which just happens to be populated by an Oracle sequence number. It looks perfect, it is unique and easy to hash, and many queries are of the form SELECT * FROM T WHERE PRIMARY_KEY = :X. But the problem is, there are many other queries against this object that are not of that form. For illustrative purposes, assume the table in question is really the ALL_OBJECTS dictionary view, and while internally many queries would be of the form WHERE OBJECT_ID = :X, the end users frequently have these requests of the application as well: • Show me the details of SCOTT’s EMP TABLE (WHERE OWNER = :O AND OBJECT_TYPE = :T ➥ AND OBJECT_NAME = :N). • Show me all of the tables SCOTT owns (WHERE OWNER = :O AND OBJECT_TYPE = :T). • Show me all of the objects SCOTT owns (WHERE OWNER = :O). In support of those queries, you have an index on (OWNER,OBJECT_TYPE,OBJECT_NAME). But you also read that “local indexes are more available,” and you would like to be more available regarding your system, so you implement with them. You end up re-creating your table like this, with 16 hash partitions: ops$tkyte@ORA10G> create table t 2 ( OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID, 3 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS, 4 TEMPORARY, GENERATED, SECONDARY ) 5 partition by hash(object_id) 6 partitions 16 7 as 8 select * from all_objects; Table created. ops$tkyte@ORA10G> create index t_idx 2 on t(owner,object_type,object_name) 3 LOCAL 4 / Index created. ops$tkyte@ORA10G> begin 2 dbms_stats.gather_table_stats 3 ( user, 'T', cascade=>true); 4 end; 5 / PL/SQL procedure successfully completed.

608 CHAPTER 13 ■ PARTITIONING and you execute your typical OLTP queries you know you run frequently: variable o varchar2(30) variable t varchar2(30) variable n varchar2(30) exec :o := 'SCOTT'; :t := 'TABLE'; :n := 'EMP'; select * from t where owner = :o and object_type = :t and object_name = :n / select * from t where owner = :o and object_type = :t / select * from t where owner = :o / but you notice that when you run this with SQL_TRACE=TRUE and review the resulting TKPROF report the following performance characteristics: select * from t where owner = :o and object_type = :t and object_name = :n call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 0 34 0 1 Rows Row Source Operation ------- --------------------------------------------------- 1 PARTITION HASH ALL PARTITION: 1 16 (cr=34 pr=0 pw=0 time=359 us) 1 TABLE ACCESS BY LOCAL INDEX ROWID T PARTITION: 1 16 (cr=34 pr=0 1 INDEX RANGE SCAN T_IDX PARTITION: 1 16 (cr=33 pr=0 pw=0 time=250 You compare that to the same table, only with no partitioning implemented, and discover the following: select * from t where owner = :o and object_type = :t and object_name = :n call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 0 5 0 1

CHAPTER 13 ■ PARTITIONING 607<br />

On many occasions, I’ve seen that the implementation team will see they have a large<br />

table, say of 10 million rows. Now, 10 million sounds like an incredibly large number (<strong>and</strong> five<br />

or ten years ago, it would have been, but time changes all things). The team decides to partition<br />

the data. But in looking at the data, there are no logical attributes that make sense for<br />

RANGE partitioning. There are no sensible attributes for that. Likewise, LIST partitioning doesn’t<br />

make sense. Nothing pops out of this table as being the “right thing” to partition by. So, the<br />

team opts for hash partitioning on the primary key, which just happens to be populated by an<br />

<strong>Oracle</strong> sequence number. It looks perfect, it is unique <strong>and</strong> easy to hash, <strong>and</strong> many queries are<br />

of the form SELECT * FROM T WHERE PRIMARY_KEY = :X.<br />

But the problem is, there are many other queries against this object that are not of that<br />

form. For illustrative purposes, assume the table in question is really the ALL_OBJECTS dictionary<br />

view, <strong>and</strong> while internally many queries would be of the form WHERE OBJECT_ID = :X, the<br />

end users frequently have these requests of the application as well:<br />

• Show me the details of SCOTT’s EMP TABLE (WHERE OWNER = :O AND OBJECT_TYPE = :T ➥<br />

AND OBJECT_NAME = :N).<br />

• Show me all of the tables SCOTT owns (WHERE OWNER = :O AND OBJECT_TYPE = :T).<br />

• Show me all of the objects SCOTT owns (WHERE OWNER = :O).<br />

In support of those queries, you have an index on (OWNER,OBJECT_TYPE,OBJECT_NAME). But<br />

you also read that “local indexes are more available,” <strong>and</strong> you would like to be more available<br />

regarding your system, so you implement with them. You end up re-creating your table like<br />

this, with 16 hash partitions:<br />

ops$tkyte@ORA10G> create table t<br />

2 ( OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,<br />

3 OBJECT_TYPE, CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS,<br />

4 TEMPORARY, GENERATED, SECONDARY )<br />

5 partition by hash(object_id)<br />

6 partitions 16<br />

7 as<br />

8 select * from all_objects;<br />

Table created.<br />

ops$tkyte@ORA10G> create index t_idx<br />

2 on t(owner,object_type,object_name)<br />

3 LOCAL<br />

4 /<br />

Index created.<br />

ops$tkyte@ORA10G> begin<br />

2 dbms_stats.gather_table_stats<br />

3 ( user, 'T', cascade=>true);<br />

4 end;<br />

5 /<br />

PL/SQL procedure successfully completed.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!