23.3. Dependency ManagementAnother important phase of PL/SQL compilation and execution is the checking of program dependencies Oracle's basic dependency objective for PL/SQL is, loosely speaking:
The good news is that most dependency management happens automatically, from the tracking of dependencies 23.3.1. Dependencies in Server-Side PL/SQLYou can use the server's data dictionary to explore dependency relationships in quite a bit of detail. Here's a simple illustration of this rule in action, using the data dictionary to give us eyes into the database. Let's say that I have a package named bookworm on the server. In this package is a function that selects from the books table. If I create the table and then create the package, I expect to see the following:
That is, there are two objects with the name BOOKWORM; the first is the package spec, and the second is the body. Right now, they're both VALID. Behind the scenes, Oracle has used its DIANA to determine a list of other objects that BOOKWORM needs in order to compile successfully. I can explore this dependency graph using a somewhat expensive query of the data dictionary view USER_DEPENDENCIES:
Figure 23-5 illustrates this information as a directed graph, where the arrows indicate a "depends-on" relationship. In other words, Figure 23-5 shows that:
Figure 23-5. Dependency graph of the bookworm packageFor purposes of tracking dependencies, Oracle records the package specification and body as two different entities. Every package body will have a dependency on its corresponding specification, but the spec will never depend on its body. Nothing depends on the body. Hey, it might not even have a body. If you've done much software maintenance in your life, you will know that performing impact analysis relies not so much on "depends-on" information as it does on "referenced-by" information. Let's say that I'm contemplating a change in the structure of the books table. Naturally, I'd like to know everything that might be affected:
Apparently, in addition to the bookworm package, there are some programs in my schema I haven't told you about, but fortunately Oracle never forgets. Nice! (By the way, a query on the referenced_name column is much faster than the earlier query on the "name" column.) As clever as Oracle is at keeping track of dependencies, it isn't clairvoyant: in the data dictionary, Oracle can only track dependencies of local stored objects written with static calls. There are plenty of ways that you can create programs that do not appear in the USER_DEPENDENCIES view. These include external programs that embed SQL or PL/SQL; remote stored procedures or client-side tools that call local stored objects; and any programs that use dynamic SQL. As I was saying, if I alter the table's structure by adding a column:
then Oracle will immediately and automatically mark everything that references the books table, including the bookworm package body, as INVALID. Any change in the DDL time of an objecteven if you just rebuild it with no changeswill cause Oracle to invalidate any programs that reference that object (see the later sidebar "Avoiding Those Invalidations."). Actually, Oracle's automatic invalidation is even more sophisticated than that; if you own a program that performs a particular DML statement on a table in another schema, and your privilege to perform that operation gets revoked, this action will also invalidate your program. After the change, this is what I have:
By the way, this again illustrates a benefit of the two-part package arrangement: for the most part, the package bodies have been invalidated, but not the specs, which can reduce the amount of recompilation required. The only spec that has been invalidated here is for FORMSTEST, which depends on the books table because (as I happen to know) it uses the anchored declaration books%ROWTYPE.
One final note: another way to look at programmatic dependencies is to use Oracle's DEPTREE_FILL procedure in combination with the DEPTREE or IDEPTREE views. As a quick example, if I run the procedure using:
I can then get a nice listing by selecting from the IDEPTREE view:
This listing shows the result of a recursive "referenced-by" query. If you want to run this built-in yourself, execute the utldtree.sql script (from the rdbms/admin subdirectory) to build the utility procedure and views in your own schema. Or, if you prefer, you can emulate it with a query such as:
Now that we have seen how the server keeps track of relationships among objects, let's explore one way that Oracle takes advantage of such information. 23.3.2. Healing InvalidsIn addition to becoming invalid when a referenced object changes, a new program may be in an invalid state as the result of a failed compilation. In any event, no PL/SQL program marked as invalid will run until a successful recompilation restores its validity. There are at least three ways that can happen:
23.3.2.1 Recompiling by handThe "by hand" method is simple, but it can be tedious. In the case presented earlier, I know by looking in the data dictionary that I need to recompile three stored programs, so I can just do this:
However, merely recompiling may be insufficient to recover from changes in the signature of a called program. You may have to edit the caller first! 23.3.2.2 Recompiling by scriptVarious scripts exist that can help you reduce the tedium of these recompilations. Later versions of Oracle provides several related scripts in the usual rdbms/admin subdirectory. Note that these must be run while logged in to the database as SYSDBA.
23.3.2.3 Automatic recompilationThe third method, automatic recompilation, is even simpler, but it isn't without drawbacks. If you merely execute one of the programs implemented in the bookworm package body, Oracle will recompile it just prior to execution. Production environments are likely to have strict policies on when you can and cannot recompile programs. That's because installing a new version of a PL/SQL program can force a lot of recompilation and can have disastrous side effects on programs currently running. You will probably want to run a script similar to utlrp.sql to find and recompile all invalid objects. Your DBA should help you schedule an upgrade procedure, which should include running a recompilation script. Aside from a potentially unscheduled drain on performance, the biggest drawback to Oracle's automatic recompilation feature is that it can interfere with packages that are currently running. The telltale sign of this will be a series of messages:
This happens because automatically recompiling a package that is currently running invalidates the package. Not only that, Oracle shares the program's bytecode among different sessions, so this invalidation affects not just the session that triggered the recompilation, but every Oracle session that has instantiated the package! Consequences of this devastation include the following:
Because all the packages executing in the current session have been reset, merely repeating the call should succeed; that is, the second call should not fail with the ORA-04068 error. Unless you expose and/or record the error numbers, it could look like some weird intermittent problem. I have written a number of scripts attempting to demonstrate this behavior in various scenarios, and have wound up with some strangely inconsistent resultsfor example, a script that produces the error twice out of 10 runs. I also have evidence, though, that recompiling the affected package with explicit ALTER...COMPILE commands reduces the ripple effect; instead of destroying the state of all packages for the current session, it seems to limit the "reset" to the package you're recompiling. The bottom line on automatic recompilation bears repeating. In live production environments, do not do anything that will invalidate or recompile (automatically or otherwise) any stored objects for which sessions might have instantiations that will be referred to again. Also, use a recompilation script. Fortunately, development environments don't need to worry about ripple effects too much, and automatic recompilation outside of production is a huge plus. 23.3.3. Remote DependenciesServer-based PL/SQL immediately becomes invalid whenever there's a change in a local object on which it depends. However, if it depends on an object on a different computer and that object changes, Oracle does not attempt to invalidate the calling PL/SQL program in real time. Instead, Oracle defers the checking until runtime. Here is a program that has a remote
If you recompile the remote procedure and some time later try to run synch_em_up, you are likely to get an ORA-04062 error with accompanying text such as timestamp (or signature) of package "SCOTT.recompute_prices" has been changed. If your call is still legal, Oracle will recompile synch_em_up, and if it succeeds, its next invocation should run without error. To understand Oracle's remote procedure call behavior, you need to know that the PL/SQL compiler always stores two kinds of information about each referenced remote procedure: its timestamp and its signature:
So when I compiled synch_em_up, Oracle retrieved both the timestamp and the signature of the remote procedure called recomputed_prices, and stored a representation of them with the bytecode of synch_em_up. How do you suppose Oracle uses this information at runtime? The model is simple: it uses either the timestamp or the signature, depending on the current value of the parameter REMOTE_DEPENDENCIES_MODE. If that timestamp or signature information, which is stored in the local program's bytecode, doesn't match the actual value of the remote procedure at runtime, you get the ORA-04062 error. Oracle's default remote dependency mode is the timestamp method, but this setting can sometimes cause unnecessary recompilations. The DBA can change the system-wide setting via the database initialization file or an ALTER SYSTEM command; an application developer can set it for the current session using the following command:
or, inside PL/SQL:
Thereafter, for the remainder of that session, every PL/SQL program run will use the signature method. As a matter of fact, Oracle's client-side tools always execute this ALTER SESSION ... SIGNATURE command as the first thing they do after connecting to the database, overriding whatever is in the Oracle initialization file. Oracle recommends using signature mode on client tools like Oracle Forms and timestamp mode on server-to-server procedure calls. Be aware that signature mode can cause false negativessituations where the runtime engine thinks that the signature hasn't changed, but it really hasin which case Oracle does not force an invalidation of a program that calls it remotely. You can wind up with silent computational errors that are difficult to detect and even more difficult to debug. Here are several risky scenarios:
In these cases, you will have to perform a manual recompilation of the caller. In contrast, the timestamp mode, while prone to false positives, is immune to false negatives. In other words, it won't miss any needed recompilations, but it may force recompilation that is not strictly required. This safety is no doubt why Oracle uses it as the default for server-to-server RPCs.
In the real world, minimizing recompilations can make a significant difference in application availability. It turns out that you can trick Oracle into thinking that a local call is really remote so that you can use signature mode. This is done using a loopback
database link inside a synonym. Assuming that you have an Oracle Net service name "localhost" that connects to the local database, here is a schematic example:
To take advantage of this arrangement, your production system would then include an invocation such as this:
As long as you don't do anything that alters the signature of volatilecode, you can modify and recompile it without invalidating save_from_recompile or causing a runtime error. You can even rebuild the synonym against a different procedure entirely. This approach isn't completely without drawbacks; for example, if volatilecode outputs anything using DBMS_OUTPUT, you won't see it unless save_from_recompile retrieves it explicitly over the database link and then outputs it directly. But for many applications, such workarounds are a small price to pay for the resulting increase in availability. |
Sunday, October 25, 2009
Section 23.3. Dependency Management
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment