Beiträge getaggt mit 11g New Features

CELL_PARTITION_LARGE_EXTENTS now obsolete

During the Exadata course that I am just delivering in Munich, I noticed that the fairly new parameter CELL_PARTITION_LARGE_EXTENTS is already obsolete now:

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

SQL> alter system set cell_partition_large_extents=true;
alter system set cell_partition_large_extents=true
*
ERROR at line 1:
ORA-25138: CELL_PARTITION_LARGE_EXTENTS initialization parameter has been made
obsolete

This parameter was introduced in 11.2.0.1 especially for Exadata Database Machine because the Allocation Unit Size (AU_SIZE) for Diskgroups built upon Exadata Cells is recommended with 4 MB. Large Segments should therefore use a multiple of 4 MB already for their initial extents. Although the parameter was made obsolete, the effect that was achievable with it is still present:

SQL> create table t (n number) partition by range (n) (partition p1 values less than (2));

Table created.

SQL> insert into t values (1);

1 row created.

SQL> select bytes/1024/1024 as mb from user_extents where segment_name='T';

 MB
----------
 8

I inserted before checking USER_EXTENTS because of the 11g New Feature deferred segment creation:

SQL> drop table t purge;

Table dropped.

SQL> create table t (n number);

Table created.

SQL> select bytes/1024/1024 as mb from user_extents where segment_name='T';

no rows selected

SQL> insert into t values (1);

1 row created.

SQL> select bytes/1024/1024 as mb from user_extents where segment_name='T';

 MB
----------
 .0625

Notice that only partitioned tables are affected by the 8 MB initial extent behavior. The new hidden parameter _PARTITION_LARGE_EXTENTS (defaults to true!) is now responsible for that:

SQL> alter session set "_partition_large_extents"=false;

Session altered.

SQL> drop table t purge;

Table dropped.

SQL> create table t (n number) partition by range (n) (partition p1 values less than (2));

Table created.

SQL> insert into t values (1);

1 row created.

SQL> select bytes/1024/1024 as mb from user_extents where segment_name='T';

 MB
----------
 .0625

Notice that the setting of CELL_PARTITION_LARGE_EXTENTS with alter session is silently overridden by the underscore parameter:

SQL> drop table t purge;

Table dropped.

SQL> alter session set cell_partition_large_extents=true;

Session altered.

SQL> create table t (n number) partition by range (n) (partition p1 values less than (2));

Table created.

SQL> insert into t values (1);

1 row created.

SQL> select bytes/1024/1024 as mb from user_extents where segment_name='T';

 MB
----------
 .0625

The parameter setting of the underscore parameter was still false.

SQL> drop table t purge;

Table dropped.

SQL> alter session set "_partition_large_extents"=true;

Session altered.

SQL> alter session set cell_partition_large_extents=false;

Session altered.

SQL> create table t (n number) partition by range (n) (partition p1 values less than (2));

Table created.

SQL> insert into t values (1);

1 row created.

SQL> select bytes/1024/1024 as mb from user_extents where segment_name='T';

 MB
----------
 8

Conclusion: With 11.2.0.2, partitioned tables get initial extents of 8 MB in size, which is particular useful in Exadata Environments where the ASM AU_SIZE will be 4 MB. But also ordinary Databases are affected – which is probably a good thing if we assume that partitioned tables will be large in size anyway and will therefore benefit from a large initial extent size as well.

Addendum: During my present Exadata course (03-JUN-2012), I saw a similar parameter for partitioned indexes also: _INDEX_PARTITION_LARGE_EXTENTS defaults to FALSE, though. Brief test:

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

SQL> create table parti (n number) partition by range (n) (partition p1 values less than (2));

Table created.

SQL> insert into parti values (1);

1 row created.

SQL> commit;

Commit complete.

SQL> create index parti_idx on parti(n) local;

Index created.

SQL> select bytes from user_extents where segment_name='PARTI_IDX';

     BYTES
----------
     65536

SQL> drop index parti_idx;

Index dropped.

SQL> alter session set "_index_partition_large_extents"=true;

Session altered.

SQL> create index parti_idx on parti(n) local;

Index created.

SQL> select bytes from user_extents where segment_name='PARTI_IDX';

     BYTES
----------
   8388608

So this parameter gives us also 8M sized extents for partitioned indexes, but not by default.

, ,

5 Kommentare

Optimizer Stats: Treat some tables different than AutoTask does

This posting was inspired by an OTN thread. Since 10g, we have an Automatic Maintenance Task (AutoTask) that gathers Optimizer Statistics during the night. This task uses DBMS_STATS.GATHER_DATABASE_STATS with default values. For whatever reason, we may consider these defaults not appropriate for some tables. We have 2 options:

  1. Write our own procedure/job to gather statistics different (10g way)
  2. Change the Statistic Preferences for these tables (11g way)

We look at the 11g New Feature first, because it is the more efficient way to go:

SQL> create table adam.a as
 select
 rownum as id,
 rownum + 1 as flag,
 'Oracle Enterprise Edition' as product,
 mod(rownum,5) as channel_id,
 mod(rownum,1000) as cust_id ,
 5000 as amount_sold,
 trunc(sysdate - 10000 + mod(rownum,10000)) as order_date,
 trunc(sysdate - 9999 + mod(rownum,10000)) as ship_date
 from dual connect by level<=1e6;

Table created.


