1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle PLSQL Language- P26

50 326 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Oracle PLSQL Language- P26
Trường học Unknown School
Chuyên ngành Oracle PLSQL Language
Thể loại document
Định dạng
Số trang 50
Dung lượng 136,91 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Tuning PL/SQL Applications Contents: Analyzing Program Performance Tuning Access to Compiled Code Tuning Access to Your Data Tuning Your Algorithms Overview of PL/SQL8 Enhancements Tunin

Trang 1

value as shown below:

new_rate := mortgage_rate (down_payment, prime_rate,

mortgage_type);

The mortgage_rate function was, unfortunately, setting new_rate to NULL After examining the function, it was clear to me that the only way it could return a NULL was if one of the inputs was NULL I then used this information as follows:

1 I had just examined the global variable holding the mortgage type That global value was transferred to the mortgage_type variable in an earlier program and passed to my current module, so I knew that it was OK

2 I performed a walk-through of the code and could not identify how any of the other two

variables could be NULL

3 So I inserted a trace statement before and after the call to mortgage_rate My code now looked like this:

DBMS_OUTPUT.PUT_LINE ('Inputs: ' || TO_CHAR (down_payment) || '-' ||

TO_CHAR (prime_rate));

new_rate := mortgage_rate ( down_payment, prime_rate, bank, mortgage_type);

DBMS_OUTPUT.PUT_LINE ('Rate: ' || NVL (TO_CHAR (new_rate), 'Missing'));

4 I ran the program and no matter what data I entered on the screen, my trace statements

remained the same:

Inputs: 55000-9.5Rate: Missing

I wracked my obviously overwrought brain: what could cause a stored function to return a NULL value? I looked at the source code for the function again There wasn't much to it Just division and multiplication How could it return a NULL without a NULL input?

After two hours of this nonsense, I finally said to myself, "Well, you know that you really haven't verified the value of the mortgage_type variable." I knew that it was OK, but, hey, it wouldn't hurt to check and if I didn't solve this one soon I would have to actually ask for help

So I modified my trace statement and, sure enough, the mortgage type was NULL Turns out that while the global variable held the proper value, the previous program did not pass it to the local

variable properly My assumption did me in

Trang 2

One of the first assumptions you will make in your testing is that you have valid inputs to your

program This can also be one of the most dangerous assumptions to make

Data errors are perhaps the most frustrating of all the kinds of bugs you will encounter You follow all the right steps for debugging and analyzing your code, only to discover that there is nothing

actually wrong with your program Instead, the data that drives your program is wrong

I encounter this problem most often in the following situations:

● I am testing my code in multiple database instances Never assume that the data structures and actual rows of data are identical in all instances Never assume that all indexes have been defined the same way

● The reference data is still unstable What is the valid code for a "closed" call? What are the ten valid company types? If this data is still changing, your program is likely to break

If you do not understand why your program is doing what it is doing, make a list of all your

assumptions and then test those including the data you rely on to run your program There is a good chance that your error was introduced very early into the process

24.2.8 Leverage Existing Utilities Or Build Your Own

As you build more and more complex programs, you will find it increasingly difficult and incredibly frustrating to manage and debug these programs without a utility of some kind Take the time to investigate what is available and what it will do for you

Historically, Oracle Corporation has been very slow to offer debugging and other

programmer-oriented utilities Third-party vendors seem to have taken a clue from Oracle and also have not

hurried to provide a strong set of tools for PL/SQL developers As of mid-year 1997, that situation is finally changing You can now purchase debuggers from the following vendors:

● Oracle Corporation: Procedure Builder

● Platinum Technology: SQL Station Debugger

● Technosolutions: SQL Navigator

● Compuware: XPediter/SQL

All of these products greatly improve the ability to debug client-side PL/SQL; you will need to

carefully examine the specific benefits and features before deciding which of these (and, I hope, by the time this book is published, others as well) fit your needs most closely

