Skip to Main Content
  • Questions
  • "Local Write Wait" wait event and truncate

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, A reader.

Asked: January 05, 2010 - 2:35 am UTC

Last updated: January 06, 2010 - 7:56 am UTC

Version: 10.2.0.4

Viewed 10K+ times! This question is

You Asked

Hi Tom,

Thanks in advance for your assistance with this one.

RDBMS: 10.2.0.4
OS: HP-UX PA-Risc

Users are complaining that a specific job is "sometimes" slow, normally this job would run in 10 minutes but sometimes it finishes in over an hour.

Tracing the job shows the following when the job takes more than 1 hour:

truncate table ARC4


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.02          0          0          1           0
Execute      1      0.83    3663.42        687       2277       2602           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.86    3663.45        687       2277       2603           0

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 21     (recursive depth: 1)

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  db file sequential read                       689        0.03          1.97
  reliable message                                9        0.00          0.00
  enq: RO - fast object reuse                    44        2.94        106.30
  local write wait                             3868        0.99       3553.96
  free buffer waits                               8        0.03          0.06
  latch: cache buffers lru chain                  3        0.00          0.00
  log file switch (private strand flush incomplete)
                                                  4        0.10          0.27
  latch: cache buffers chains                     1        0.00          0.00
  latch: messages                                 1        0.00          0.00
  latch: shared pool                              1        0.00          0.00
  latch: library cache                            1        0.00          0.00
********************************************************************************



As opposed to the following when the job takes 15 minutes:

truncate table ARC4


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.03       0.03          0          2          5           0
Execute      1      0.27      70.01        666       2746       2610           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.30      70.05        666       2748       2615           0

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 21     (recursive depth: 1)

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  db file sequential read                       666        0.02          1.32
  reliable message                                9        0.02          0.02
  enq: RO - fast object reuse                    12        2.94         12.28
  local write wait                              359        0.98         56.00
  latch: cache buffers chains                     1        0.00          0.00
********************************************************************************



As you can see here, the main wait event to tackle is "local write wait".
My understanding is that for Oracle to perform the truncate, it needs to scan the whole buffer cache checking for any buffers that belong to that object, and dump these dirty buffers on disk, then clean those buffers. Our DB_CACHE_SIZE is 1GB.

My questions are:

1. Apart from using Global Temporary Tables which is not an option because of business need, is there anything else you could think of with respect to this?

Would it be better if we use delete (no logging) from the table rather than truncate?

I am trying to find other alternatives than using truncate really.

The table is on a locally managed tablespace uniform allocation and manual segment space management. The block size for this tablespace is 4k


2. Might be a different question but it's actually related to the same job, developers are using the following logic in the job:

Select count(*) into VAR1 from Table1;

If VAR1 > 10000 then
...

End if


I know that you are totally against using count(*), but in this specific situation where they need to know if the table has a fixed number of rows to process a request, what other alternative do you recommend?

I was thinking of adding a column with a sequence but there could always be gaps in there.


Thanks Tom.

and Tom said...

1) ... Would it be better if we use delete (no logging) from the table rather than truncate? ...

sometimes yes, sometimes no, maybe.

If the buffer cache is rather "clean", truncate will likely best delete. If the buffer cache is rather "dirty", delete might best truncate.

truncate will also reset the high water mark, delete will not. scans of this segment could be negatively impacted by that.

if you make dbwr more aggressive (configuring the database to minimize the time to perform instance recovery) there will be less blocks in the cache to flush (but beware it could make other aspects of the system perform differently - by keeping the cache "clean").

why are you using differing block sizes? I ask because you say "The block size for this tablespace is 4k " - that indicates other tablespaces have other blocksizes. That 4k block means the table uses 2-3 times the number of blocks an 8k one would - it might be more efficient to put it into the default blocksize and let it just mingle with everything else (probably reduce the number of dirty blocks in the cache by doing so).


If you do not want to truncate in real time - you could always use partitioning and just add/drop partitions over time (design change, application would probably want to participate in that)



2) at the very very very least:

select count(*) from t where rownum <= 10001;


