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 587 | SELECT STATEMENT | | 1 | | | | PARTITION RANGE ALL | | 1 | 1 | 2 | | TABLE ACCESS BY LOCAL INDEX ROWID| PARTITIONED_TABLE | 1 | 1 | 2 | | INDEX RANGE SCAN | LOCAL_NONPREFIXED | 1 | 1 | 2 | ---------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("B"=1) Here the optimizer was not able to remove PART_2 of LOCAL_NONPREFIXED from consideration—it needed to look in both the PART_1 and PART_2 partitions of the index to see if B=1 was in there. Herein lies a performance issue with local nonprefixed indexes: they do not make you use the partition key in the predicate as a prefixed index does. It is not that prefixed indexes are better; it’s just that in order to use them, you must use a query that allows for partition elimination. If we drop the LOCAL_PREFIXED index and rerun the original successful query as follows: ops$tkyte@ORA10G> drop index local_prefixed; Index dropped. ops$tkyte@ORA10G> select * from partitioned_table where a = 1 and b = 1; A B DATA ---------- ---------- -------------------- 1 1 x it succeeds, but as we’ll see, it used the same index that just a moment ago failed us. The plan shows that Oracle was able to employ partition elimination here—the predicate A=1 was enough information for the database to eliminate index partition PART_2 from consideration: ops$tkyte@ORA10G> delete from plan_table; 4 rows deleted. ops$tkyte@ORA10G> explain plan for 2 select * from partitioned_table where a = 1 and b = 1; Explained. ops$tkyte@ORA10G> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------- | Operation | Name | Rows | Pstart| Pstop | ---------------------------------------------------------------------------------- | SELECT STATEMENT | | 1 | | | | PARTITION RANGE SINGLE | | 1 | 1 | 1 | | TABLE ACCESS BY LOCAL INDEX ROWID| PARTITIONED_TABLE | 1 | 1 | 1 | | INDEX RANGE SCAN | LOCAL_NONPREFIXED | 1 | 1 | 1 | ----------------------------------------------------------------------------------

588 CHAPTER 13 ■ PARTITIONING Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("A"=1) 3 - access("B"=1) Note the PSTART and PSTOP column values of 1 and 1.This proves that the optimizer is able to perform partition elimination even for nonprefixed local indexes. If you frequently query the preceding table with the following queries: select ... from partitioned_table where a = :a and b = :b; select ... from partitioned_table where b = :b; then you might consider using a local nonprefixed index on (b,a). That index would be useful for both of the preceding queries. The local prefixed index on (a,b) would be useful only for the first query. The bottom line here is that you should not be afraid of nonprefixed indexes or consider them to be major performance inhibitors. If you have many queries that could benefit from a nonprefixed index as outlined previously, then you should consider using one. The main concern is to ensure that your queries contain predicates that allow for index partition elimination whenever possible. The use of prefixed local indexes enforces that consideration. The use of nonprefixed indexes does not. Consider also how the index will be used. If it will be used as the first step in a query plan, there are not many differences between the two types of indexes. Local Indexes and Unique Constraints To enforce uniqueness—and that includes a UNIQUE constraint or PRIMARY KEY constraints— your partitioning key must be included in the constraint itself if you want to use a local index to enforce the constraint. This is the largest limitation of a local index, in my opinion. Oracle enforces uniqueness only within an index partition—never across partitions. What this implies, for example, is that you cannot range partition on a TIMESTAMP field and have a primary key on the ID that is enforced using a locally partitioned index. Oracle will instead utilize a global index to enforce uniqueness. In the next example, we will create a range partitioned table that is partitioned by a column named LOAD_TYPE, but has a primary key on the ID column. We can do that by executing the following CREATE TABLE statement in a schema that owns no other objects, so we can easily see exactly what objects are created by looking at every segment this user owns: ops$tkyte@ORA10G> CREATE TABLE partitioned 2 ( load_date date, 3 id int, 4 constraint partitioned_pk primary key(id) 5 ) 6 PARTITION BY RANGE (load_date) 7 ( 8 PARTITION part_1 VALUES LESS THAN 9 ( to_date('01/01/2000','dd/mm/yyyy') ) , 10 PARTITION part_2 VALUES LESS THAN 11 ( to_date('01/01/2001','dd/mm/yyyy') )

588<br />

CHAPTER 13 ■ PARTITIONING<br />

Predicate Information (identified by operation id):<br />

---------------------------------------------------<br />

2 - filter("A"=1)<br />

3 - access("B"=1)<br />

Note the PSTART <strong>and</strong> PSTOP column values of 1 <strong>and</strong> 1.This proves that the optimizer is able<br />

to perform partition elimination even for nonprefixed local indexes.<br />

If you frequently query the preceding table with the following queries:<br />

select ... from partitioned_table where a = :a <strong>and</strong> b = :b;<br />

select ... from partitioned_table where b = :b;<br />

then you might consider using a local nonprefixed index on (b,a). That index would be useful<br />

for both of the preceding queries. The local prefixed index on (a,b) would be useful only for the<br />

first query.<br />

The bottom line here is that you should not be afraid of nonprefixed indexes or consider<br />

them to be major performance inhibitors. If you have many queries that could benefit from<br />

a nonprefixed index as outlined previously, then you should consider using one. The main<br />

concern is to ensure that your queries contain predicates that allow for index partition elimination<br />

whenever possible. The use of prefixed local indexes enforces that consideration. The<br />

use of nonprefixed indexes does not. Consider also how the index will be used. If it will be<br />

used as the first step in a query plan, there are not many differences between the two types<br />

of indexes.<br />

Local Indexes <strong>and</strong> Unique Constraints<br />

To enforce uniqueness—<strong>and</strong> that includes a UNIQUE constraint or PRIMARY KEY constraints—<br />

your partitioning key must be included in the constraint itself if you want to use a local index<br />

to enforce the constraint. This is the largest limitation of a local index, in my opinion. <strong>Oracle</strong><br />

enforces uniqueness only within an index partition—never across partitions. What this<br />

implies, for example, is that you cannot range partition on a TIMESTAMP field <strong>and</strong> have a primary<br />

key on the ID that is enforced using a locally partitioned index. <strong>Oracle</strong> will instead utilize<br />

a global index to enforce uniqueness.<br />

In the next example, we will create a range partitioned table that is partitioned by a column<br />

named LOAD_TYPE, but has a primary key on the ID column. We can do that by executing<br />

the following CREATE TABLE statement in a schema that owns no other objects, so we can easily<br />

see exactly what objects are created by looking at every segment this user owns:<br />

ops$tkyte@ORA10G> CREATE TABLE partitioned<br />

2 ( load_date date,<br />

3 id int,<br />

4 constraint partitioned_pk primary key(id)<br />

5 )<br />

6 PARTITION BY RANGE (load_date)<br />

7 (<br />

8 PARTITION part_1 VALUES LESS THAN<br />

9 ( to_date('01/01/2000','dd/mm/yyyy') ) ,<br />

10 PARTITION part_2 VALUES LESS THAN<br />

11 ( to_date('01/01/2001','dd/mm/yyyy') )

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

Saved successfully!

Ooh no, something went wrong!