If, on the other hand, you cannot find anything that will help (or you can't get the approval to buy the utility of your dreams), you might consider building your own I have found in the past that it is

relatively straightforward to implement utilities that have a significant impact on my debugging

capabilities I built XRay Vision, a debugger for SQL*Forms, implemented entirely in SQL*Forms itself, which gave me the ability to view and modify all variables in my programs You'll find this

Trang 3

debugger, xrayvizn.zip, on the RevealNet Web site While you are unlikely to be using SQL*Forms at

this point, you may find the source code of interest (stored in the good, old INP files)

When Oracle Forms 4.x (even the version in Oracle Developer/2000 that has its own source code debugger) came along, I realized that it was impossible to view and change data structures created at runtime (record groups, parameter lists, etc.) So I built a utility named Arjy (pronounced "RG" for

Record Group), which gave me that access The shareware version of Arjy, arjy.zip is also available

at the RevealNet Web site

The basic PL/SQL product from Oracle Corporation will never have everything you need If you can't find what you need to get the job done, then get creative and take a crack at meeting your own needs Dive in and build your own utility Not only will you improve your productivity (and that of others), but you will gain a feeling of intense satisfaction from solving your own problems all by yourself

24.2.9 Build Debugging Messages into Your Packages

If you do not use a GUI-based, source code debugger, you probably spend a fair amount of time throwing debug or trace messages into your code and then removing them when things are fixed A much better approach is to leave these messages intact, but give yourself lots of flexibility in deciding when you want to see them

The simplest model for this technique is actually built right into the DBMS_OUTPUT package The DBMS_OUTPUT.PUT_LINE procedure displays output from your PL/SQL program when that program completes execution But it will not show anything unless the package itself is enabled with

a call to DBMS_OUTPUT.ENABLE and/or unless from within SQL*Plus you issue the SET

SERVEROUTPUT ON command Furthermore, this is an all-or-nothing proposition: you either see

no output, or you see output from every call to this procedure from every corner of your application That can be overwhelming if you have inserted lots of trace messages

You can easily come up with a more discerning technique when working with packages Suppose I have developed a package to perform calculations for profit-and-loss statements My p_and_l

package maintains a last statement date as a global variable for use within the package I build a "get and set" layer of code around the variable so that applications can retrieve and manipulate the

variable but only through my code layer Here is the package:

CREATE OR REPLACE PACKAGE p_and_l

IS

PROCEDURE set_lastdate (date_in IN DATE);

FUNCTION lastdate RETURN DATE;

/* Lots of other stuff, too! */

END p_and_l;

/

Trang 4

CREATE OR REPLACE PACKAGE BODY p_and_l

/* Date cannot be in future */

g_lastdate := LEAST (SYSDATE, date_in);

PROCEDURE set_lastdate (date_in IN DATE)

IS

BEGIN

DBMS_OUTPUT.PUT_LINE (`setting date to ` || TO_CHAR

(date_in));

/* Date cannot be in future */

g_lastdate := LEAST (SYSDATE, date_in);

END;

but then I have to see all the output in my application and try to find this one statement among all the others The approach I take instead is to provide a debug "toggle" in my package which allows me to focus output to just the statements I need to see With the toggle technique, I add three programs to

my package specification:

CREATE OR REPLACE PACKAGE p_and_l

IS

PROCEDURE set_lastdate (date_in IN DATE);

FUNCTION lastdate RETURN DATE;

PROCEDURE dbg;

PROCEURE nodbg;

FUNCTION debugging RETURN BOOLEAN;

Trang 5

/* Lots of other stuff, too! */

PROCEDURE dbg IS BEGIN g_dbg := TRUE; END;

PROCEDURE nodbg IS BEGIN g_dbg := FALSE; END;

FUNCTION debugging RETURN BOOLEAN RETURN g_dbg; END;

PROCEDURE set_lastdate (date_in IN DATE)

/* Date cannot be in future */

g_lastdate := LEAST (SYSDATE, date_in);

Trang 6

SQL> exec p_and_l.dbg

SQL> exec testing_program

before set 12-JAN-97

after set 15-JAN-97

Of course, you'd probably want to see more information, such as the execution call stack to see what program called the p_and_l.set_lastdate procedure You can add anything you want all within the confines of the IF debugging clause and that information will be available only on a need-to-know basis You might even decide to free yourself from the confines of DBMS_OUTPUT by writing information out to a database pipe

Furthermore, if you set as a standard in your group that every package is to have a debug toggle, then

it will be much easier for users of those packages to debug their own use (or misuse) of that reusable code They know that there will be a program named PKG.dbg which can be used to extract

additional information about package processing

This technique is explored in more detail and with a slightly different focus (production support) in

Chapter 26, Tracing PL/SQL Execution

Previous: 24.1 The Wrong

Way to Debug

Oracle PL/SQL Programming, 2nd Edition

Next: 25 Tuning PL/SQL Applications

24.1 The Wrong Way to

Trang 7

Previous: 24.2 Debugging

Tips and Strategies

Chapter 25 Next: 25.2 Tuning Access

to Compiled Code

25 Tuning PL/SQL Applications

Contents:

Analyzing Program Performance

Tuning Access to Compiled Code

Tuning Access to Your Data

Tuning Your Algorithms

Overview of PL/SQL8 Enhancements

Tuning an application is a very complicated process Really, it deserves a book of its own

Fortunately, there is such a book: Oracle Performance Tuning by Mark Gurry and Peter Corrigan.[1]

Many of the ideas in this section are drawn from and explored more thoroughly in Gurry and Corrigan's book

[1] O'Reilly & Associates, Second Edition, 1996 There are other books on Oracle

tuning as well

Before diving into the particulars, I want to be sure that you recognize the different aspects of tuning PL/SQL that you might want to perform:

Analyzing program performance Before you can tune your application, you need to figure out

what is running slowly and where you should focus your efforts

Tuning access to compiled code Before your code can be executed (and perhaps run too

slowly), it must be loaded into the System Global Area (SGA) of the Oracle instance This process can benefit from a focused tuning effort

Tuning access to your data Much of the tuning you do will attempt to optimize the way PL/

SQL programs manipulate data in the Oracle database, both queries and DML (updates,

inserts, deletes) Lots of the issues here involve tuning SQL statements (out of the scope of this book), but there are certainly steps you can take in your PL/SQL code and environment to improve the performance of even an optimally constructed chunk of SQL

Tuning your algorithms As a procedural language, PL/SQL is often used to implement

complex formulas and algorithms You make use of conditional statements, loops, perhaps even GOTOs and reusable modules (I hope) to get the job done These algorithms can be

Trang 8

written in many different ways, some of which perform very badly How do you tune poorly written algorithms? A tough question with no simple answers; I offer some case studies at the end of this chapter which will perhaps give you some fresh approaches to bring to bear on your own code

The following sections address each of these areas of PL/SQL tuning

25.1 Analyzing Program Performance

Before you can tune your application, you need to know what is causing it to slow down To do this, you usually need to be able to analyze the performance of your application Oracle offers a number of database monitoring and diagnostic tools, as do third-party vendors like Platinum Technology and

Quest Check Oracle documentation and Chapter 10 of Oracle Performance Tuning for more details,

and be aware of the following major tools:

A utility that translates the SQL_TRACE file into readable output and can also show the

execution plan for a SQL statement

A statement that compiles statistics for use by the cost-based optimizer to construct its

execution plan The statement also produces other useful information that can be used to

detect chained rows and help with capacity planning

UTLBSTAT (begin) and UTLESTAT (end)

Scripts that produce a snapshot of how the database is performing from the time you start UTLBSTAT until you run UTLESTAT

Enterprise Manager/Performance Pack

Trang 9

An Oracle product introduced with Oracle7.3 that provides some excellent tuning tools,

including Oracle Performance Manager, Oracle Trace, and Oracle Expert

25.1.1 Use the

DBMS_UTILITY.GET_TIME Function

The tools listed in the previous section provide varying levels of detail and granularity; however, they all do require some effort often on the part of a person other than the PL/SQL developer in need

to get them enabled And then they require even more effort to interpret results Don't get me wrong;

I am not really complaining It's just that, quite frankly, PL/SQL developers often want to examine the performance of a particular program and do not want to have to deal with all that other stuff

No problem! PL/SQL provides a mechanism to obtain timings of code execution that are accurate to 100th of a second: the DBMS_UTILTY.GET_TIME function Yes, that's right I said 100th of a second For those of you who have programmed in Oracle over the past few years, this should be a welcome surprise Before the advent of the DBMS_UTILITY package, the only way to measure elapsed time was to use SYSDATE and examine the difference in the time component Sadly, this component only records times down to the nearest second This doesn't help much when you need to measure subsecond response time

DBMS_UTILTY.GET_TIME returns the number of hundredths of seconds which have elapsed since some arbitrary point in time I don't remember what that point is and, well, that's the whole point A single value returned by a call to dbms_utility.get_time is, by itself, meaningless If, on the other

hand, you call this built-in function twice and then take the difference between the two returned

values, you will have determined the number of hundredths of seconds which elapsed between the

two calls So if you sandwich the execution of your own program between calls to DBMS_UTILTY.GET_TIME, you will have discovered how long it takes to run that program

The anonymous block below shows how to use GET_TIME to determine the time it takes to perform the calc_totals procedure:

Trang 10

substrings into a long string?

There are two basic approaches you can take to using this handy function:

● Write again and again the kind of script you see above, changing the program or lines of code executed

● Encapsulate the way dbms_utility.get_time operates inside a package, which will hide the details and make it easier to use

You will find on the companion disk an explanation and code for such a package, sp_timer, in the

files sptimer.sps and sptimer.spb In addition, you will find in Advanced Oracle PL/SQL

Programming with Packages a more complete performance timing utility based on DBMS_UTILITY.

GET_TIME in the PLVtmr package

Once you have encapsulated your usage of DBMS_UTILITY.GET_TIME, it is very easy to put together scripts which not only analyze performance, but also compare different implementations The following script, for example, executes two different versions of the is_number function (see

"Section 25.4, "Tuning Your Algorithms"" for more information on this function) and displays the resulting elapsed times (using the PLVtmr and p packages from the PL/Vision library; again, see

Advanced Oracle PL/SQL Programming with Packages:

SET VERIFY OFF

Trang 11

Next: 25.2 Tuning Access

to Compiled Code24.2 Debugging Tips and

Trang 12

Previous: 25.1 Analyzing

Program Performance

Chapter 25Tuning PL/SQL Applications

Next: 25.3 Tuning Access

to Your Data

25.2 Tuning Access to Compiled Code

Before your code can be executed (and perhaps run too slowly), it must be loaded into the System Global Area (SGA) of the Oracle instance (described in more detail in Chapter 23, Managing Code in

the Database) There are two elements to PL/SQL code in shared memory: the code segment and the data segment This loading process can benefit from its own special tuning effort

25.2.1 Tune the Size of the Shared Pool of the SGA

Before you can execute a stored package module or reference a stored package object, the compiled code for that package must be loaded into the SGA Clearly, if the package is already present in

shared memory, your code executes more quickly An important element of tuning an application which is heavily dependent on stored packages (especially large ones) is to optimize package access

so that the most often-used packages are always present when needed

The default method for maintaining packages in the SGA (or "shared pool") is to let the RDBMS manage the code using its least-recently-used algorithm The first time you reference a package, the compiled code is loaded into the shared pool It is then available to anyone with EXECUTE authority

on that package It remains in the shared pool until the memory is needed by other memory-based resources and that package has not been used most recently At that point, the package is flushed from the shared pool The next time an object in the package is needed, the whole package has to be loaded once again into memory

The larger your shared pool, the more likely it is that your programs will be resident in memory the next time they are needed Yet if you make your shared pool too large, you will be wasting memory You should monitor your shared buffer pool to make sure it is retaining all the parsed SQL cursors and PL/SQL code segments which are commonly referenced in your application If you find that too much swapping is occurring, increase the size of the shared buffer pool (as physical memory permits)

by adjusting the SHARED_POOL_SIZE parameter in your INIT.ORA file

You can display all the objects currently in the shared pool that are larger than a specified size (in the example, 25KB) with the following statement (make sure you have SET SERVEROUTPUT ON in SQL*Plus before you make this call):

Trang 13

SQL> exec dbms_shared_pool.sizes (25);

25.2.2 Pin Critical Code into the SGA

To increase your ability to tune application performance, Oracle supplies the

DBMS_SHARED_POOL package to pin a package in the shared pool When a package is pinned, the RDBMS does not apply its least-recently-used algorithm to that package The package remains in memory for as long as the database instance is available (or until you explicitly "unpin" the package,

Usually you will pin programs right after the database is started up, so that all the critical elements of your application are in place for all users Here is an example of the pinning of the order entry

package (owned by the appowner schema):

DBMS_SHARED_POOL.KEEP ('appowner.ordentry');

Here is the code you would execute to unpin the same package from shared memory:

DBMS_SHARED_POOL.UNKEEP ('appowner.ordentry');

Keep the following factors in mind when working with the DBMS_SHARED_POOL package:

● When you call the KEEP procedure, the package is "queued" for pinning in the SGA

However, the KEEP procedure does not immediately load the package into the shared pool that happens when the package is first referenced, either to execute a module or to use one of the declared objects, such as a global variable or a cursor

● Oracle recommends that you pin all your packages in the shared pool soon after instance

startup, when the SGA is still relatively unfragmented That way it can set aside contiguous blocks of memory for large packages

● If you pin a package which is not owned by SYS (DBMS_OUTPUT, for example, is owned

by SYS), you must grant EXECUTE on the package to PUBLIC before you execute the KEEP

Trang 14

procedure Once you have pinned the package, you can revoke the PUBLIC access

● The SQL DDL command, ALTER SYSTEM FLUSH SHARED_POOL, does not affect

pinned packages You must either explicitly UNKEEP a package or restart the database to release the package from the shared pool

25.2.2.1 Candidates for pinning in the shared pool

You might consider pinning the following packages in the shared pool to improve performance: STANDARD

Package which implements the core elements of the PL/SQL language

Package which allows programmers to display output to the screen

In addition, if you make frequent use of any other Oracle-provided "SYS" packages such as

DBMS_LOCK or DBMS_PIPE, pinning those objects could improve performance as well

You are probably getting the idea that the more you pin into the shared pool, the better off you are Certainly that is true, at least as true as the statement: "If all your data is stashed in memory, your applications will run much faster." Memory is always quicker than disk access The problem is

making sure you have enough memory

The more you pin into the shared pool, the less space is left in the SGA for other memory-based resources, such as data dictionary latches, application data, and shared SQL Since a pinned object is never aged out of the SGA using a least-recently-used algorithm, other elements in the SGA are instead pushed out of the way

You can use SQL to generate a script to KEEP packages in the SGA You can use the following SQL statement to access the v$db_object_cache to generate a KEEP for each package currently in the shared pool:

SELECT 'EXECUTE DBMS_SHARED_POOL.KEEP('''||name||''');'

FROM v$db_object_cache

Trang 15

25.2.3 Tune ACCESS$ Table to Reduce First Execution Time of Code

When a database object is first referenced in a PL/SQL program, the PL/SQL engine checks the

ACCESS$ table (owned by SYS) to see if the executor of the program has authority on that database object The structure of this table is shown here:

SQL> desc access$

Name Null? Type

-

D_OBJ# NOT NULL NUMBER

ORDER# NOT NULL NUMBER

COLUMNS RAW(32)

TYPES NOT NULL NUMBER

The PL/SQL engine searches through this table on the D_OBJ# column, so if you create a nonunique index on the D_OBJ# column, you may in some cases reduce significantly the amount of time needed

to perform this security check

25.2.4 Creating Packages with Minimal Interdependencies

Design your code (preferably, most of it inside packages) so that you only load into memory the code you need at any given moment in time To accomplish this objective, you should create more smaller packages, each of which is tightly focused on implementing functionality in a given area The

Trang 16

alternative, which too many of us employ without giving it much thought, is to create a few large packages that group together lots of different elements of functionality

The problem with this approach is that if I need to execute one function in that 32K package, the entire package still must be loaded up into memory Suppose that my application then touches

another element of the package, such as a constant or perhaps a different function in a different

functional area The least-recently-used algorithm will then ensure that all the memory for that

package continues to be set aside, perhaps crowding out other smaller programs The result can be excessive swapping of code

As you build your programs and design your package interfaces, be on the lookout for an opportunity

to break up a single package into two or even more distinct packages with minimal

interdependencies

25.2.5 Reducing Memory Usage of Package Variables

Prior to PL/SQL8, any data declared in a package simply stayed around until the end of the session, whether or not it was needed any more by the application This is an important feature of PL/SQL packages (persistent, global data), but it limits scalability since such memory grows linearly with the number of users

To help applications better manage memory usage, PL/SQL8 provides the pragma

SERIALLY_REUSABLE, which lets you mark some packages as "serially reusable." You can so mark a package if its state is needed only for the duration of a call to the server (for example, an OCI call to the server, a PL/SQL client-to-server, or server-to-server RPC)

The global memory for such packages is not kept in the memory area per user, but instead in a small SGA pool At the end of the call to the server, this memory is returned to the pool for reuse Before reuse, the package global variables are initialized to NULL or to the default values provided

The pool is kept in SGA memory so that the work area of a package can be reused across users who have requests for the same package In this scheme, the maximum number of work areas needed for a package is only as many as there are concurrent users of the package, which is typically much fewer than the total number of logged on users The use of "serially reusable" packages does increase the shared-pool requirements slightly, but this is more than offset by the decrease in the per-user memory requirements Further, Oracle ages out work areas not in use when it needs to reclaim shared pool memory

The following example shows how global variables in a "serially reusable" package behave across call boundaries:

CREATE OR REPLACE PACKAGE sr_pkg

IS

PRAGMA SERIALLY_REUSABLE;

num NUMBER := 0;

Trang 17

the body is required to have the pragma since the

specification of this package has the pragma

Initialize package state

PROCEDURE init_pkg(n NUMBER) IS

Now I will exercise this package First, I enable output from SQL*Plus:

SQLPLUS> set serveroutput on;

Next, I initialize the package with a value of 4 and then display package contents all within a single PL/SQL block:

SQLPLUS> begin

initialize and print the package

SR_PKG.init_pkg(4);

Print it in the same call to the server

We should see the new values

And we see that initial value of 4 If I had not placed the call to sr_pkg.print_pkg inside the same PL/

SQL block, however, that package variable would lose its setting, as you can see in the following steps:

Trang 18

Next: 25.3 Tuning Access

to Your Data25.1 Analyzing Program

Trang 19

Previous: 25.2 Tuning

Access to Compiled Code

Chapter 25Tuning PL/SQL Applications

Next: 25.4 Tuning Your Algorithms

25.3 Tuning Access to Your Data

Much of the tuning you do will attempt to optimize the way PL/SQL programs manipulate data in the Oracle database, both queries and DML (updates, inserts, deletes) Lots of the issues here involve tuning SQL statements, and I am not even going to attempt to show you how to tune SQL (definitely not my strong suit) There are certainly steps you can take, though, in your PL/SQL code and

environment to improve the performance of even an optimally constructed chunk of SQL

25.3.1 Use Package Data to Minimize SQL Access

When you declare a variable in a package body or specification, its scope is not restricted to any particular procedure or function As a result, the scope of package-level data is the entire Oracle session, and the value of that data persists for the entire session Take advantage of this fact to

minimize the times you have to access data from the SQL layer Performing lookups against

structures located in your own Program Global Area (PGA) is much, much faster than going through the SGA even if the data you want is resident in shared memory

This tip will come in handy most when you find that your application needs to perform multiple lookups which do not change during your session Suppose, for example, that one of your programs needs to obtain a unique session identifier to avoid overlaps with other sessions One of the ways to

do this is to call DBMS_LOCK.ALLOCATE_UNIQUE to retrieve a unique lockname Here is the inefficient way to do this: I need the ID or lockname in the calc_totals procedure So I make the call

to the built-in package right inside the procedure:

Trang 20

The problem with this approach is that every time calc_totals is called, the built-in function is also called to get the unique value a totally unnecessary action After you get it the first time, you

needn't get it again

Packages provide a natural repository for these "session-level" pieces of data The following sesspkg (session package) defines a variable to hold the lock name and then assigns it a value on initialization

processing inside sesspkg Instead, it simply returns the value resident in the constant

session-/* Filename on companion disk: dbdata.spp */

CREATE OR REPLACE PACKAGE db_data

IS

/* function to return the name of the database */

FUNCTION db_name RETURN VARCHAR2;

END db_data;

/

CREATE OR REPLACE PACKAGE BODY db_data

IS

Trang 21

/* DB_name variable only manipulated by this function

*/

v_db_name VARCHAR2(8) := NULL;

/* function to return the name of the database */

FUNCTION db_name RETURN VARCHAR2

NOTE: You will need to have access to the v$parameter table granted to you from

SYS if you want to compile and use this package outside of the SYS account

For a final example of using package data to reduce SQL I/O and improve performance, Chapter 10,

PL/SQL Tables, shows how you can use a PL/SQL table stored in a package to "remember" values which have already been queried in that session If the value is in the PL/SQL table, the function returns that value If not, it retrieves the value from the database table and, before returning the value, stores it in the PL/SQL table

25.3.2 Call PL/SQL Functions in SQL to Reduce I/O

Chapter 17, Calling PL/SQL Functions in SQL, explains how to create and place functions inside

SQL statements There are many advantages to this approach, which can result in cleaner, easier to read SQL and performance improvements The following example illustrates the use of packaged functions in SQL to minimize I/O in a SQL query (and thereby to improve performance); it also takes advantage of persistent package data to minimize data access

Suppose we are given a table of address information, primary-keyed by a unique system-generated identifier as follows:

CREATE TABLE addresses

(id NUMBER NOT NULL PRIMARY KEY

Trang 22

Suppose also that we have a complex view joining several tables and that one or more columns may

contain address identifiers (or be NULL) and that we want to join in a single address according to some prioritization:

CREATE VIEW termination_notices

use that address

ELSIF spouse_addr_id IS NOT NULL

multiple columns, we are in danger of doing address lookups four times per row (once for each column of the addresses table) This can be avoided by making use of the persistent state of package variables:

CREATE OR REPLACE PACKAGE address_info

Trang 25

Notice that the DECODEs handle the prioritization of which address to use based on whether

customer_addr_id and employer_addr_id are NULL Notice also that the package ensures that we will hit the address table at most once per row selected Certainly this is still a complex view, but we only have to scan the termination_notices view once, and we join in the correct address only when we need it

As you can see, taking full advantage of all of this technology to improve performance doesn't always result in very attractive code When you are faced with programs that do not meet minimal

requirements, however, you must be ready to abandon elegance and even (as a last resort) simplicity

to get the job done

25.3.3 Avoid Client-Side SQL

Set as a goal for yourself or your entire development team that no one ever places a chunk of SQL code on the client side of the divide Why? Because if you put all SQL or data access inside stored code in the database you get the following:

● You are much more likely to share that same SQL across multiple programs or even

applications This will result in a higher percentage of shared, preparsed SQL

● Multiple SQL statements can be batched together into a single procedure or function, so that a single network access kicks off a sequence of SQL activity on the server without unnecessary network traffic

Objections to this advice are often raised by Oracle Developer/2000 developers When you create a form in Oracle Forms, the base table block takes care of an awful lot of the required SQL, including some very complex locking mechanisms Am I saying that you should abandon all of that

Ngày đăng: 24/10/2013, 09:15

TỪ KHÓA LIÊN QUAN