Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 12 ■ DATATYPES 525 You can see the obvious difference. Using TO_CHAR consumed an order of magnitude more CPU than using TRUNC. That is because TO_CHAR must convert the date to a string, using a much larger code path, taking all of the NLS we have in place to do so. Then we had to compare a string to a string. The TRUNC, on the other hand, just had to set the last 5 bytes to 1. Then it compared 7 binary bytes to 7 binary bytes, and it was done. So, you should never use TO_CHAR on a DATE column simply to truncate it. Additionally, avoid applying a function at all to the DATE column when possible. Taking the preceding example one step further, we can see that the goal was to retrieve all data in the year 2005. Well, what if CREATED had an index on it and a very small fraction of the values in that table were in the year 2005? We would like to be able to use that index by avoiding a function on the database and column using a simple predicate: select count(*) from t where created >= to_date('01-jan-2005','dd-mon-yyyy') and created < to_date('01-jan-2006','dd-mon-yyyy'); We would achieve two things: • An index on CREATED could be considered. • The TRUNC function would not have to be invoked at all, and that overhead would go away entirely. This technique of using a range comparison instead of TRUNC or TO_CHAR applies equally to the TIMESTAMP type discussed shortly. When you can avoid applying a function to a database column in a query, you should. In general, avoiding the function will be more performant and allow the optimizer to choose from a wider variety of access paths. Adding Time to or Subtracting Time from a DATE A question I am frequently asked is, “How do I add time to or subtract time from a DATE type?” For example, how do you add one day to a DATE, or eight hours, or one year, or one month, and so on? There are three techniques you’ll commonly use: • Simply add a NUMBER to the DATE. Adding 1 to a DATE is a method to add 1 day. Adding 1/24 to a DATE therefore adds 1 hour, and so on. • You may use the INTERVAL type, as described shortly, to add units of time. INTERVAL types support two levels of granularity, years and months, or days/hours/minutes/seconds. That is, you may have an interval of so many years and months or an interval of so many days, hours, minutes, and seconds. • Add months using the built-in ADD_MONTHS function. Since adding a month is generally not as simple as adding 28 to 31 days, a special-purpose function was implemented to facilitate this. Table 12-3 demonstrates the techniques you would use to add N units of time to a date (or subtract N units of time from a date, of course).

526 CHAPTER 12 ■ DATATYPES Table 12-3. Adding Time to a Date Unit of Time Operation Description N seconds DATE + n/24/60/60 There are 86,400 seconds in a day. DATE + n/86400 Since adding 1 adds one day, adding DATE + NUMTODSINTERVAL(n,'second') 1/86400 adds one second to a date. I prefer the n/24/60/60 technique over the 1/86400 technique. They are equivalent. An even more readable method is to use the NUMTODSINTERVAL (number to day/second interval) to add N seconds. N minutes DATE + n/24/60 There are 1,440 minutes in a date. DATE + n/1440 Adding 1/1440 therefore adds one DATE + NUMTODSINTERVAL(n,'minute') minute to a DATE. An even more readable method is to use the NUMTODSINTERVAL function. N hours DATE + n/24 There are 24 hours in a day. Adding DATE + NUMTODSINTERVAL(n,'hour') 1/24 therefore adds one hour to a DATE. An even more readable method is to use the NUMTODSINTERVAL function. N days DATE + n Simply add N to the DATE to add or subtract N days. N weeks DATE + 7*n A week is seven days, so just multiply 7 by the number of weeks to add or subtract. N months ADD_MONTHS(DATE,n) You may use the ADD_MONTHS built-in DATE + NUMTOYMINTERVAL(n,'month') function or add an interval of N months to the DATE. Please see the important caveat noted shortly regarding using month intervals with DATEs. N years ADD_MONTHS(DATE,12*n) You may use the ADD_MONTHS built-in DATE + NUMTOYMINTERVAL(n,'year') function with 12*n to add or subtract N years. Similar goals may be achieved with a year interval, but please see the important caveat noted shortly regarding using year intervals with dates. In general, when using the Oracle DATE type I recommend the following: • Use the NUMTODSINTERVAL built-in function to add hours, minutes, and seconds. • Add a simple number to add days. • Use the ADD_MONTHS built-in function to add months and years. I do not recommend using the NUMTOYMINTERVAL function. The reason has to do with how the functions behave at the months’ end. The ADD_MONTHS function treats the end of month days specially. It will in effect “round” the dates for us; for example, if we add one month to a month that has 31 days and the next

CHAPTER 12 ■ DATATYPES 525<br />

You can see the obvious difference. Using TO_CHAR consumed an order of magnitude more<br />

CPU than using TRUNC. That is because TO_CHAR must convert the date to a string, using a much<br />

larger code path, taking all of the NLS we have in place to do so. Then we had to compare a<br />

string to a string. The TRUNC, on the other h<strong>and</strong>, just had to set the last 5 bytes to 1. Then it<br />

compared 7 binary bytes to 7 binary bytes, <strong>and</strong> it was done. So, you should never use TO_CHAR<br />

on a DATE column simply to truncate it.<br />

Additionally, avoid applying a function at all to the DATE column when possible. Taking the<br />

preceding example one step further, we can see that the goal was to retrieve all data in the year<br />

2005. Well, what if CREATED had an index on it <strong>and</strong> a very small fraction of the values in that<br />

table were in the year 2005? We would like to be able to use that index by avoiding a function<br />

on the database <strong>and</strong> column using a simple predicate:<br />

select count(*) from t<br />

where created >= to_date('01-jan-2005','dd-mon-yyyy')<br />

<strong>and</strong> created < to_date('01-jan-2006','dd-mon-yyyy');<br />

We would achieve two things:<br />

• An index on CREATED could be considered.<br />

• The TRUNC function would not have to be invoked at all, <strong>and</strong> that overhead would go<br />

away entirely.<br />

This technique of using a range comparison instead of TRUNC or TO_CHAR applies equally to<br />

the TIMESTAMP type discussed shortly. When you can avoid applying a function to a database<br />

column in a query, you should. In general, avoiding the function will be more performant <strong>and</strong><br />

allow the optimizer to choose from a wider variety of access paths.<br />

Adding Time to or Subtracting Time from a DATE<br />

A question I am frequently asked is, “How do I add time to or subtract time from a DATE type?”<br />

For example, how do you add one day to a DATE, or eight hours, or one year, or one month, <strong>and</strong><br />

so on? There are three techniques you’ll commonly use:<br />

• Simply add a NUMBER to the DATE. Adding 1 to a DATE is a method to add 1 day. Adding<br />

1/24 to a DATE therefore adds 1 hour, <strong>and</strong> so on.<br />

• You may use the INTERVAL type, as described shortly, to add units of time. INTERVAL<br />

types support two levels of granularity, years <strong>and</strong> months, or days/hours/minutes/seconds.<br />

That is, you may have an interval of so many years <strong>and</strong> months or an interval of<br />

so many days, hours, minutes, <strong>and</strong> seconds.<br />

• Add months using the built-in ADD_MONTHS function. Since adding a month is generally<br />

not as simple as adding 28 to 31 days, a special-purpose function was implemented to<br />

facilitate this.<br />

Table 12-3 demonstrates the techniques you would use to add N units of time to a date (or<br />

subtract N units of time from a date, of course).

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!