Oracle Scratchpad

February 28, 2011

Prefixed

Filed under: Indexing,Partitioning — Jonathan Lewis @ 6:12 pm UTC Feb 28,2011

From time to time the question about whether local indexes on partitioned tables should be prefixed or non-prefixed appears on the Oracle forums and mailing lists.

It’s possible that I’m wrong – although no-one has come up with a counter-example to the statement I keep repeating – but the whole prefixed/non-prefixed thing for local indexes dates back to a limitation in the optimizer somewhere in the 8.0 time line where Oracle couldn’t do partition elimination on indexes properly but the overhead of the error it made could be dramatically reduced (in most cases) by sticking the partition key at the start of the index.

The guideline for local indexes are the same as they would be for a non-partitioned index on a non-partitioned heap table – the partitioning column(s) are just columns in the table that might be worth including in the index, and the order of the index columns is dictated by the important queries that have to access the table.

For further comments, there’s a note I wrote (which I’ve just been reminded of) on the OTN database forum that adds a little detail to this argument.

February 27, 2011

Internal Views

Filed under: CBO,Execution plans — Jonathan Lewis @ 6:10 pm UTC Feb 27,2011

When Oracle transforms a query it will sometimes report an internal view name in the execution plan – and I have seen people asking for help occasionally because they’ve tried to find the view name in dba_views and it hasn’t existed. So, just for reference, here’s a short list of the view names that might appear during query transformation but won’t exist in your system.

With each name I’ve put a brief comment of why they might appear:
(more…)

February 25, 2011

AWR Snapshots

Filed under: Statspack,Troubleshooting — Jonathan Lewis @ 6:32 pm UTC Feb 25,2011

A couple of days ago I mentioned as a passing comment that you could take AWR snapshots at the start and end of the overnight batch processing so that if you ever had to answer the question: “Why did last night’s batch overrun by two hours?” you had the option of creating and comparing the AWR report from the latest batch run with the report from a previous batch run (perhaps the corresponding night the previous week) and check for any significant differences. Moreover, Oracle supplies you with the code to compare and report such differences from 10.2 (at least) using the script $ORACLE_HOME/rdbms/admin/awrddrpt.sql

The thing I didn’t mention at the time was how to take a snapshot on demand. It’s very easy if you have the appropriate execute privilege on package dbms_workload_repository.

execute dbms_workload_repository.create_snapshot('TYPICAL');

The single input parameter can be ‘TYPICAL’ (the default) or ‘ALL’.

I keep this one liner in a little script called awr_launch.sql – because I can never remember the exact name of the package without looking it up. (And sometimes I run it with sql_trace enabled so that I can see how much work goes into a snapshot as we change versions, features, configuration, workload and platforms.)

February 23, 2011

AWR Reports

Filed under: AWR,Oracle,Statspack,Troubleshooting — Jonathan Lewis @ 6:51 pm UTC Feb 23,2011

A little thought for those who use OEM to generate AWR reports – if you generate the standard HTML form and then try posting it into (say) the OTN database forum when you want some help interpreting it, it won’t look very readable (even if you do remember to put the right tags before and after to reproduce it in fixed font).
(more…)

February 22, 2011

Smiley

Filed under: humour — Jonathan Lewis @ 1:09 pm UTC Feb 22,2011

I’ve just had an email ending with the first “smiley” that made me smile. How often have you felt that you’re flogging a dead horse ?

For a derivation of the expression see Wikipedia.

February 21, 2011

Constraints

Filed under: Infrastructure,NULL,Oracle,Troubleshooting — Jonathan Lewis @ 7:15 pm UTC Feb 21,2011

There’s an important detail about constraints – check constraints in particular – that’s easy to forget, and likely to lead you into errors. Here’s a little cut-n-paste demo from an SQL*Plus session:

SQL> select count(*) from t1;

  COUNT(*)
----------
         4

1 row selected.

SQL>
SQL> alter table t1 add constraint t1_ck_v1 check (v1 in ('a','b','c'));

Table altered.

SQL>
SQL> select count(*) from t1 where v1 in ('a','b','c');

  COUNT(*)
----------
         3

1 row selected.

We count the number of rows in a table – and it’s four.
We add a constraint to restrict the values for a certain column – and every column survives the check.
We use the corresponding predicate to count the number of rows that match the check constraint – and we’ve lost a row !

Why ?

A predicate returns a row if it evaluates to TRUE.
A constraint allows a row if it does not evaluate to FALSE - which means it is allowed to evaluate to TRUE or to NULL.

I have one row in the table where v1 is null, and for that row the check constraint evaluates to NULL, which is not FALSE. So the row passes the check constraint, but doesn’t get returned by the predicate. I think it’s worth mentioning this difference because from time to time I see production systems that “lose” data because of this oversight.

To make the constraint consistent with the predicate I would probably add a NOT NULL declaration to the column or rewrite the constraint as (v1 is not null and v1 in (‘a’,'b’,'c’)).

February 17, 2011

Philosophy – 14

Filed under: Philosophy — Jonathan Lewis @ 6:48 pm UTC Feb 17,2011

Paraphrasing Yogi Berra:

    “It ain’t committed until it’s committed.”

If you’re wondering why it’s worth remembering this odd comment – it addresses the (commonly asked) question:

    “does the redo log contain uncommitted data as well as committed data?”

The answer is: yes.

When a session is creating redo change vectors it doesn’t know whether it is going to commit or rollback. But a session has to be able to store an arbitrarily large list of change vectors somewhere, and that list has to appear in the redo log (ideally “instantly”) if the session commits – so Oracle avoids delays on commit by putting the change vectors into the redo log as they are created***.

If you view the question from the opposite extreme, the recovery mechanism has to be able to deal with uncommitted data anyway because there are, after all, several scenarios where data that definitely was committed cannot be recovered; for example, recovery until end of log file 9998 because log file 9999 was destroyed and simply doesn’t exist – how can the code handle transactions that were not committed until part way through file 9999 if it only knows how to handle committed transactions ?)

*** Not strictly true from 10g onwards where Oracle introduced a delaying effect aimed at reducing competition for the redo allocation and redo copy latches for “small” transactions.

[The Philosophy Series]

February 15, 2011

ORA-29913

Filed under: Infrastructure,Troubleshooting — Jonathan Lewis @ 1:19 pm UTC Feb 15,2011

External tables as a substitute of loading tables through SQL*Loader have become more popular over the last couple of years – which means questions about Oracle error ORA-29913 have also become more popular. So what do you do about something like this:


SQL> select * from extern;
select * from extern
*
ERROR at line 1:
ORA-29913: error in executing ODCIEXTTABLEOPEN callout
ORA-29400: data cartridge error
KUP-04063: unable to open log file EXTERN_17063.log
OS error No such file or directory
ORA-06512: at "SYS.ORACLE_LOADER", line 19


(more…)

February 14, 2011

Burleson buys BMC ?

Filed under: humour — Jonathan Lewis @ 8:40 am UTC Feb 14,2011

There have been rumours running through the Oracle community over the last couple of days following publication of a note containing a clue that Burleson Consulting may have acquired the rights to BMC’s performance monitoring tool “Patrol” – and may even have bought out BMC itself. These rumours started shortly after the disappearance of a blog item by Charles Hooper discussing an SQL statement executed by the product formerly (perhaps still) known as BMC Patrol.

When questioned about the disappearance of the blog item Mr. Hooper explained that it had been taken down by his service provider in accordance with a DMCA takedown notice issued by Burleson Consulting and signed by Don Burleson who had quoted the SQL statement in question and stated that: “Under penalty of perjury, I swear that … I am the copyright owner of this material”.

Disclaimer:

The purchase of BMC Patrol by Burleson Consulting has not yet been officially announced by either party but the copyright claim contained in the DMCA notice would appear to indicate that Burleson Consulting has acquired exclusive copyright by purchasing (at a minimum) the rights to the product.

In other news

Latest gossip suggests that database giant Oracle Corporation has not completely discounted their option to sue Burleson Consulting regarding the latter’s frequent publication of the SQL statement: "select sysdate from dual;" despite having  prior publication dates for  the phrase as a whole and  the words “sysdate” and “dual” independently.

Any such gossip is, as yet, completely unsubstantiated but attorneys representing the descendants of Rene Descartes are said to be keeping their fingers crossed that Oracle Corporation will make something of this issue.

It is possible, however, that these rumours were never intended as serious comment and are the result of the inevitable mockery that ought to follow any ridiculous abuse of the DMCA mechanism.

Update 28th Feb:

The original article is back – with a footnote about the false DMCA claim.

I can’t help noticing that the article was unavailable for 17 days in total, though – which is longer than the eleven days it took for my articles to reaappear. There is an important performance guideline here – when Mr. Burleson is behaving badly, publish the fact and drop a note to his wife.

February 10, 2011

CBOddity

Filed under: CBO,Oracle,Troubleshooting — Jonathan Lewis @ 6:43 pm UTC Feb 10,2011

Warning – make sure you read to the end of this post.

Someone sent me an email this morning asking how Oracle calculates the index cardinality of an index range scan. Now, as I’ve often said, I don’t do private email about Oracle – unless it just happens to catch my attention and looks like something that is sufficiently generic to be worth publishing.

Today’s emailer was a lucky winner – he’d sent me a very short email that took about 30 seconds to read, contained a significant error, and (at first sight) probably had the right information in it for me to work with. Here’s the problem, as a cut-n-paste from an SQL*Plus session:

SQL> explain plan for select * from admlxa.QRT_BENCH where QRT_BENCH_DATE < :a3; 
Explained. 

Elapsed: 00:00:00.01 

SQL> select * from table(dbms_xplan.display); 

PLAN_TABLE_OUTPUT 
-----------------
Plan hash value: 2896103184 

----------------------------------------------------------------------------------------------- 
| Id  | Operation                   | Name            | Rows  | Bytes | Cost (%CPU)| Time     | 
----------------------------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT            |                 |   424K|    81M|  3170   (4)| 00:00:05 | 
|   1 |  TABLE ACCESS BY INDEX ROWID| QRT_BENCH       |   424K|    81M|  3170   (4)| 00:00:05 | 
|*  2 |   INDEX RANGE SCAN          | IDX_QRT_BENCH_1 | 78876 |       |   303   (5)| 00:00:01 | 
----------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 
   2 - access("QRT_BENCH_DATE"<:A3) 

Look closely at the “Rows” column – there’s clearly a logic error appearing here. If you select 78,876 rowids from an index you can’t possibly acquire 424,000 rows from the table – so where have those two numbers come from ?

The supporting information looked like this:

num_rows for QRT_BENCH table = 8480798 
num_distinct for QRT_BENCH_DATE column = 458 

num_rows for IDX_QRT_BENCH_1 = 8763975 
distinct_keys for IDX_QRT_BENCH_1 = 537 

Of course, I really needed to know whether this was a single-column or multi-column index if I wanted to model the problem correctly and do further checks on when the error appeared, but this was good enough to get started. We note, first, that the 424K for the table cardinality is just the standard “5% due to range predicate with unknown value”: round(0.05 * 8480798) = 424040.

    Step 1: since I don’t know where the number 78876 comes from, let’s try to work backwards – use it in a bit if arithmetic and see what drops out. Let’s try dividing it into the table cardinality: 424040 / 78876 = 5.3760

    Step 2: Does 5.376 look familiar — it may be a coincidence, but isn’t that really close to 1% of the number of distinct keys in the index ?

At this point I don’t have any time to investigate in detail, but a scratch hypothesis is that Oracle is calculating something like: 5 * (number of rows in table / (number of distinct keys in index)); and maybe that magic five appears through a piece of code that takes 5%, but for some reason then divides by the 1% associated with the selectivity normally associated with function(col).

If I had the time (and the data set) I’d start playing with dbms_stats.set_index_stats() et.al. to see the effect of changing num_distinct and num_rows to see if my initial guess was somewhere in the right ballpark. As it is I’ve just emailed this note back to the source.

Erratum:

Before I published this note I got a reply from the original correspondent, with the following comment:

Sure enough – five years ago I had published some details about exactly this “feature” – and that 537 vs. 5.376 really was just a coincidence.

I decided to publish the note anyway for three reasons –

    one: to make sure you realise that I do make mistakes
    two: to show you that simple games with numbers may give you a working hypothesis
    three: to remind you that once you’ve got a working hypothesis it’s often easy to think of ways to demonstrate that your hypothesis is wrong. (A couple of hacks of the statistics would have shown me a constant 0.009 appearing, rather than anything like 5% divided by 1%.)

LinkedIn

Filed under: Advertisements — Jonathan Lewis @ 2:03 pm UTC Feb 10,2011

I’ve been ignoring the “social network” phenomenon for a long time but I’ve finally given in and, as some people have already discovered, signed up to LinkedIn. I don’t know whether this is a good, bad, or pointless thing to do, but I thought I’d give it a go for a while and see what happens.

At present, though, I’m only linking to people who fall into one of several restrictive categories: I know them “outside” the internet, or have worked for them, or collaborated with them, or had a length technical exchange with them either by email or in person at a technical conference.

So if you send me a “Join my network” and I don’t do anything about it, please don’t be offended – it just means you don’t belong to a fairly restricted group. (On the other hand, since I’ve averaged about 3 days per site at 40 client sites per year for the last 10 years, it’s possible that you’ve been let down by my appalling memory for names.)

February 9, 2011

Philosophy – 13

Filed under: Philosophy — Jonathan Lewis @ 6:32 pm UTC Feb 9,2011

If you see a comment like “X is a bad idea” this does not mean “some mechanism that is vaguely ‘not X’ is a good idea”.

If, for example, I say:

    “Histograms will not work well on character strings that are more than 32 bytes long and generally similar in the first 32 bytes”

that is absolutely not the same as saying

    “It’s a good idea to create histograms on character strings that are less than 32 bytes long.”

If this were a purely mathematical world we could invoke symbolic logic and point out:

(A => B) <=> (¬B => ¬A)

which means my statement is equivalent to:

    if you have a histogram that is working well then the data is not character strings of more than 32 bytes with generally similar values in the first 32 bytes”

Of course, being Oracle, you may find that someone, somewhere, has exactly such a histogram that appears to work brilliantly for them – but that will be because the optimizer has messed up the arithmetic so much that they are getting a great execution plan for completely the wrong reason … so they need to watch out for the next upgrade or patch release in case the optimizer gets enhanced.

[The Philsophy Series]

February 6, 2011

GTTs

Filed under: Infrastructure — Jonathan Lewis @ 6:51 pm UTC Feb 6,2011

That’s Global Temporary Table, of course.

A request appeared on the OTN database forum recently asking if it was possible to allocate a global temporary table to a particular temporary tablespace because the programmer didn’t want typical users to be at risk of running out of temporary space when a particular global temporary table suddenly got loaded with millions of rows.

If you’re running 11.1 or above, go straight to the footnote, otherwise read on.
(more…)

February 4, 2011

Dynamic Views

Filed under: humour — Jonathan Lewis @ 7:42 pm UTC Feb 4,2011

People forget from time to time that when you query the dynamic performance views (v$ views) you shouldn’t expect to get a read-consistent result set – and this can lead to some very strange results, especially when you start writing joins between views (for example you may be able to find a session is both “not waiting” and “waiting” if you still join v$session and v$session_wait).

Here’s a visual analogy to help you remember what’s going on: “Australian Propellors ?”

And a graphic to help explain the phenomenon: “Rolling Shutter Effect.”

And here, for stunning effect only, is another clip that appeared in the “related topics”.

February 3, 2011

Upgrade issues

Filed under: CBO,Oracle,Partitioning,Troubleshooting — Jonathan Lewis @ 6:41 pm UTC Feb 3,2011

Here’s an example of how a bug-fix can create problems. It’s a code change in 11.2.x.x and (I believe) 10.2.0.5 relating to the costing of queries involving (but perhaps not restricted to) composite partitioned tables. I first saw this change in an email from Doug Burns, who sent me the 10053 traces from a very simple query that had started using the wrong index after an upgrade from 10.2.0.4 to 11.2.0.2.

As part of his testing he had set the optimizer_features_enable parameter back to 10.2.0.4 and found that not only did the choice of index change back to the expected index, but the costs of the two indexes changed dramatically. (The cost of using the “right” index changed from 15 to something in excess of 9,000 on the upgrade!)

(more…)

Next Page »

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 819 other followers