Rating

  (3 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Truncate is slow

A reader, January 05, 2010 - 9:36 pm UTC


We had the same issue on quite a few databases. There is also a patch available on Metalink for the same and you can also set fast_object_reuse (something similar to false).

Better get in touch with Oracle Support before doing anything.

In our case, besides the patch and the parameter, we had aysnc mode but SRDF replication was one of the major causes.

In the end we moved to premium disks and things have fallen into place now. Make sure that your disks are supported by Oracle on the OS in which the database resides.

Cheers

A comment

A reader, January 05, 2010 - 10:26 pm UTC

Hi Tom,

I am not sure I got your point when you say:

"If the buffer cache is rather "clean", truncate will likely best delete."

1. What do you mean by truncate will likely best delete? do you mean that it would be better if we use truncate if the buffer cache does not have many buffers belonging to that table? If yes, then how can anyone control that in the job code? The whole problem is that the job takes a considerable amount of time when the buffer cache has lots of buffers for this table.
Are you recommending that the logic of job code change to something like:

- Check if the buffer cache has many buffers belonging to that object.

- If yes, go for a delete.

- If no, go for a truncate.

But how much is "many buffers" anyways?


2. When you say:

"If the buffer cache is rather "dirty", delete might best truncate"

Why is it a "might"? what other factors when using a delete could affect performance? I was thinking of using delete no logging here.

3. Would it be any better for performance of truncate if I place this table in the recycle pool?

4. I am not using different block size, that's the default block size for all tablespaces.

5. Thanks for the tip on rownum, I was thinking of usnig rownum too. And now you confirmed that it could be an option.


Thanks again Tom.
Tom Kyte
January 06, 2010 - 7:56 am UTC

1) if the cache is clean, truncate will have very little work to do before it truncates, it will "best" or "beat" delete probably in that case.

... then how can anyone control that in
the job code?...

they don't, the DBA would set up the database using settings such as:

http://www.oracle.com/technology/deploy/availability/htdocs/fs_chkpt.html

that would keep the cache clean, limiting the amount of work the truncate would have to do (at the expense of OTHER operations of course, no free lunch here)

... re you recommending that the logic of job code change to something like:
...

Absolutely NOT. I'm saying there are tradeoffs here, sometimes truncate will be faster than delete, sometimes the opposite is true. I just tried to list some of the considerations you have to take into account when deciding between them.


2) "delete might best truncate"

say there are 100 indexes on the table, delete is going to do a TON of work maintaining them, truncate - not so much.


" I was thinking of using delete no logging here."

don't, for the simple reason that "it does not exist". You cannot delete without logging, it is not possible.


3) I would recommend just the default pool, the recycle pool (and keep pool and default pool) manage blocks pretty much the same, they just have different names to by convention.

I would recommen ONE cache and ONE cache only - unless and until you have a really good reason to do otherwise.




Unusual high LIOs for TABLE FULL SCAN

Prashant, June 15, 2012 - 3:44 am UTC

Hi Tom,

Database 11.2.0.2 RAC 2 node
I am running a query where I see a high interconnect traffic and the query is running since a long time and its all on CPU. I figured out the interconnect traffic is quite high because the query hasn't even completed 1% of its work.

Querying the gv$session_wait_history shows me a lot of local write waits although they are not contributing to the elapsed_time greatly.

ELAPSED_TIME CPU_TIME BUFFER_GETS DISK_READS DIRECT_WRITES IO_INTERCONNECT_MB PHY_RD_REQ PHY_RD_MB
10422335865 9771588493 1210577216 373 132066 12467 373 86


The query is doing a full scan on the table (all partitions)
The table stats are below. When I check in gv$session_longops I see the following

     
       
SOFAR TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS MESSAGE
2268 284828 Blocks 1293322 10381 Table Scan: B: 2389 out of 284828 Blocks done
  


The table stats below
      
BLOCKS NUM_ROWS AVG_ROW_LEN    
284828 27103648 297     


I know I am supplying very little information. I can provide more details if needed. Could you advise me where I need to look into? I have run this query before and it has completed in less than 1 hr. Simplicity purposes its an INSERT /*+ APPEND */ INTO TABLE A SELECT B.*, C.*, D.* FROM B,C,D WHERE <join conditions>. The first is full scanned i.e. B because there are no limiting conditions.

I see the explain plan and compare with gv$session_longops I see that its still at the first step scanning the first table (B)

Please advise. I suspect it was RAC related because of the high interconnect traffic but wasn't sure. Can you please advise? and suggest how to remedy this?

Thanks
Prashant

More to Explore

VLDB

If you are new to partitioning, check out Connor McDonald's introduction series here.

VLDB

Documentation set on VLDB and Partitioning.