• Aucun résultat trouvé

Sequence Cache

Dans le document Expert Oracle RAC 12cExpert Oracle RAC 12c (Page 170-173)

nam='enq: RO - fast object reuse' ela= 976 name|mode=1380909062 2=65598 0=2 obj#=22 ...

nam='enq: RO - fast object reuse' ela= 1022 name|mode=1380909062 2=65598 0=1 obj#=22 nam='enq: RO - fast object reuse' ela= 478 name|mode=1380909057 2=65598 0=2 obj#=22 ...

nam='local write wait' ela= 270 file#=11 block#=280 p3=0 obj#=89956 nam='local write wait' ela= 1315 file#=11 block#=281 p3=0 obj#=89956 nam='local write wait' ela= 1702 file#=11 block#=282 p3=0 obj#=89956 nam='DFS lock handle' ela= 651 type|mode=1128857605 id1=13 id2=5 obj#=89956 nam='DFS lock handle' ela= 563 type|mode=1128857605 id1=13 id2=1 obj#=89956 nam='DFS lock handle' ela= 1492 type|mode=1128857605 id1=13 id2=2 obj#=89956

For further discussion about the DFS lock handle mechanism, see Chapter 11.

In most cases, developers use TRUNCATE or DROP commands to store the data temporarily while processing the data. Global temporary tables (GTTs) are the preferred method instead of DDL commands. Rows in GTTs are session specific and not visible to any other session. By default, rows in a GTT are thrown away after a commit. You can also choose to create a GTT with on commit preserve rows to preserve rows in the GTT across commits.

As GTT is session specific, it does not suffer from the ill effects of DDL commands. The DELETE command on a GTT does not trigger any checkpoint, and there is no need to invalidate parse locks, either. So, code developed using GTTs will scale better in both a single-instance and a RAC database compared to DDL statements.

I am not advocating that you should never use TRUNCATE or DDL statements in your code. On the contrary, be aware of the ill effects of DDL statements in a RAC database and use the method that best suits your requirements.

For example, if you must delete all rows from a big table (100K+ rows) infrequently in your code (or ad hoc), then you should use TRUNCATE commands instead of DELETE statements.

A common reason developers shy away from using GTT is that the optimizer can choose an inefficient execution plan for SQL statements accessing GTT. It is common for an application to gather schema-level statistics, thereby collecting statistics on GTT as well. The problem is that the statistics collection process has not populated any rows in those GTTs, and therefore zero rows statistics are populated for the GTT. The optimizer uses special considerations for zero rows statistics leading to inefficient execution plans.

One option to resolve the GTT statistics issue is to remove statistics on GTT and lock the statistics. Dynamic sampling will be triggered if there are no statistics on the table. Another option is to collect statistics after populating a representative number of rows in the GTT, and then lock the table statistics. However, this method assumes that all sessions have a uniform number of rows, which may not be entirely accurate. Release 12c introduces a new feature, session-level private statistics for a GTT, to resolve the statistics issue. You can choose to collect either session-level private statistics and/or shared statistics on GTT. If private statistics are available, the optimizer uses private statistics to choose an optimal execution plan. If not, the optimizer uses shared statistics.

Sequence Cache

Sequences provide unique values, not necessarily strict sequential values. Due to a misconception among developers and designers, however, applications often are designed assuming that sequences will provide strict sequential values.

At the first access to a sequence, sequence values are cached in an instance SGA, up to 20 values by default.

Subsequent access to that sequence will retrieve values from the cache until the cache is depleted. After the

exhaustion of cached values, the next access to the sequence will cache 20 more values in the instance SGA. The data dictionary table seq$ keeps permanent record of the highest cached value for every sequence in the database. The replenishing of the sequence cache will update the seq$ table, marking a new highest cached value for that sequence.

In a single-instance database, updates to a dictionary table require a lock on a row cache.

The problem with the caching sequence value is that in case of instance failure, cached values are permanently lost. For example, consider a sequence with a next value of 1,014 and the maximum cached value of 1,021 recorded in a seq$ table. In an instance crash, values from 1,014 to 1,021 will be permanently lost. If the application code assumes that sequence values will be in a strict sequential order, the loss of cached values can lead to unnecessary application data issues. Also, note that losing sequence values does not imply a data loss scenario, only that cached sequence values are permanently lost. Application designers alter attributes of sequences to ORDER, NOCACHE to impose strict sequential order. The ORDER and NOCACHE attributes have adverse effects if the sequences are accessed very frequently.

Every access to the sequence forces an update to the seq$ table. As updates to the seq$ table are performed under the protection of a row cache lock, if many sessions are trying to access sequence concurrently, then the row cache lock event can be seen as a major wait event.

Note

■ updates to the seq$ table are not the only cause of row cache lock event waits. Further review of details is warranted to identify the root cause. Chapter 11 discusses row cache locks further.

The following few lines from a SQL trace shows that the seq$ table is updated for each access to the sequence if the attributes of the sequence are set to ORDER, NOCACHE. The wait for row cache lock event is also shown in the following.

update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6,cache=:7,highwater=:8, audit$=:9,flags=:10,partcount=:11 where obj#=:1

nam='row cache lock' ela= 101 cache id=13 mode=0 request=5 obj#=89956 tim=1364157893629929

