PL/SQL for Dummies
NOTE: The material for
this paper was excerpted from PL/SQL for
Dummies (Rosenblum & Dorsey, 2006, Wiley Publishing, Inc.)
Being a good PL/SQL programmer means more than knowing all about
the latest features, obscure syntax for commands in the packages, VARRAYs,
object collections, and so on. Even if you are very knowledgeable about the
PL/SQL language, this does not automatically make you a good PL/SQL programmer.
Well-written code provides good performance and is bug-free
whenever possible. But even more important, the code is structured in such a
way that when modifications are necessary, it is easy to see where they are
needed. To help you create code that meets these goals, this paper discusses
some important best practices to keep in mind when programming in PL/SQL.
Why best practices are important
The following are some examples from actual systems where failure
to follow best practices caused companies to lose hundreds of millions of
dollars. In each case, the mistakes were not made by students or people
unfamiliar with PL/SQL, but by consultants from well-known consulting firms
doing work for very large companies on highly visible projects. Each one
resulted in catastrophic software failures for different reasons:
1.
The code ran so slowly that it made the system
unusable. It would have taken 26.5 years for a month-end routine to run.
2.
The code was so difficult to modify that it took 3.5
months to change the code in order to add a single attribute to one table.
3.
The system included so many complex rules that, even
after years of development, it never worked.
These failures were all due to the way in which the software and
its underlying code were designed and constructed and not because the
programmer did not know how to use a particular command.
Setting up a successful coding environment
Coding is 90 percent thinking and 10 percent actual writing of
the code. You need to learn how to think through a program before you write it.
Since it is unlikely that you will ever
undertake a PL/SQL project all on your own, this section discusses some of the
ways in which PL/SQL programmers can be good system development team players.
1. Make sure you understand the big picture
As a PL/SQL programmer, you might not have any control over the
larger system architecture, but you do need to understand that architecture in
order to create the appropriate code and integrate it into the rest of the
system. System architecture encompasses the overall design and structure of the
system as a whole including the following elements:
· Database
·
Business rules – how and where these will be
enforced
·
Programming languages
·
Programming algorithms
It is a very common mistake for programmers and developers to say
something like “I don’t need to understand the whole system; just tell me what
you want the code to do.” But being that short sighted is one of the reasons
that systems fail. To program well, you should keep the following principles in
mind:
· Understand the business function for your code. You should be able to accurately describe what your code does in terms that users can understand. The more clearly you can express what the code is intended to do, the more likely it is that the system will actually satisfy the user requirements. For example, when asking for help in debugging an algorithm, the first question that a good programmer should ask is, "What is the code supposed to do from a business perspective?" Until you understand the answer to that question, you will not be able to successfully debug the code.
· Frequently refer to a copy of the system data model showing the relevant portion of the database. Understanding the data model is important because you need to understand where the code you are writing fits into the bigger system. By keeping a copy of the entire system data model handy, you can continually check to make sure you understand what your piece of code is supposed to do and what other portions of the system might be impacted by it.
2. Communicate effectively
As a developer, you probably spend no more than 30 percent of
your time sitting alone, in front of a terminal, writing code. Most of the
time, you are working with a second developer (or pair programming), talking to
someone about getting the system requirements, or figuring out how to write the
code.
In all three project failures mentioned earlier, one common
mistake made was that people who were aware that the system failures were
likely to occur either neglected to call this to the attention of the system
architects or were ignored when trying to point out problems with the system
architecture. As the rules of the system are captured and coded, you might
discover that the architecture is inadequate to support the system requirements.
PL/SQL programmers should recognize possible problems in the system
architecture and point these out to the database designers and system
architects so that the necessary changes can be made.
3. Create a code specification
Before you ever start writing code, you need written
specifications. Writing good code specifications encourages developers to think
about what the code does and puts this information on paper. Having this
document makes talking to others about the code much easier and allows better
sharing of information. In modern development environments, it is not uncommon
to have Java and .
A good code specification describes what the software or program
modification entails at a reasonable level of detail. The specification
document should describe the function of the code as well as outline key design
decisions. For example, the document should address the following questions:
·
Why is this code or modification being written
(in business terms)?
·
What procedures will be created?
·
How will these procedures be named?
·
What modifications to the database (new tables,
columns, and so on) are required?
·
What are the detailed design constraints, if
any? (For example, “This is a rarely called routine from the user interface. As
long as it executes in less than half a second, it is okay.” or “This is a
critical batch routine that must execute in under an hour.”)
The specification should also include any special factors that
people need to take into account when developing or testing. An example might
be “This routine will be executed by many simultaneous users.”
By including all of this information in the code specification,
the probability that the team will understand the requirements and write good
code is significantly increased.
Remember that the goal is to create functioning code, and not to
create a large pile of documentation that few will read. Do not assume that the
code specification will be complete, accurate, or not undergo changes as the
project moves forward. As more code is written and changes are needed, you
might need to talk to users for additional clarification about some
undiscovered requirement or subtle area of the program. Having the
specification handy provides a starting point for discussion.
Integrating best practices into your code
When trying to decide how to proceed with coding a new project or
even making changes to an existing software project, how do you determine the
appropriate code structure? This section describes some of the things you can
do to write effective PL/SQL code that is maintainable over time, as well as
avoid some of the pitfalls common to many PL/SQL projects.
Stub out your code
Don’t just start writing code right from the beginning. First,
figure out how the code should be structured and create the necessary procedure
and function headers with no code in them. This gives you an idea of what
information will be needed at each point in your routine and what each routine
needs to return. These little “stubs” of code will help you see the overall
routine. If the project is very large, it will be easier to pass parts of the
code to someone else to write by using this “code outline.” By following this
stubbing method, your code will naturally be well structured and easier to
debug if something goes wrong.
Check the architecture as you go
Be sure that the underlying system architecture is sound before
spending days, weeks, or even months writing code. For example, one large batch
routine encountered was architected to make so many round trips to the database
that, even if all the complex logic that the program needed to perform executed
in zero time, the program would never execute within an acceptable time frame.
It had to be almost entirely rewritten in order to perform adequately. In
another situation, a program was designed to take precise code statements and
translate them into business language statements. The first attempt to create
the program was not able to logically manage the required elements. Although
this early version worked in limited circumstances, the code had to be completely
rewritten before it was usable in the larger system.
Following these guidelines will help ensure that the system
architecture is sound:
1. Periodically take a step back and evaluate
the system logic. Does the approach being used make sense? Draw the algorithm
on a white board and discuss it with a colleague. Sometimes, the exercise of
simply describing the algorithm to someone else can help clarify your thinking
and prevent serious coding errors from occurring.
2. Have someone review your code with you and
make sure that it works. Do not be afraid to take the time to run some
tests on your code.
3.
Check the
performance time of your code and its memory requirements. Just because a
particular architecture works well with a few sample data points and a single
user, the same code will not necessarily work on a production system with 100
million records and 200 simultaneous users.
4.
Be willing
to discard code and start over. Despite the planning and discussions, you
might create a bunch of code and still feel that something is not working
right. Often, the pressure to covering
ground is so great that no one bothers to notice that the project is headed for
failure. Stop periodically and ask these questions:
·
Is the team moving in the right direction?
·
Will the direction in which the team is going
ultimately result in a working system?
You might face an almost irresistible temptation to forge ahead
because so much time and effort has been invested. Unfortunately, in many
cases, if your intuition is telling you that the code will never work
correctly, it is probably right. It is better to discard all of the old code
and start over rather than trying to fix badly architected code.
“You can’t see the forest for the trees” is an important phrase
to remember when writing PL/SQL code. Do not allow yourself get so lost in
endless routines that you lose sight of the big picture. Every two weeks, you
should climb to the top of the tallest tree around (figuratively speaking, of
course) to see where you are, make sure that you are still going in the right
direction, and look out for any obstacles between you and your goal. Then climb
back down the tree, have a group meeting, and have the project manager clearly
point in the direction where everyone should be heading. The number of huge project failures that could
have been prevented by using this strategy is surprisingly large.
Prove sections of code work with test cases
The first time you use a feature that you have never used before,
make sure you understand how it works by writing a separate, small, example
program to demonstrate its functionality. Similarly, when you are embedding a
complex expression such as a combination of INSTR and SUBSTR or regular
expressions, isolate the piece of code in a simple SQL expression to prove that
the code is correct. This can save you hours of debugging time later.
One way you can make sure that your code works is by setting up
small test cases using DBMS_OUTPUT statements to print out interim results. Do
this frequently for each section of code written.
Use code libraries
Although you may think that you are the only person who will ever
need to use the code that you write, this is rarely the case. In any large
system, the same code will have been written dozens of times (frequently by the
same developer). If that code had been placed in a code library and referenced
each time it was used, there would not only be less code, but the remaining
code would be less prone to errors. Every time a piece of logic is rewritten,
there is the chance that the code will be written slightly differently. This
can cause code errors that are very difficult to find.
Code should be well documented and placed where it can be reused
easily. Code that is used only once in a large system is the exception rather
than the rule.
There are usually hundreds of reusable components in a large system, so you need to divide them into logical packages to avoid losing track of them.
Keep the code maintainable
The technology to support the myriad of information systems being
used to work with databases seems to evolve faster and faster with each passing
year. Designing and coding a system that can be used and easily maintained over
time requires some thought and skill. Make sure that someone else down the road
will be able to read and understand your code and find potential problem areas.
Think about performance
In addition to understanding what the program you are creating
needs to do, you need to have some sense about how fast the code needs to
execute and return the desired information. To create a month-end routine that
must interact with other batch routines and execute within a 4-hour time
window, your portion of the program might need to execute in 10-20 minutes.
Understanding what constitutes acceptable performance in a given situation is
very important.
You also need to know how often a given programming routine will be run. PL/SQL is capable of supporting a range of capabilities, some of which are used only once, such as data migration routines or low-level translations for changing system time into local time around the world that might be accessed millions of times a day. If a routine will be run only once, performance and maintainability of the code are not critical issues.
Be careful before deciding that a routine will never be used
again and discarding the code. Very often, you will find that you need to run
the same or a very similar routine to one you wrote a few months ago.
Compile as you go
Many inexperienced programmers create an entire first draft of a
program (possibly hundreds of lines of code) without ever compiling it. When
they do compile the code for the first time, hours of debugging are usually
required. Writing more than a few lines of code without at least one mistake is
very unusual, even for experienced programmers. Sometimes errors are nothing
more than simple misspellings or typos, but errors are inevitable.
Compile your code every few minutes from the very beginning of the process. When writing a new function or procedure, create the function name with one line of code (which might even be NULL;) and save it before doing anything further. Every few lines, compile the code again to check for errors. Never write more than about ten lines of code without compiling it.
Debug efficiently
If your code does not work, how can you fix it? It might not
compile or it might compile and not do what you expect it to do. The most
important thing to remember when debugging is to always start with a piece of
code that works. The first step to take when the code will not compile or
behave as expected is not to look through the code to try to find the problem. Programs
can be made up of thousands of lines of code. The problem might not be located
in an obvious place. Comment out portions of the code until it runs successfully.
This will help to pinpoint where the problem is occurring.
Commenting
Commenting is a very effective technique that allows you to
remove selected portions of the code to help isolate problems quickly and
efficiently. This same technique can be used for both compilation and logic
errors.
The SQL compiler is not perfect. Sometimes it will indicate that an error exists in a place that is far from the actual mistake. Unfortunately, this often occurs in some of the most common types of errors, namely forgetting a semicolon, missing a comma in a SELECT statement, and missing an END statement.
With a compilation error messages may not be very helpful.
Therefore you should not let your routines get too large in the first place. If
you limit your routines to no more than a few hundred lines, even a problem
that results in a misleading compilation error will not be as difficult to
find.
When your routine is in a package, it is common for packages to
contain hundreds, if not thousands, of lines of code. Finding an error will be
more difficult without using the commenting technique to sequentially add
portions of the routine until the error is found. In complex routines, it is
helpful to comment out individual lines to narrow down where the compilation
error is occurring.
The technique of commenting and un-commenting portions of a
routine to help isolate a problem is very easy to use. A programmer should
always have an idea about where to find the problem area in the code. It is
acceptable not to know how to fix the problem, but even beginning programmers
should be able to locate the precise trouble spot in the code.
Finding out what
the program is doing at various points
Using a PL/SQL Integrated Development Environment (IDE) often
includes some sophisticated debugging functionality that allows you to set
watches (where you can see the values of variables) and breakpoints (places
where you pause the program) in your code. Knowing how to use these features will
greatly assist you in finding errors. Each IDE has its own debugging features. You
might also want to use DBMS_OUTPUT or autonomous transactions to log
information to a database table.
Testing your code
Often, the members of the Quality Assurance (QA) team who test
the code are the most unpopular members of the development team. They are the people
who get in the way of pushing things out the door. Inexperienced developers
will do anything they can to avoid the QA process. Experienced developers
recognize that no code is perfect. Having another set of eyes looking at your
code greatly reduces the chance that errors will be missed.
If the QA team does nothing more than making sure you have filled
out the proper paperwork and put a comment block at the top of your code, your
QA process is not sufficient. The QA process helps to make sure that code is
well written and that standards have been followed.
It is not sufficient to deliver a program after running it once
without noticing any errors or problems. You must be much more thorough. You
must make sure that your code does what it was intended to do. Proving that the
code you have written works in the way you expect is just as important as
writing it correctly in the first place. In recent years, software testing has
become a much more disciplined practice.
Understanding the following basics of testing can improve the
quality of your code:
·
The
essence of testing is the idea of an assertion.
You assert that the software will do X when Y. Each test can be translated
formally into such an assertion.
·
There are
different types of tests. Some involve a manual set of steps that need to
be performed by a human tester. However, whenever possible, tests should be
written as code scripts that can be easily run every time someone modifies the
code.
·
The cost
of delivering bad software is much more expensive than testing. If your
code isn’t tested carefully enough, you might think it works, and then later
someone will discover that the system has a problem. The problem might require
many hours (or weeks) to be tracked down and isolated. Then, many more hours
(or weeks) will be spent figuring out how to fix the code. As a result of the
problem, the database might have incorrect data in it that will require time to
fix. Testing software is expensive, but not testing software is much more
expensive.
·
Even
thorough testing does not guarantee perfect code. It is not possible to
test everything. The most you can do is ensure core functionality. Anyone can
easily miss subtle problems. Usually, the best approach is to test all the main
functions and deal with the bugs when they are found.
If your software has to be perfect, you have a very difficult
job. Ensuring perfection in software means that you will spend many times the
development cost of the software in testing that software. When building
software where bugs can result in serious consequences, count on spending lots
of time testing. Software that controls medical devices, some military systems,
and systems that control financial institutions all need to be tested
differently from most business systems. Even then, it is very hard to find
every problem. In such cases, the errors can have catastrophic effects on the
organization. In one well-publicized software error, a simple coding error
caused a multi-billion dollar loss to AT&T and an outage of phone service
along most of the eastern seaboard.
The following list includes
a brief description of ten of the most important things to remember when
working with PL/SQL
1. Use SELECT INTO correctly
Each time you use SELECT INTO, remember that your query might
return more than one row, or no rows at all. Therefore, you need to include
exception handlers to take care of these situations if there is any possibility
of them occurring. The reason this is so important is that your code might
execute correctly for many months before some unusual condition shows up that
causes it to fail. Then you can spend days trying to figure out what went
wrong.
When working with the BULK COLLECT clause, you need to check for
the number of fetched records because the exception NO_
2. Do not assume column order in DML statements
When you have a DML statement in your code, you should explicitly
list the columns that you are referencing. Never assume that the number and
order of the columns in a table or view are constant. Columns that are added to
a table later will break your code. Rebuilding your database might result in
the default column order being changed.
When working with a large number of columns, using variables of
type RECORD is a better approach. With this approach, you do not have to list
anything in the INSERT statement, because you are inserting a variable into the
table that is defined as a row from the same table. There is no chance for
inconsistency.
Another good reason for having a variable of type RECORD is that
it is a much easier way of passing data to different routines. For example, you
might have a procedure that will perform validation for the data you entered.
You would need to pass only one variable and not a whole list of columns.
3. Use the NOCOPY command
Use NOCOPY when passing an IN/OUT parameter to avoid passing by
value. This is mainly a performance rather than a logic issue.
Normally when you pass an IN/OUT parameter, Oracle makes a copy
of the parameter in memory and uses that copy in the called program unit. When
the program unit is executed, it copies the values back to the original
variable. Performing this operation once does not take a lot of time, but in a
procedure that is called thousands of times, the time can add up.
NOCOPY is just a hint, not a directive. This means that Oracle
may ignore it. Also, depending upon the version of Oracle used, there are a
number of restrictions on using NOCOPY. But if you violate one of those
restrictions, there will be no raised error. Oracle will ignore your hint
without notifying you.
Another thing to be aware of when using a NOCOPY hint is
exception handling. If you are passing a variable by value to a subroutine and
that routine fails, the original value of the variable does not change. But if
you are passing the variable by reference, the failed subroutine might have
changed the original variable’s value (before it failed), unless you have an
exception-handling block in that subroutine.
4. Be careful of function calls that impact performance
If you have a loop and need to calculate some values, ask
yourself whether you can perform the calculations before the loop, or reduce
the number of times the calculations are performed within the loop. Otherwise,
you might be running the same function many more times than needed. You can
decrease that overhead in a number of ways. The idea is to cache the calculated
data in the local variables.
The same logic of reducing the number of executions is true not
only for user-defined functions and procedures, but for built-in ones. Even
executing SYSDATE several hundred thousand times could cause some problems. If
you need to move a few million records from a production table to an archive,
use the following logic:
A function in an SQL statement will execute at least once for
every row returned. However, sometimes in SQL queries joining multiple tables,
the function might execute so many times that the query never returns. You have
to look closely at the execution plan of the query to see how many times the
function will execute.
5. Beware of implicit commits
Any DDL command causes an implicit commit. This is not a major
issue because you will not usually have DDL commands in your code. But every
experienced developer has encountered situations similar to the following when
building a system: Imagine that you insert or delete a bunch of data, and then
you recompile your procedure and your changes are instantly committed. The
problem is that you might not need to commit (for example, you just discovered
a bug in your code).Always think about any uncommitted changes whenever
performing DDL operations.
Be careful! The TRUCNATE TABLE command is also DDL and forces an
explicit commit, as well.
Each time you work with the data and the code simultaneously, try
to do only one thing at a time. Always use an explicit commit or rollback
before you start modifying your code.
The same problem of unintentional commits could happen if you are
using Dynamic SQL to build DDL statements on the fly. What if you forgot to
check whether the hard drive had enough space and the CREATE TABLE failed? Even
a failed DDL command issues a commit. As a result this command updates the
table even though the backup was not completed.
This problem has a number of solutions. The simplest is to modify
the code so that, at the moment of DDL execution, there is no uncommitted data
that would be rolled back in case of a fatal error.
An alternative and more efficient solution involves using
autonomous transactions. Autonomous transactions do not see uncommitted parent
changes. You have to either commit or roll back your changes before the return
(whether the return is successful or not) from the function or procedure
declared as an autonomous transaction to ensure that your function can be used
appropriately.
6. Only use one RETURN statement per function
Keeping function returns to a minimum is important. One very
useful technique is to use a single OUT point in the routine. This means that
·
Functions have only one RETURN statement.
·
The RETURN statement should be the last line
before the exception block.
By remembering these rules, you can clearly see when a
function expects to return a value.
7. Use WHEN OTHERS to save debugging time
Most programmers know better than to use WHEN OTHERS THEN NULL in
their code because it hides errors and makes the code harder to debug. However,
using the exception WHEN OTHERS can save you a lot of debugging time because it
captures unpredictable events.
Many things can go wrong in your code, but explicitly placing
exception handlers to cover all situations is impossible. On the other hand,
debugging an exception raised somewhere deep in a chain of function calls is
also difficult.
The exception WHEN OTHERS allows you to intercept these unspecified exceptions. But what do you do with them? One option is to log an error message. Although developers need to know what is going on in the system, it is not possible to return an error to the end user in all cases.
If you do not want to intercept the error, you can always
re-raise an exception in the exception block. Using this approach, the routine
raises the same error that it would raise without exception handling, but now
you have a log record indicating the existence of an error. This log can be
very useful in debugging.
8. Understand when to pass parameters or use global variables
In a stateless, Web-based environment, cursors, functions, and
procedures sometimes are unable to reference values outside of themselves.
Instead, they should pass parameters.
Although global variables might appear very convenient, there is
a good reason for passing parameters into the routines instead of keeping
global values. In an environment with stateless Web applications, you cannot be
sure of getting the same session each time you request the data.
Code can be formatted for a client/server environment, where
packaged variables can be used as session-level global variables. But in a
Web-based environment, you cannot always guarantee that your second request
will go to the same session. This means that, instead of keeping global
variables in the session, the global variables become properties of the client.
(Some Web developers store them as cookies in browsers.) Therefore, you need to
pass all parameters explicitly. Before writing any APIs to support front-end
developers, you need to understand the environment in which they are working.
If you cannot guarantee that subsequent calls will be in the same session, you
need to make sure that all necessary variable values are passed on each call to
the program unit.
9. Use implicit cursors when appropriate
Implicit cursors are marginally faster than explicit cursors for
single record fetches. But, the main reason to use them is that they make code
easier to read. Instead of having a cursor in the declaration section of your
code that is referenced in the body of the code (as with an explicit cursor),
the cursor is defined right where it is executed.
Because there is now no good reason to use explicit cursors
whenever you need to get a single record, use implicit cursors instead. Code
using implicit cursors is usually cleaner, but keep the following issues in
mind:
·
You cannot simply replace explicit cursors with
implicit ones. Explicit cursors do no raise the exceptions NO_
·
To store a fetched value, you can reference an
explicit cursor with %ROWTYPE, but with an implicit one you have to think about
the appropriate variables into which to fetch the data.
10. Dates are numbers
Internally in Oracle, dates are really numbers, so you can
perform numeric operations against dates. Oracle 9i and 10g have new
datatypes to store dates: TIMESTAMP and INTERVAL. But good old dates are still
very useful when you do not need to know the time zone or granularity below the
time unit of a second. Internally, dates are stored as numbers, so you can do
whatever you want with them. A common set of date tasks can be resolved if you
think about dates as numbers.
Top 10 PL/SQL "Don’ts"
The following list includes a brief description of ten of the
most important things NOT to do when working with PL/SQL. Be sure to preface
each of the headings in this section with a big
1. Catch an exception with WHEN OTHERS THEN NULL
Never catch an unidentified exception without logging information
about it. The exception handler WHEN OTHERS is extremely useful, but it can
also be the source of the most dangerous line of code that can exist in PL/SQL,
as shown here:
begin
...
exception
when others then
null;
end;
Unless you are in the debugging or development mode, never use an
exception handler like this, especially in production instances of a system. All
exception handlers that have WHEN OTHERS without additional activity (you might
need to have that exception) should not raise an exception if something goes
wrong, but instead, returning and log an ERROR You can use this logic if,
because of front-end restrictions, you cannot throw Oracle exceptions (for
example, in a Web-based environment). This technique is a cleaner way of
notifying the front end that something has gone wrong without destroying
performance, and it also provides useful debugging information.
2. Forget to handle NULL values
Operating on variables or columns that might contain NULL values
without explicitly handling these NULL values can cause problems and produce
strange results. The reason for this is that NULL is handled differently from
other values. You should keep the following rules in mind:
1. All logical operations (including NOT) that
involve NULL values always return FALSE.
2. All operations (built-in functions,
arithmetic) with NULL return NULL, with the following exceptions:
·
Concatenations of strings ignore NULL.
·
DECODE can compare values with NULL.
In grouping functions (SUM, AVG, COUNT), you also need to watch
out for NULL values. The rule is that these functions process only not-NULL
values; but if all values are NULL, the result is also NULL, as shown here:
3. Create unintended Boolean expressions
Be careful when building complex logical conditions. You need to
group logical conditions appropriately so that others can maintain your code in
the future. After grouping the rules, convert the group into logical
operations. Each group of conditions should be enclosed in parentheses.
You should use the same syntax rule of enclosing condition groups in parentheses, not only in PL/SQL but in SQL, too. Remembering this could save you hours of debugging afterward.
4. Forget to close an explicit cursor
Each time you use an explicit cursor, don’t forget to close it. Using explicit cursors is good coding practice. Remember that the database parameter OPEN_CURSORS defines the maximum number of cursors that can be open at the same time. The value of the variable might change from one environment to another, but the point is that the number of cursors is limited. Forgotten cursors that are left open can bring a system to a halt.
But with dynamic SQL, you have to use explicit cursors. If you
stick to the following rules, you should be able to use explicit cursors
successfully:
·
When you start typing a routine, immediately
include both the OPEN and CLOSE cursor statements.
·
Never add a RETURN clause before closing the
cursor.
·
In the exception-handling block, always check to
see whether explicit cursors are open, and if so, close them.
If you are using recursive calls to the same routine, be very
careful about using explicit cursors. In a structure with 20 levels of
hierarchy, at some point, you are likely to have 20 cursors open
simultaneously. If you have a large number of users, this could cause your
system to reach or exceed the maximum number of cursors.
Oracle is fairly smart about closing cursors if you forget to do
so. When a program unit terminates, all cursors that it opened are
automatically closed. But relying on this capability is dangerous and can
ultimately result in having too many cursors open at once, so close your
cursors explicitly.
5. Start endless loops
Endless loops can cause endless problems including freezing your
system. Each time you create a loop, think about how the code will exit from
the loop.
The best way to avoid endless loops is to use CURSOR FOR loops or
FOR loops whenever possible. If you do not need to interrupt processing, always
use a FOR loop. This is much safer approach.
6. Reinvent the wheel
You should not try to create code structures that have already
been developed for you by Oracle. Before you start coding, it is a good idea to
review an Oracle manual with the list of built-in functions. This tip is
especially true when working with strings.
There is one more reason to use built-in functions. Oracle has tuned them to improve performance speed. If you need to parse very large strings or even CLOBs, built-in functions can significantly improve performance.
7. Convert datatypes implicitly
Although Oracle sometimes can implicitly convert one datatype to another, this does not mean that you should trust implicit conversions of datatypes, especially dates. In fact, this is not a good idea at all. Another common problem with implicit conversion occurs when working with numeric values that are not exactly numeric. Not everything that looks like a numeric value is a numeric value. Oracle cannot differentiate these cases. You must define the appropriate datatypes.
8. Cut and paste code indiscriminately
Sooner or later, all developers are tempted to copy and paste an
existing piece of code, modify it a bit, and be done with it. But a quick
shortcut during development can cost more time and effort than you might think
down the road.
Copying and pasting code does have some advantages:
·
You are not touching the existing code, just
adding code.
·
The code has already been checked and therefore
does not contain syntax errors.
·
You do not need to retest the code that is
dependent on the original code.
The drawbacks of cutting and pasting are:
·
The same modification has to be replicated
everywhere.
·
The code becomes less readable and more
spaghetti-like.
Ironically, the advantages are relevant only for developers, and
the disadvantages are relevant for those who maintain the system. Although time
spent by developers to create the code can be very expensive, the cost of
ongoing errors when maintaining the code is hundreds of times higher.
Although there is technically nothing wrong with cutting and pasting code, a few development hours saved can mean hours of downtime for an entire organization, so cut and paste at your own risk.
9. Ignore code readability
The next person who looks at your code should not have to guess about your naming conventions or program structure. Ongoing maintenance can consume large portions of the total cost of building an information system. Your goal as a developer should be to think about the long-term maintenance of the system when you write code.
10. Assume code does not need comments
There is no such thing as self-documenting code. The mistake of
thinking that working code is perfectly self-documenting has caused thousands
of lost hours in organizations all over the world. Even with the best naming
and coding conventions, you must still explicitly note many details. And you do
that by adding comments.
In the many systems that require complex code, the trick to
adding useful comments is to make sure that you (or someone else) will be able
to understand the code a few months (or even years) later. Writing code that
enables a system to be efficiently maintained is a critical part of building
successful information systems.
All comments should include the following elements:
·
A header that includes the following:
·
Basic information (ownership and functionality)
·
Functional comments that explain the implemented
solution and possible issues with the code
·
A change log to keep track of all changes to the
routine
·
Inline comments, which separate different parts
of the code and explain specific code lines
You shouldn’t over comment your code. A comment on every line is not necessary. Use your judgment and plan an external code review to determine how much commenting your routines require.
Getting Help and Keeping up to Date
SQL and PL/SQL are constantly evolving. With every release of
Oracle, new features are added and older features get better. The best
practices of this year will be outdated coding next year. Features that have
been added in version 9i and 10g of Oracle are used only by a minority
of developers. The best ways to keep up to date are
Buy books
Fortunately, plenty of good PL/SQL books are available on the
market. Three of the most important are:
·
Oracle
PL/SQL Programming, Steven Feuerstein & Bill Prybyl, 2005, O’Reilly
·
Oracle
PL/SQL for DBAs, Arup Nanda & Steven Feuerstein, 2005, O’Reilly
· Oracle Database 10g PL/SQL Programming, Scott Urman et.al, 2004, McGraw-Hill
·
PL/SQL for
Dummies, Rosenblum & Dorsey, 2006, John Wiley & Sons
After you have been coding for a while, you will easily be able to read a PL/SQL complete reference book cover to cover. No matter how much coding you have done, you will be amazed at how many things you did not know.
Go to conferences
One of the best-kept secrets in the industry is that you can see
the same content at almost any of the large Oracle conferences. The same
speakers tend to go to most of the national and regional conferences, and many
of them frequent local Oracle user group meetings as well. The difference is
that you will see more vendors at a large conference, and there will be more
presentations from Oracle employees. Although large conferences offer a larger
variety of topics and presentation levels, you will also pay a lot more to
attend a large conference.
For developers, the two best conferences are the Oracle
Development Tools User Group (ODTUG, www.odtug.com) and the Independent Oracle
Users Group (IOUG, www.ioug.org) annual conferences. These are both technically
focused events. ODTUG is geared for developers. If you are also interested in
DBA topics, you should go to the IOUG conference. IOUG and ODTUG hold their
conferences in different cities each year. Oracle OpenWorld in
Regional conferences can provide almost as much technical content as the national conferences, and you might not have to travel as far or pay as much. The Rocky Mountain Oracle User Group (RMOUG), the New York Oracle Users Group (NYOUG), the Northern California Oracle User Group (NOCOUG), the Mid-Atlantic Oracle Users Group (MAOP-AOTC), and others all host annual conferences that have multiple tracks and provide excellent content.
Join your local Oracle user group
Join your local Oracle user group and get to know people. It is
very helpful to know someone you can call when you have a question. You should
also become an ODTUG and/or IOUG member. You will receive discounts for the
conferences, access to conference papers and presentations online, and
well-written journals with technical articles about a variety of Oracle-related
topics.
Many large companies have their own internal user groups where
you can exchange tips that you have discovered. Smaller companies might host
brown bag lunches where you can take turns presenting useful tips. Be sure to
take advantage of these resources, as well.
Use online resources
Surfing the Web is one of the best ways to find out about PL/SQL
features. Most conference papers will be posted on one or more Web sites. You
can also post questions to various Internet list-serves and get your questions
answered (usually within a day). Probably the best list for PL/SQL questions is
the ODTUG-SQLPLUS-L list. You can sign up for this free list (you do not even
have to be a member of ODTUG) at www.odtug.com.
About the Authors
Dr.
Michael Rosenblum is a
Development DBA at Dulcian, Inc. He is responsible for system tuning and
application architecture. He supports Dulcian developers by writing complex
PL/SQL routines and researching new features. Mr. Rosenblum is the co-author of
PL/SQL for Dummies (Wiley Press,
2006). Michael is a frequent presenter at various regional and national Oracle
user group conferences. In his native