This is another example of using ANALYTICAL function to optimize the SQL Access.
Consider the following SQL
-- Table Columns:
( COLA,
a.TXT_1 as FULL_TXT,
FROM MY_TABLE a
a.TXT_2 as FULL_TXT,
FROM MY_TABLE a
a.TXT_3 as FULL_TXT,
FROM MY_TABLE a ;
This is another example of using ANALYTICAL function to optimize the SQL Access.
Consider the following SQL
-- Table Columns:
It is common practice to use corelated subquery to get the max record for a given value.
Problem with Above query is Oracle needs to query the BIG_TABLE twice.
We can rewrite the query as follows using analytical function to avoid scanning table twice.
How does range condition effects the performance ?
---------------------------------------------------------------
One of the select query is taking more time and the application changed the following
id <=2 to id < 3
select * from table where id <=2 --- original query
select * from table where id < 3 ---- new query , taking longer
both queries are using the index range scan i.e. same execution plan
both queries are semantically same and provides the same results but for true oltp systems it makes different.
for new query we are seeing more buffer gets than the old query
i.e. for new query buffer gets reduced dramatically, so we opened the sr with oracle and they provided following possible reason
id <=2 will scan the less number of blocks than the id < 3
:-)
How to solve Cache buffers Chain Latch Contention :
-----------------------------------------------------------------
Since the Oracle SGA holds lots of information in various types of memory structures, it is not enough to have just one latch for each type of memory structure to be protected.
For example, if you have an 8 GB buffer cache for 8 KB blocks, then you have one million buffers in the buffer cache.
Reasonable concurrent access to all these million buffers can't be provided by a single latch (in this case a "cache buffers chains" latch).
Therefore, Oracle has split the memory structures that need protection into logical sub-pieces and each piece is protected by a separate sub-latch known as a child latch
For example, if you run a database with large buffer cache, you may have thousands of cache buffers chains child latches in use.
When accessing a data buffer block, Oracle will run a modulus function on the data block address (DBA) of the block
to determine which cache buffers chains latch to get to satisfy that access
Cache buffers chains (CBC) latch contention can occur due a number of reasons. One of the most common reasons is that you have an extremely hot block in the buffer cache
1) First, there are many CBC latches in an Oracle instance
SQL> select name, count(*) from v$latch_children where name like '%chains%' group by name;
NAME COUNT(*)
-------------------------------------------------- ----------
cache buffers chains 2048
enqueue hash chains 8
library cache hash chains 11
2) So, as a first step we should identify which CBC latches are experiencing the contention:
i.e. is the contention lightly spread across many CBC latch children or is there a single child latch experiencing much heavier contention compared to others?
V$LATCH_CHILDREN.WAIT_TIME --> find the latch children that has highest number of wait time
ex: in a sql trace we found following:
WAIT #1: nam='latch: cache buffers chains' ela= 204 address=15742234376 ...
WAIT #1: nam='latch: cache buffers chains' ela= 8 address=15742234376 ...
WAIT #1: nam='latch: cache buffers chains' ela= 2 address=15742234376 ...
WAIT #1: nam='latch: cache buffers chains' ela= 7 address=15742234376 ...
From address: (sql trace shows address and we need to change it to hexadecimal)
SQL> select name, gets, misses, sleeps from v$latch_children where addr = hextoraw(trim(to_char(15742234376, '0XXXXXXXXXXXXXXX')));
NAME GETS MISSES SLEEPS
------------------------- ---------- ---------- ----------
cache buffers chains 62178598 125541 805
from ASH:
SQL> SELECT *
FROM
( SELECT
event,
TRIM(TO_CHAR(p1, 'XXXXXXXXXXXXXXXX')) latch_addr,
TRIM(ROUND(RATIO_TO_REPORT(COUNT(*)) OVER () * 100, 1))||'%' PCT,
COUNT(*)
FROM
v$active_session_history
WHERE
event = 'latch: cache buffers chains'
AND session_state = 'WAITING'
GROUP BY
event,
p1
ORDER BY
COUNT(*) DESC
) WHERE ROWNUM <= 10;
EVENT LATCH_ADDR PCT COUNT(*)
----------------------------- ----------------- ------ ----------
latch: cache buffers chains 3AA4F6F08 4.1% 50
latch: cache buffers chains 3AA4D4908 3.7% 45
latch: cache buffers chains 3AA4E2558 3.4% 42
latch: cache buffers chains 3AA4F00E0 3.2% 39
latch: cache buffers chains 3AA519440 2.9% 36
latch: cache buffers chains 3AA527090 2.8% 34
latch: cache buffers chains 3AA4FDD30 2.8% 34
latch: cache buffers chains 3AA50B8B8 2.7% 33
latch: cache buffers chains 3AA4DB730 2.6% 32
latch: cache buffers chains 3AA534C18 2.6% 32
10 rows selected.
3) find the sql:
After getting the latch_children address we can find the session and corresponding sql.
SQL> desc v$latchholder;
Name Null? Type
----------------------------------------- -------- ------
PID NUMBER
SID NUMBER
LADDR RAW(8)
NAME VARCHAR2(64)
GETS NUMBER