In the preceding wait line, cache_id is set to 13. Querying v$rowcache view, you can identify the type of rowcache entry. In this example, the update to the seq$ table is the reason to lock a row cache.

select type, parameter from v$rowcache where cache#=13;

TYPE PARAMETER

--- ---PARENT dc_sequences

The lines from a tkprof output of a SQL trace file (see Listing 6-1) show the impact of uncached sequences in a RAC database. About 255 seconds are spent on row cache lock waits in a total run time of 282 seconds. Note that there are no waits for the DFS lock handle event since the sequence attribute is set to NOCACHE. This difference will be relevant when I discuss cached sequences later in this section.

Listing 6-1. Performance of Uncached Sequence INSERT INTO RS.T_GEN_SEQ_02

VALUES

( RS.T_GEN_SEQ_02_SEQ.NEXTVAL, LPAD ('Gen',25,'DEADBEEF')

call count cpu elapsed disk query current rows --- --- --- ---Parse 1 0.00 0.00 0 0 0 0 Execute 5001 7.71 282.75 3 333 20670 5001 Fetch 0 0.00 0.00 0 0 0 0 --- --- --- ---total 5002 7.71 282.75 3 333 20670 5001

Event waited on Times Max. Wait Total Waited ---- Waited --- row cache lock 4586 0.76 255.01 Disk file operations I/O 7 0.00 0.00 db file sequential read 3 0.01 0.03 gc current block busy 1064 0.46 7.08 gc current block 2-way 2660 0.05 3.36

In a RAC database, sequence values can be cached in all instances. This sequence caching leads to retrieved sequence values not correlating with a time component. Consider the following scenario:

1. Session 1 connects to PROD1 instance and accesses a sequence emp_id_seq, retrieving a value of 1,022. Values in the range of 1,022 to 1,041 will be cached in PROD1 SGA for that sequence, assuming a default cache of 20.

2. Another session connecting to PROD2 will retrieve a value of 1,042 from that sequence.

Values in the range of 1,042 to 1,061 will be cached in the PROD2 instance SGA.

3. If session 1 connected to the PROD1 instance accesses the sequence again, a value of 1,023 will be returned.

So, the retrieved sequence values sorted by time will be 1,022, 1042, and 1,023, clearly not correlating with a time component.

In a RAC database, if the attributes of a frequently accessed sequence are set to ORDER, NOCACHE, performance problems will be magnified. As uncached sequences trigger an update to a seq$ table for every access, row cache locks are acquired aggressively. In a RAC database, row cache locks are globalized as GES layer locks, so additional GES locks must be acquired before updating dictionary tables. Essentially, a magnification effect comes into play, and a huge amount of waiting for GES locks and row cache lock wait events will be the result.

If you must retrieve sequence values in a strict sequential order, one option is to use ORDER, CACHE attributes of sequences. In RAC, a GES resource is used to maintain the current maximum cached value of a sequence, reducing updates to a dictionary table. Using the attributes ORDER and CACHE is a much better option if you must retrieve values in a strict sequential order. Still, if the resource master instance of the sequence crashes, then there is a possibility of losing cached sequence values. Note that an excessive amount of access to sequences with ORDER and CACHE attributes results in longer waits for the DFS lock handle event.

The test case in Listing 6-1 was repeated with sequence attributes set to ORDER, CACHE 20. The lines from the tkprof output file in Figure 6-2 show that the insert statement completed in about 12 seconds compared to 282 seconds in the case of uncached sequences test case in Listing 6-2.

Listing 6-2. Sequence with ORDER and CACHE INSERT INTO RS.T_GEN_SEQ_02

VALUES

( RS.T_GEN_SEQ_02_SEQ.NEXTVAL, LPAD ('Gen',25,'DEADBEEF')

call count cpu elapsed disk query current rowsf --- --- --- ---Parse 1 0.00 0.01 0 0 0 0 Execute 5001 0.94 12.60 0 910 16440 5001 Fetch 0 0.00 0.00 0 0 0 0 --- --- --- ---total 5002 0.94 12.62 0 910 16440 5001

Event waited on Times Max. Wait Total Waited ---- Waited --- DFS lock handle 359 0.05 0.64 enq: HW - contention 6 0.03 0.09 buffer busy waits 130 0.06 0.50

Our recommendations for a sequence in a RAC database are as follows:

1. If sequences are heavily accessed, then use a bigger cache value (1,000+). A bigger cache improves performance because access to a cached value is an order of magnitude faster than access to an uncached sequence value. The only drawback is that an instance crash can lose all cached sequence values.

2. If the sequences are accessed infrequently, use the default cache value of 20.

3. If you must retrieve values sequentially for infrequently accessed sequences, alter the sequence attributes to ORDER, CACHE value to avoid ill effects of uncached sequences in a RAC database. Also, alter the cache value of the sequence to 20. This option has less impact than sequences with nocache attributes because sequence values are stored in a GES resource.

4. If you cannot afford to lose any sequence value, then you should consider only ORDER, NOCACHE attributes. You should know that if you alter index attributes to ORDER, NOCACHE for frequently accessed sequences, it could lead to a hung cluster.

Dans le document Expert Oracle RAC 12cExpert Oracle RAC 12c (Page 170-173)