6.3 Use Comments Rationale: The best documentation for maintaining a program has been comments in the code.. Perhaps it is easier for procedural language programmers to add comments beca
Trang 1which is a little cleaner than:
WHERE (a IN (x, y) OR z IS NULL)
6.2.4.3 Use CASE Expressions, Not Complex Nested Predicates
An advanced trick in the WHERE clause is to use a CASE expression for
a complex predicate with material implications If you forgot your freshman logic, a material implication logical operator is written as an arrow with two tails, and it means “p implies q” or “if p is true then q is true” in English
WHERE CASE
WHEN <search condition #1>
THEN 1
WHEN <search condition #2>
THEN 1
.
ELSE 0 END = 1
The use of a function that returns one or zero when given a predicate
as its parameter is called a characteristic function in logic and set theory.
Review the rules for the CASE expression in section 6.2.2 first, so you understand it The order of execution of the WHEN clauses can be used
to optimize performance and avoid redundant tests You can also nest CASE expressions inside the WHEN and THEN clauses of a containing CASE expression and display the logic as an indented tree structure WHERE CASE
WHEN <search condition #1>
THEN CASE
WHEN <search condition #1.1>
THEN 1
WHEN <search condition #1.2>
THEN 1 ELSE 0 END
WHEN <search condition #2>
THEN 1
.
ELSE 0 END = 1
The goal of this technique is to replace pages of long lists of simple theta expressions inside horrible levels of parentheses and to provide
Trang 2118 CHAPTER 6: CODING CHOICES
some short-circuit evaluation as a bonus When the nesting is too messy
to understand, stop and reconsider your logic Decision table tools, such
as Logic Gem, are an excellent way to do this
6.3 Use Comments
Rationale:
The best documentation for maintaining a program has been comments
in the code Perhaps it is easier for procedural language programmers to add comments because they are explaining in a narrative fashion what their program is doing Unfortunately, procedural language comments are often redundant if you can read the code How much help did you get from:
UPDATE Teams SET score = score + 1;—increment score
which gives you no information about what the variable score means and why it is incremented
In Standard SQL, a comment begins with two dashes ( ) and ends with a new line, because the first SQL engines were on IBM mainframes and used punchcards This format is a poor choice with modern computers that can store free-form text Word wrap in program text can split a comment and give you errors Because SQL supports the unary minus operator, this is ambiguous in some rare situations and makes the compiler work extra hard Later standards added the C style /* and */ pairs, and many vendors have similar comment brackets They are a better choice
SQL programmers do not like to put comments in their code, not even redundant or useless ones My guess is that because SQL does a lot
of work in one statement and programmers have been taught to comment the code at the statement execution level rather than explain the purpose of the code, the higher level of abstraction confuses them They are not inclined to put comments at the clause level because the appearance of the code can be crowded
Get over it You need a high-level descriptive comment on a block of SQL, and then more detailed comments on a few important clauses Try
to keep the comments aimed at non-SQL programmers and in plain English For example, don’t say “relational division of motor pool vehicles by available drivers” on the assumption that the reader will
Trang 3know what a relational division is Try “list all drivers who can drive all the vehicles in the motor pool” instead The other trick is to reference the documentation for the schema and the applications This assumes that they are current and useful, however
If you have the time, another guru-level trick is to save the best of the various statements you tried that worked but did not perform as well as the final choice as comments In SQL, what was the best answer in one situation is often no longer the best answer Instead of making the next programmer start from scratch, share your notes
Exceptions:
In a well-designed schema with good data element names, much of the code is easy for an experienced SQL programmer to read You can skip comments on single statements if their intent is really obvious, but remember that one programmer’s obvious is another’s “what the heck?” when you code
Always start a stored procedure with a comment that gives at least the author, the date, and the update history This is simply basic software management After that, add a high-level description of the function of this module The procedure name will be in a “<verb><object>” format Each parameter should have a comment as needed
Comments on control statements, such as IF-THEN-ELSE, BEGIN-END, and WHILE-DO loops, will look much like comments in any procedural program Complicated SQL statements need a comment at the top and often comments at the clause level
This point is difficult to generalize, but things that act as a unit might need a comment For example, a derived table for which there is no good alias might need a comment to explain what it contains A series of predicates that define a complicated join might be prefaced with a comment to explain what they are doing at a higher level
Trang 4120 CHAPTER 6: CODING CHOICES
6.4 Avoid Optimizer Hints
Rationale:
Many products have proprietary syntax for sending parameters to the optimizer to change the execution plan for a statement Because each physical implementation is different, this syntax will not be portable, but there are other problems too
First, the optimizer is usually smarter than the programmer and finds
a good plan People cannot handle computations that involve tens of parameters very well Second, once a hint is put on a statement, it stays there permanently, long after the reason for the hint is gone A typical example of this would set up a query hint for a skewed statistical distribution and then, as the database grows, the distribution becomes more normal or skewed in the opposite direction The hint that used to
be so helpful is now a handicap
Exceptions:
If you do have a skewed statistical distribution or other weirdness in your data that is destroying performance, then use a hint Set up a review of all statements with hints to see if they actually need to be maintained Reviews should occur when a new release of database is installed (optimizer might be better) or the statistics of one or more of the tables change (data might be better), but if the performance is acceptable, then
do not use hints
6.5 Avoid Triggers in Favor of DRI Actions
Rationale:
Although there is an ANSI/ISO standard for triggers, their syntax and semantics are still highly proprietary Triggers are blocks of procedural code that are executed (fired) when a database event occurs to a table This code is usually in a proprietary 3GL language A database event is something that changes the data—an insert, update, or delete
The full ANSI version of triggers does not fire on an insertion, but some vendor products do The full ANSI version of triggers have more than one trigger on a table and can fire them in a sequence either before
or after the database event Most vendor products do not have that much control over the triggers On the other hand, the syntax and semantics for DRI actions are well defined and standardized
A newbie posted a topic under the title “Need Help with a Calculation Trigger” on the forums in the SQL Server Central Web site in November
2004 This person was having trouble setting up a trigger to check the
Trang 5units of a “number field [sic]”; the real problem was that the poster did not know that a column is not a field
For some reason, the column was declared as FLOAT and was called length The trouble is that some people were entering a length in meters, centimeters, and millimeters The poster was trying to code a trigger that will fire on UPDATE or INSERT to check the value of length If it is greater than 20, chances are the number is in millimeters and should be divided by 10 If the number is less than 0, then the number is probably
in meters and should be multiplied by 100
CREATE TRIGGER SetCentimeters
AFTER INSERT ON Samples
UPDATE Samples
SET length
= (CASE
WHEN length > 10.00
THEN Length / 10.00
WHEN length < 0.00
THEN Length * 100.00
ELSE Length END)
WHERE length NOT BETWEEN 0.00 AND 10.00;
However, this is the wrong answer It is in procedural code The right answer is in the DDL, with something like this:
length DECIMAL(2,1) NOT NULL
CONSTRAINT length_in_centimeters_only
CHECK (length BETWEEN 0.01 AND 9.99)
Triggers tend to fix errors on the fly; the goal is not to permit them in the first place
Exceptions:
Some things should be done with triggers because you cannot do them with DRI In particular, the INSTEAD OF trigger has to be used for updatable views This trigger is attached to a VIEW, and instead of taking actions on the VIEW, it changes the base tables from which the VIEW is built, so that the user sees those changes reflected in the VIEW
Heuristics tend to favor stored procedures over triggers A trigger
fires every time its database event occurs, which puts it out of your control and adds that overhead to each database event A stored