Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 14 ■ PARALLEL EXECUTION 631 This sounds all right at first, but in a data warehouse environment, this can lead to “wastage” after a large load. Let’s say you want to load 1,010MB of data (about 1GB), and you are using a tablespace with 100MB extents. You decide to use ten parallel execution servers to load this data. Each would start by allocating its own 100MB extent (there will be ten of them in all) and filling it up. Since each has 101MB of data to load, it would fill up its first extent and then proceed to allocate another 100MB extent, of which it would use 1MB. You now have 20 extents, 10 of which are full and 10 of which have 1MB each, and 990MB is “allocated but not used.” This space could be used the next time you load, but right now you have 990MB of dead space. This is where extent trimming comes in. Oracle will attempt to take the last extent of each parallel execution server and “trim” it back to the smallest size possible. Extent Trimming and Dictionary-Managed Tablespaces If you are using legacy dictionary-managed tablespaces, then Oracle will be able to convert each of the 100MB extents that contain just 1MB of data into 1MB extents. Unfortunately, that would (in dictionary-managed tablespaces) tend to leave ten noncontiguous 99MB extents free, and since your allocation scheme was for 100MB extents, this 990MB of space would not be very useful! The next allocation of 100MB would likely not be able to use the existing space, since it would be 99MB of free space, followed by 1MB of allocated space, followed by 99MB of free space, and so on. We will not review the dictionary-managed approach further in this book. Extent Trimming and Locally-Managed Tablespaces Enter locally-managed tablespaces. Here we have two types: UNIFORM SIZE, whereby every extent in the tablespace is always precisely the same size, and AUTOALLOCATE, whereby Oracle decides how big each extent should be using an internal algorithm. Both of these approaches solve nicely the problem of the 99MB of free space, followed by 1MB of used space, followed by 99MB of free space, and so on, resulting in lots of free space that cannot be used. However, they each solve it very differently. The UNIFORM SIZE approach obviates extent trimming from consideration all together. When you use UNIFORM SIZEs, Oracle cannot perform extent trimming. All extents are of that single size—none can be smaller (or larger) than that single size. AUTOALLOCATE extents, on the other hand, do support extent trimming, but in an intelligent fashion. They use a few specific sizes of extents and have the ability to use space of different sizes—that is, the algorithm permits the use of all free space over time in the tablespace. Unlike the dictionary-managed tablespace, where if you request a 100MB extent, Oracle will fail the request if it can find only 99MB free extents (so close, yet so far), a locally-managed tablespace with AUTOALLOCATE extents can be more flexible. It may reduce the size of the request it was making in order to attempt to use all of the free space. Let’s now look at the differences between the two locally-managed tablespace approaches. To do that, we need a real-life example to work with. We’ll set up an external table capable of being used in a parallel direct path load situation, which is something that we do frequently. Even if you are still using SQL*Loader to parallel direct path load data, this section applies entirely—you just have manual scripting to do to actually load the data. So, in order to investigate extent trimming, we need to set up our example load and then perform the loads under varying conditions and examine the results.
632 CHAPTER 14 ■ PARALLEL EXECUTION Setting Up To get started, we need an external table. I’ve found time and time again that I have a legacy control file from SQL*Loader that I used to use to load data. One that looks like this, for example: LOAD DATA INFILE '/tmp/big_table.dat' INTO TABLE big_table REPLACE FIELDS TERMINATED BY '|' ( id ,owner ,object_name ,subobject_name ,object_id ,data_object_id ,object_type ,created ,last_ddl_time ,timestamp ,status ,temporary ,generated ,secondary ) We can convert this easily into an external table definition using SQL*Loader itself: $ sqlldr big_table/big_table big_table.ctl external_table=generate_only SQL*Loader: Release 10.1.0.3.0 - Production on Mon Jul 11 14:16:20 2005 Copyright (c) 1982, 2004, Oracle. All rights reserved. Notice the parameter EXTERNAL_TABLE passed to SQL*Loader. It causes SQL*Loader in this case to not load data, but rather to generate a CREATE TABLE statement for us in the log file. This CREATE TABLE statement looked as follows (this is an abridged form; I’ve edited out repetitive elements to make the example smaller): CREATE TABLE "SYS_SQLLDR_X_EXT_BIG_TABLE" ( "ID" NUMBER, ... "SECONDARY" VARCHAR2(1) ) ORGANIZATION external ( TYPE oracle_loader DEFAULT DIRECTORY SYS_SQLLDR_XT_TMPDIR_00000 ACCESS PARAMETERS ( RECORDS DELIMITED BY NEWLINE CHARACTERSET WE8ISO8859P1 BADFILE 'SYS_SQLLDR_XT_TMPDIR_00000':'big_table.bad' LOGFILE 'big_table.log_xt' READSIZE 1048576 FIELDS TERMINATED BY "|" LDRTRIM REJECT ROWS WITH ALL NULL FIELDS ( "ID" CHAR(255) TERMINATED BY "|", .... "SECONDARY" CHAR(255)
- 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
- Page 656 and 657: CHAPTER 13 ■ PARTITIONING 611 So,
- Page 658 and 659: CHAPTER 13 ■ PARTITIONING 613 Aud
- Page 660 and 661: CHAPTER 14 ■ ■ ■ Parallel Exe
- Page 662 and 663: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 664 and 665: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 666 and 667: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 668 and 669: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 670 and 671: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 672 and 673: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 674 and 675: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 678 and 679: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 680 and 681: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 682 and 683: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 684 and 685: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 686 and 687: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 688 and 689: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 690 and 691: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 692 and 693: CHAPTER 14 ■ PARALLEL EXECUTION 6
- Page 694 and 695: CHAPTER 15 ■ ■ ■ Data Loading
- Page 696 and 697: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 698 and 699: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 700 and 701: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 702 and 703: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 704 and 705: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 706 and 707: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 708 and 709: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 710 and 711: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 712 and 713: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 714 and 715: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 716 and 717: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 718 and 719: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 720 and 721: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 722 and 723: CHAPTER 15 ■ DATA LOADING AND UNL
- Page 724 and 725: CHAPTER 15 ■ DATA LOADING AND UNL
CHAPTER 14 ■ PARALLEL EXECUTION 631<br />
This sounds all right at first, but in a data warehouse environment, this can lead to<br />
“wastage” after a large load. Let’s say you want to load 1,010MB of data (about 1GB), <strong>and</strong> you<br />
are using a tablespace with 100MB extents. You decide to use ten parallel execution servers to<br />
load this data. Each would start by allocating its own 100MB extent (there will be ten of them<br />
in all) <strong>and</strong> filling it up. Since each has 101MB of data to load, it would fill up its first extent <strong>and</strong><br />
then proceed to allocate another 100MB extent, of which it would use 1MB. You now have<br />
20 extents, 10 of which are full <strong>and</strong> 10 of which have 1MB each, <strong>and</strong> 990MB is “allocated but<br />
not used.” This space could be used the next time you load, but right now you have 990MB of<br />
dead space. This is where extent trimming comes in. <strong>Oracle</strong> will attempt to take the last extent<br />
of each parallel execution server <strong>and</strong> “trim” it back to the smallest size possible.<br />
Extent Trimming <strong>and</strong> Dictionary-Managed Tablespaces<br />
If you are using legacy dictionary-managed tablespaces, then <strong>Oracle</strong> will be able to convert<br />
each of the 100MB extents that contain just 1MB of data into 1MB extents. Unfortunately, that<br />
would (in dictionary-managed tablespaces) tend to leave ten noncontiguous 99MB extents<br />
free, <strong>and</strong> since your allocation scheme was for 100MB extents, this 990MB of space would not<br />
be very useful! The next allocation of 100MB would likely not be able to use the existing space,<br />
since it would be 99MB of free space, followed by 1MB of allocated space, followed by 99MB of<br />
free space, <strong>and</strong> so on. We will not review the dictionary-managed approach further in this book.<br />
Extent Trimming <strong>and</strong> Locally-Managed Tablespaces<br />
Enter locally-managed tablespaces. Here we have two types: UNIFORM SIZE, whereby every<br />
extent in the tablespace is always precisely the same size, <strong>and</strong> AUTOALLOCATE, whereby <strong>Oracle</strong><br />
decides how big each extent should be using an internal algorithm. Both of these approaches<br />
solve nicely the problem of the 99MB of free space, followed by 1MB of used space, followed<br />
by 99MB of free space, <strong>and</strong> so on, resulting in lots of free space that cannot be used. However,<br />
they each solve it very differently.<br />
The UNIFORM SIZE approach obviates extent trimming from consideration all together.<br />
When you use UNIFORM SIZEs, <strong>Oracle</strong> cannot perform extent trimming. All extents are of that<br />
single size—none can be smaller (or larger) than that single size.<br />
AUTOALLOCATE extents, on the other h<strong>and</strong>, do support extent trimming, but in an intelligent<br />
fashion. They use a few specific sizes of extents <strong>and</strong> have the ability to use space of different<br />
sizes—that is, the algorithm permits the use of all free space over time in the tablespace.<br />
Unlike the dictionary-managed tablespace, where if you request a 100MB extent, <strong>Oracle</strong> will<br />
fail the request if it can find only 99MB free extents (so close, yet so far), a locally-managed<br />
tablespace with AUTOALLOCATE extents can be more flexible. It may reduce the size of the<br />
request it was making in order to attempt to use all of the free space.<br />
Let’s now look at the differences between the two locally-managed tablespace approaches.<br />
To do that, we need a real-life example to work with. We’ll set up an external table capable of<br />
being used in a parallel direct path load situation, which is something that we do frequently.<br />
Even if you are still using SQL*Loader to parallel direct path load data, this section applies<br />
entirely—you just have manual scripting to do to actually load the data. So, in order to investigate<br />
extent trimming, we need to set up our example load <strong>and</strong> then perform the loads under<br />
varying conditions <strong>and</strong> examine the results.