15.4. BULK COLLECTOracle8i Database introduced a very powerful new feature that improves the efficiency of queries in PL/SQL: the BULK COLLECT clause Take a look at the following code snippet. I need to retrieve hundreds of rows of data on automobiles that have a poor environmental record. I place that data into a set of collections so that I can easily and quickly manipulate the data for both analysis and reporting.
This certainly gets the job done, but the job might take a long time to complete. Consider this: if the transportation table contains 2,000 vehicles, then the PL/SQL engine issues 2,000 individual fetches against the cursor in the SGA. To help out in this scenario, use the BULK COLLECT clause for the INTO element of your query. By using this clause in your cursor (explicit or implicit) you tell the SQL engine to bulk bind the output from the multiple rows fetched by the query into the specified collections before returning control to the PL/SQL engine. The syntax for this clause is:
where collection_name identifies a collection. Here are some rules and restrictions to keep in mind when using BULK COLLECT:
Let's explore these rules and the usefulness of BULK COLLECT through a series of examples. First, here is a rewrite of the major polluters example using BULK COLLECT:
I am now able to remove the initialization and extension code from the row-by-row fetch implementation. I don't have to rely on implicit cursors to get this job done. Here is another reworking of the major polluters example, retaining the explicit cursor:
And with Oracle9i Database Release 2 and above, I can simplify my life by fetching into a collection of records, as you see here:
15.4.1. Limiting Rows Retrieved with BULK COLLECTOracle provides a LIMIT clause
where rows can be any literal, variable, or expression that evaluates to an integer (otherwise, Oracle will raise a VALUE_ERROR exception). LIMIT is very useful with BULK COLLECT, because it helps you manage how much memory your program will used to process data. Suppose, for example, that you need to query and process 10,000 rows of data. You could use BULK COLLECT to retrieve all those rows and populate a rather large collection. However, this approach will consume lots of memory in the Process Global Area for that session. If this code is run by many separate Oracle schemas, your application performance may degrade because of PGA swapping. The following block of code uses the LIMIT clause in a FETCH that is inside a simple loop. Notice that I check the COUNT of the collection returned to determine if any rows were retrieved. The %FOUND and %NOTFOUND attributes should not be used to determine this.
15.4.2. Bulk Fetching of Multiple ColumnsAs you have seen in previous examples, you certainly can bulk fetch the contents of more than one column. It would be most elegant if we could fetch those multiple columns into a single collection of records. This feature became available in Oracle9i Database Release 2. Suppose that I would like to retrieve all the information in my transportation table for each vehicle whose mileage is less than 20 miles per gallon. In Oracle9i Database Release 2 and above, I can do so with a minimum of coding fuss:
Prior to Oracle9i Database Release 2, the above code would raise this exception:
If you are running Oracle8i Database or Oracle9i Database Release 1, you will need to declare multiple collections and then fetch individually into those collections:
Note that you can use the LIMIT clause with a BULK COLLECT into a collection of records, just as you would with any other BULK COLLECT statement. 15.4.3. Using the RETURNING Clause with Bulk OperationsYou've now seen BULK COLLECT used for both implicit and explicit query cursors. You can also use BULK COLLECT inside a FORALL statement, in order to take advantage of the RETURNING clause. The RETURNING clause, introduced in Oracle8 Database, allows you to obtain information (such as a newly updated value for a salary) from a DML statement. RETURNING can help you avoid additional queries to the database to determine the results of DML operations that just completed. Suppose that Congress has passed a law requiring that a company pay its highest-compensated employee no more than 50 times the salary of its lowest-paid employee. I work in the IT department of the newly merged company Northrop-Ford-Mattel-Yahoo-ATT, which employs a total of 250,000 workers. The word has come down from on high: the CEO is not taking a pay cut, so we need to increase the salaries of everyone who makes less than 50 times his 2004 total compensation package of $145 millionand decrease the salaries of all upper management except for the CEO. After all, somebody's got to make up for this loss in profit. Wow! I have lots of updating to do, and I want to use FORALL to get the job done as quickly as possible. However, I also need to perform various kinds of processing on the employee data and then print a report showing the change in salary for each affected employee. That RETURNING clause would come in awfully handy here, so let's give it a try. See the onlyfair.sql file on the book's web site for all of the steps shown here, plus table creation and INSERT statements. First, I'll create a reusable function to return the compensation for an executive:
In the main block of the update program, I declare a number of local variables and the following query to identify underpaid employees and overpaid employees who are not lucky enough to be the CEO:
At the start of my executable section, I load all of this data into my collections with a BULK COLLECT query:
Then I can use the names collection in my FORALL update:
I use DECODE to give an employee either a major boost in yearly income or an 80% cut in pay to keep the CEO comfy. I end it with a RETURNING clause that relies on BULK COLLECT to populate a third collection: the new salaries. Finally, because I used RETURNING and don't have to write another query against the compensation table to obtain the new salaries, I can immediately move to report generation:
Here, then, is the report generated from the onlyfair.sql script:
Now everyone can afford quality housing and health care. And tax revenue at all levels will increase, so public schools can get the funding they need.
|
Friday, November 6, 2009
Section 15.4. BULK COLLECT
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment