Who makes the decisions? I thought it was Optimizer


Direct path read decision

Some decisions are actually not taken by the optimizer.

We started to experience a performance problem with an sql query which we can not change the software code and tried to find a solution in solely database layer. 

Sql query was a sophisticated one, but problem can be summarized with the short one below.

Here is the plan output.

Products table was a large table exceeding 50 Gb size and query's execution time was 180 - 200 seconds. 

Query was searching in PRODUCTS table for the HTML_CONTENT with not null records, but for all rows,  HTML_CONTENT column values was null and as this column is not indexed, query was performing a full table scan. And also, html_content column data type was CLOB. For that reason I could not create a functional index and i could not rewrite the query as the source code is not available.

I tried to execute the query with  /*+ PARALLEL(2) */ hint, execution completed within milliseconds.  In Parallel Execution with Oracle Database White Paper document it is stated that Scaling linearly is the ultimate goal of parallel processing. But for this query it was executing 200 times faster than the original one. I checked the execution plan, but access paths were same. 

I tried to find a clue to explain why execution times differ that much. I used 10046 event tracing to get a clear picture and used TKPROF tool. Here is the elapsed time outputs of tkprof analysis respectively (original and hinted one).

Cell multiblock physical read and cell single block physical read wait events are  the direct reads of data from multiple/single blocks in a cell to a  memory location. Cell multiblock physical read is generally caused due to full table scan queries whose processing is not offloaded to the storage layer. If we were not using Exadata and using traditional (not Oracle engineered) servers, we would be observing db file scattered read and db file sequential read events. 

We observed cell smart table scans. Cell smart table scan is the capability of an Oracle Database to offload SQL processing to the Exadata Storage Servers. Exadata Smart Scan works in collaboration with Exadata Storage Indexes, which reduces the amount of IO required to satisfy the smart scan process. I am not writing this post for marketing purposes. 

What is interesting here is, despite the same access paths are choosen by the optimizer, WITH THE /*+ PARALLEL */ hint in use, the decision of reading the blocks from disk to memory changed with the decision of reading the blocks from disk directly. A direct read is a physical I/O from a data file that bypasses the buffer cache and reads the data block directly into process-private memory.  This decision is not taken by the OPTIMIZER, who is in charge was the database engine itself. 

This behavior is controlled by the hidden "_serial_direct_read" parameter. And how this decision(buffered read or direct path read) is taken is explained in detail by Tanel Poder blog post, Optimizer statistics-driven direct path read decision for full table scans .

In short, these are the factors involved in the decisions:

    * Are block counts taken from optimizer stats or segment header?

    * Do the segment header and/or optimizer stats block counts change?

    * Does the buffer cache size change (thus the _small_table_threshold too)?

    * Does the amount of cached blocks of a segment change?

    * Parallel vs Serial execution

    * Are buffered parallel full scans allowed (the in-memory PX feature of 11.2)

    * Did a new child cursor get created or the old one reused

     * Etc.

According to the How To Force Direct Path Read for SQL Statements (Doc ID 2426051.1) document, there are two methods to force direct path read for sql statements. First one use running sql statement with parallel hint (That is what i did), and second one is "Setting the statistics of the tables involved in the SQL such that the no.of blocks of tables > _small_table_threshold to enable the serial direct path read".

Another mystery is solved and now we can patch our sql statement with a sql patch.  From now on, it will be working super fast.

Hope it helps.


Comments

Popular posts from this blog

Using table stats hint to force a direct path read but with a rownum predicate surprise

Oracle Grid Release Update by using Ansible Playbooks

Oracle Database Release Update by Using Ansible Playbooks