Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 13 ■ PARTITIONING 561 elsewhere to hold a copy of both indexes, you’ll need a temporary transaction log table to record the changes made against the base table during the time you spend rebuilding the index, and so on. On the other hand, if the index itself had been partitioned into ten 1GB partitions, then you could rebuild each index partition individually, one by one. Now you need 10 percent of the free space you needed previously. Likewise, the individual index rebuilds will each be much faster (ten times faster, perhaps), so far fewer transactional changes occurring during an online index rebuild need to be merged into the new index, and so on. Also, consider what happens in the event of a system or software failure just before completing the rebuilding of a 10GB index. The entire effort is lost. By breaking the problem down and partitioning the index into 1GB partitions, at most you would lose 10 percent of the total work required to rebuild the index. Alternatively, it may be that you need to rebuild only 10 percent of the total aggregate index—for example, only the “newest” data (the active data) is subject to this reorganization, and all of the “older” data (which is relatively static) remains unaffected. Finally, consider the situation whereby you discover 50 percent of the rows in your table are “migrated” rows (see Chapter 10 for details on chained/migrated rows), and you would like to fix this. Having a partitioned table will facilitate the operation. To “fix” migrated rows, you must typically rebuild the object—in this case, a table. If you have one 100GB table, you will need to perform this operation in one very large “chunk,” serially, using ALTER TABLE MOVE. On the other hand, if you have 25 partitions, each 4GB in size, then you can rebuild each partition one by one. Alternatively, if you are doing this during off-hours and have ample resources, you can even do the ALTER TABLE MOVE statements in parallel, in separate sessions, potentially reducing the amount of time the whole operation will take. Virtually everything you can do to a nonpartitioned object, you can do to an individual partition of a partitioned object. You might even discover that your migrated rows are concentrated in a very small subset of your partitions, hence you could rebuild one or two partitions instead of the entire table. Here is a quick example demonstrating the rebuild of a table with many migrated rows. Both BIG_TABLE1 and BIG_TABLE2 were created from a 10,000,000-row instance of BIG_TABLE (see the “Setup” section for the BIG_TABLE creation script). BIG_TABLE1 is a regular, nonpartitioned table, whereas BIG_TABLE2 is a hash partitioned table in eight partitions (we’ll cover hash partitioning in a subsequent section; suffice it to say, it distributed the data rather evenly into eight partitions): ops$tkyte@ORA10GR1> create table big_table1 2 ( ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME, 3 OBJECT_ID, DATA_OBJECT_ID, 4 OBJECT_TYPE, CREATED, LAST_DDL_TIME, 5 TIMESTAMP, STATUS, TEMPORARY, 6 GENERATED, SECONDARY ) 7 tablespace big1 8 as 9 select ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME, 10 OBJECT_ID, DATA_OBJECT_ID, 11 OBJECT_TYPE, CREATED, LAST_DDL_TIME, 12 TIMESTAMP, STATUS, TEMPORARY, 13 GENERATED, SECONDARY 14 from big_table.big_table; Table created.
562 CHAPTER 13 ■ PARTITIONING ops$tkyte@ORA10GR1> create table big_table2 2 ( ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME, 3 OBJECT_ID, DATA_OBJECT_ID, 4 OBJECT_TYPE, CREATED, LAST_DDL_TIME, 5 TIMESTAMP, STATUS, TEMPORARY, 6 GENERATED, SECONDARY ) 7 partition by hash(id) 8 (partition part_1 tablespace big2, 9 partition part_2 tablespace big2, 10 partition part_3 tablespace big2, 11 partition part_4 tablespace big2, 12 partition part_5 tablespace big2, 13 partition part_6 tablespace big2, 14 partition part_7 tablespace big2, 15 partition part_8 tablespace big2 16 ) 17 as 18 select ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME, 19 OBJECT_ID, DATA_OBJECT_ID, 20 OBJECT_TYPE, CREATED, LAST_DDL_TIME, 21 TIMESTAMP, STATUS, TEMPORARY, 22 GENERATED, SECONDARY 23 from big_table.big_table; Table created. Now, each of those tables is in its own tablespace, so we can easily query the data dictionary to see the allocated and free space in each tablespace: ops$tkyte@ORA10GR1> select b.tablespace_name, 2 mbytes_alloc, 3 mbytes_free 4 from ( select round(sum(bytes)/1024/1024) mbytes_free, 5 tablespace_name 6 from dba_free_space 7 group by tablespace_name ) a, 8 ( select round(sum(bytes)/1024/1024) mbytes_alloc, 9 tablespace_name 10 from dba_data_files 11 group by tablespace_name ) b 12 where a.tablespace_name (+) = b.tablespace_name 13 and b.tablespace_name in ('BIG1','BIG2') 14 / TABLESPACE MBYTES_ALLOC MBYTES_FREE ---------- ------------ ----------- BIG1 1496 344 BIG2 1496 344
- Page 556 and 557: CHAPTER 12 ■ DATATYPES 511 They a
- Page 558 and 559: CHAPTER 12 ■ DATATYPES 513 ■Not
- Page 560 and 561: CHAPTER 12 ■ DATATYPES 515 Coping
- Page 562 and 563: CHAPTER 12 ■ DATATYPES 517 Note t
- Page 564 and 565: CHAPTER 12 ■ DATATYPES 519 We are
- Page 566 and 567: CHAPTER 12 ■ DATATYPES 521 Format
- Page 568 and 569: CHAPTER 12 ■ DATATYPES 523 ops$tk
- Page 570 and 571: CHAPTER 12 ■ DATATYPES 525 You ca
- Page 572 and 573: CHAPTER 12 ■ DATATYPES 527 month
- Page 574 and 575: CHAPTER 12 ■ DATATYPES 529 DT2-DT
- Page 576 and 577: CHAPTER 12 ■ DATATYPES 531 DT TS
- Page 578 and 579: CHAPTER 12 ■ DATATYPES 533 ops$tk
- Page 580 and 581: CHAPTER 12 ■ DATATYPES 535 Since
- Page 582 and 583: CHAPTER 12 ■ DATATYPES 537 ops$tk
- Page 584 and 585: CHAPTER 12 ■ DATATYPES 539 ops$tk
- Page 586 and 587: CHAPTER 12 ■ DATATYPES 541 suppor
- Page 588 and 589: CHAPTER 12 ■ DATATYPES 543 Concep
- Page 590 and 591: CHAPTER 12 ■ DATATYPES 545 We can
- Page 592 and 593: CHAPTER 12 ■ DATATYPES 547 buffer
- Page 594 and 595: CHAPTER 12 ■ DATATYPES 549 Note t
- Page 596 and 597: CHAPTER 12 ■ DATATYPES 551 13 dbm
- Page 598 and 599: CHAPTER 12 ■ DATATYPES 553 equall
- Page 600 and 601: CHAPTER 12 ■ DATATYPES 555 ROWID/
- Page 602 and 603: CHAPTER 13 ■ ■ ■ Partitioning
- Page 604 and 605: CHAPTER 13 ■ PARTITIONING 559 6 (
- Page 608 and 609: CHAPTER 13 ■ PARTITIONING 563 BIG
- Page 610 and 611: CHAPTER 13 ■ PARTITIONING 565 Enh
- Page 612 and 613: CHAPTER 13 ■ PARTITIONING 567 Tab
- Page 614 and 615: CHAPTER 13 ■ PARTITIONING 569 tha
- Page 616 and 617: CHAPTER 13 ■ PARTITIONING 571 PAR
- Page 618 and 619: CHAPTER 13 ■ PARTITIONING 573 35
- Page 620 and 621: CHAPTER 13 ■ PARTITIONING 575 If
- Page 622 and 623: CHAPTER 13 ■ PARTITIONING 577 We
- Page 624 and 625: CHAPTER 13 ■ PARTITIONING 579 14
- Page 626 and 627: CHAPTER 13 ■ PARTITIONING 581 ops
- Page 628 and 629: CHAPTER 13 ■ PARTITIONING 583 In
- Page 630 and 631: CHAPTER 13 ■ PARTITIONING 585 ops
- Page 632 and 633: CHAPTER 13 ■ PARTITIONING 587 | S
- Page 634 and 635: CHAPTER 13 ■ PARTITIONING 589 12
- Page 636 and 637: CHAPTER 13 ■ PARTITIONING 591 ops
- Page 638 and 639: CHAPTER 13 ■ PARTITIONING 593 •
- Page 640 and 641: CHAPTER 13 ■ PARTITIONING 595 Now
- Page 642 and 643: CHAPTER 13 ■ PARTITIONING 597 the
- Page 644 and 645: CHAPTER 13 ■ PARTITIONING 599 imp
- Page 646 and 647: CHAPTER 13 ■ PARTITIONING 601 OLT
- Page 648 and 649: CHAPTER 13 ■ PARTITIONING 603 5 s
- Page 650 and 651: CHAPTER 13 ■ PARTITIONING 605 Sur
- Page 652 and 653: CHAPTER 13 ■ PARTITIONING 607 On
- Page 654 and 655: CHAPTER 13 ■ PARTITIONING 609 Row
CHAPTER 13 ■ PARTITIONING 561<br />
elsewhere to hold a copy of both indexes, you’ll need a temporary transaction log table to<br />
record the changes made against the base table during the time you spend rebuilding the<br />
index, <strong>and</strong> so on. On the other h<strong>and</strong>, if the index itself had been partitioned into ten 1GB partitions,<br />
then you could rebuild each index partition individually, one by one. Now you need<br />
10 percent of the free space you needed previously. Likewise, the individual index rebuilds will<br />
each be much faster (ten times faster, perhaps), so far fewer transactional changes occurring<br />
during an online index rebuild need to be merged into the new index, <strong>and</strong> so on.<br />
Also, consider what happens in the event of a system or software failure just before completing<br />
the rebuilding of a 10GB index. The entire effort is lost. By breaking the problem down<br />
<strong>and</strong> partitioning the index into 1GB partitions, at most you would lose 10 percent of the total<br />
work required to rebuild the index.<br />
Alternatively, it may be that you need to rebuild only 10 percent of the total aggregate<br />
index—for example, only the “newest” data (the active data) is subject to this reorganization,<br />
<strong>and</strong> all of the “older” data (which is relatively static) remains unaffected.<br />
Finally, consider the situation whereby you discover 50 percent of the rows in your table<br />
are “migrated” rows (see Chapter 10 for details on chained/migrated rows), <strong>and</strong> you would like<br />
to fix this. Having a partitioned table will facilitate the operation. To “fix” migrated rows, you<br />
must typically rebuild the object—in this case, a table. If you have one 100GB table, you will<br />
need to perform this operation in one very large “chunk,” serially, using ALTER TABLE MOVE. On<br />
the other h<strong>and</strong>, if you have 25 partitions, each 4GB in size, then you can rebuild each partition<br />
one by one. Alternatively, if you are doing this during off-hours <strong>and</strong> have ample resources,<br />
you can even do the ALTER TABLE MOVE statements in parallel, in separate sessions, potentially<br />
reducing the amount of time the whole operation will take. Virtually everything you can do to<br />
a nonpartitioned object, you can do to an individual partition of a partitioned object. You<br />
might even discover that your migrated rows are concentrated in a very small subset of your<br />
partitions, hence you could rebuild one or two partitions instead of the entire table.<br />
Here is a quick example demonstrating the rebuild of a table with many migrated rows.<br />
Both BIG_TABLE1 <strong>and</strong> BIG_TABLE2 were created from a 10,000,000-row instance of BIG_TABLE<br />
(see the “Setup” section for the BIG_TABLE creation script). BIG_TABLE1 is a regular, nonpartitioned<br />
table, whereas BIG_TABLE2 is a hash partitioned table in eight partitions (we’ll cover<br />
hash partitioning in a subsequent section; suffice it to say, it distributed the data rather evenly<br />
into eight partitions):<br />
ops$tkyte@ORA10GR1> create table big_table1<br />
2 ( ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME,<br />
3 OBJECT_ID, DATA_OBJECT_ID,<br />
4 OBJECT_TYPE, CREATED, LAST_DDL_TIME,<br />
5 TIMESTAMP, STATUS, TEMPORARY,<br />
6 GENERATED, SECONDARY )<br />
7 tablespace big1<br />
8 as<br />
9 select ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME,<br />
10 OBJECT_ID, DATA_OBJECT_ID,<br />
11 OBJECT_TYPE, CREATED, LAST_DDL_TIME,<br />
12 TIMESTAMP, STATUS, TEMPORARY,<br />
13 GENERATED, SECONDARY<br />
14 from big_table.big_table;<br />
Table created.