SQL> create table adam.b as select * from adam.a;

Table created.

SQL> select table_name,num_rows,sample_size,to_char(last_analyzed,'hh24:mi:ss') from user_tables;

TABLE_NAME                       NUM_ROWS SAMPLE_SIZE TO_CHAR(
------------------------------ ---------- ----------- --------
A
B
SQL> exec dbms_stats.gather_schema_stats('ADAM')

PL/SQL procedure successfully completed.

SQL> select table_name,num_rows,sample_size,to_char(last_analyzed,'hh24:mi:ss') from user_tables;

TABLE_NAME                       NUM_ROWS SAMPLE_SIZE TO_CHAR(
------------------------------ ---------- ----------- --------
A                                 1000000     1000000 10:03:11
B                                 1000000     1000000 10:03:12

You may notice that DBMS_STATS analyzed all the blocks/rows by default – that is because the tables are rather small in size. I want to change that for table b:

SQL> exec dbms_stats.set_table_prefs('ADAM','B','ESTIMATE_PERCENT','50')

PL/SQL procedure successfully completed.

Next, I will delete more than 10 Percent of both tables, so that DBMS_STATS will consider both as stale and collect new stats for them. Then I call again GATHER_SCHEMA_STATS as before, but b is treated different:

SQL> delete from a where rownum<200000;

199999 rows deleted.

SQL> delete from b where rownum<200000;

199999 rows deleted.

SQL> commit;

Commit complete.

SQL> exec dbms_stats.gather_schema_stats('ADAM')

PL/SQL procedure successfully completed.

SQL> select table_name,num_rows,sample_size,to_char(last_analyzed,'hh24:mi:ss') from user_tables;

TABLE_NAME                       NUM_ROWS SAMPLE_SIZE TO_CHAR(
------------------------------ ---------- ----------- --------
A                                  800001      800001 10:10:06
B                                  801196      400598 10:10:09

Notice the different sample size of b. Now to the old (10g) way to achieve the same. If we would just let the AutoTask collect all the stats (including our „different tables“) and after that collect stats again on those tables, we would do the doubled work for them. Therefore we lock the stats (10g New Feature). I drop & recreate the tables a & b the same as before. Then:

SQL> exec dbms_stats.lock_table_stats('ADAM','B')

PL/SQL procedure successfully completed.

SQL> exec dbms_stats.gather_schema_stats('ADAM')

PL/SQL procedure successfully completed.
SQL> create procedure mygather
as
begin
dbms_stats.unlock_table_stats('ADAM','B');
dbms_stats.gather_table_stats('ADAM','B',estimate_percent=>50);
dbms_stats.lock_table_stats('ADAM','B');
end;


Procedure created.

SQL> exec mygather

PL/SQL procedure successfully completed.

SQL> select table_name,num_rows,sample_size,to_char(last_analyzed,'hh24:mi:ss') from user_tables;

TABLE_NAME                       NUM_ROWS SAMPLE_SIZE TO_CHAR(
------------------------------ ---------- ----------- --------
A                                 1000000     1000000 10:18:27
B                                  999662      499831 10:18:54

Conclusion: If we are aware of the (New) Features of each Oracle Database version, we are able to do our work more efficiently. One aspect of this general rule is the dealing with Optimizer Statistics, that we can collect different from the AutoTasks default for some tables if we are inclined to do so.

,

8 Kommentare

Flashback Database puts Physical Standby into MOUNT from READ-ONLY OPEN

Another bit of discovery from my present Data Guard course in Munich: If you have a Physical Standby opened READ-ONLY, you can do Flashback Database in that state without first shutting down and going to status MOUNT.

I think that this is an 11g New Feature, but I didn’t check it with 10g yet. Let’s have a look first at the ordinary behavior:

SQL> select database_role,open_mode,flashback_on from v$database;

DATABASE_ROLE    OPEN_MODE            FLASHBACK_ON
---------------- -------------------- ------------------
PRIMARY          READ WRITE           YES

SQL> flashback database to timestamp systimestamp - interval '5' minute;
flashback database to timestamp systimestamp - interval '5' minute
*
ERROR at line 1:
ORA-38757: Database must be mounted and not open to FLASHBACK.

This is not a Standby Database and the error is completely expectable. Everybody knows that Flashback Database can only be done in status MOUNT, right? Well not always:

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

SQL> select database_role,open_mode,flashback_on from v$database;

DATABASE_ROLE    OPEN_MODE            FLASHBACK_ON
---------------- -------------------- ------------------
PHYSICAL STANDBY READ ONLY            YES

SQL> flashback database to timestamp systimestamp - interval '5' minute;

Flashback complete.

It did the Flashback Database! And very fast also. But silently, the instance is now placed in status MOUNT:

SQL> select database_role,open_mode,flashback_on from v$database;

DATABASE_ROLE    OPEN_MODE            FLASHBACK_ON
---------------- -------------------- ------------------
PHYSICAL STANDBY MOUNTED              YES

In fact, I did not discover this behavior myself, but an attendee did and later on asked me, why Real-Time Query is now no longer in place on the Standby – that is because it is now in status MOUNT. I would not even had try to do that Flashback Database, because I ‚knew‘ that it can’t work 🙂

Now did you know that?

By the way, since 11gR2, you can turn on Flashback Database for an ordinary Database with it in status OPEN, as I have already posted here.

, ,

4 Kommentare