Pregunta

I have 5 development schemas. And each of them have partitioned tables. We also have scripts to dynamically create partition tables (Monthly/Yearly). We have to go to DBA everytime for gathering the details over the parition tables. Our real problem is we do have a parition table with 9 partitions. Every day after a delta load operation (Updates/Deletes using a PL/SQL) also some APPEND load using SQL*Loader. This operation happens when database has the peak load. We do have some performace issues over this table.(SELECT queries)

When reported to DBA, they would say the table statistics are stale and after they do "gathering stats", magically the query works faster. I searched about this and identified some information about dynamic performance views.

So, now , I have the following Questions.

1) Can the developer generate a the list of all partitionon tables, partition name, no of records available without going to DBA?
2) Shall we identify the last analysed date of every parition
3) Also the status of the parition(index) if it usable or unusable.

¿Fue útil?

Solución 4

I used to query all_ tables mentioned below.

The statistics and histogram details you mention will be updated in a frequency automatically by Oracle. But when the database is busy with many loads, I have seen these operations needs to be triggered manually. We faced similar situation, so we used to force the Analyze operation after our load for critical tables. You need to have privilege for the id you use to load the table.

ANALYZE TABLE table_name PARTITION (partition_name) COMPUTE STATISTICS;

EDIT: ANALYZE no longer gather CBO stats as mentioned here

So, DBMS_STATS package has to be used.

DBMS_STATS.GATHER_TABLE_STATS (
   ownname          VARCHAR2, 
   tabname          VARCHAR2, 
   partname         VARCHAR2 DEFAULT NULL,
   estimate_percent NUMBER   DEFAULT to_estimate_percent_type 
                                                (get_param('ESTIMATE_PERCENT')), 
   block_sample     BOOLEAN  DEFAULT FALSE,
   method_opt       VARCHAR2 DEFAULT get_param('METHOD_OPT'),
   degree           NUMBER   DEFAULT to_degree_type(get_param('DEGREE')),
   granularity      VARCHAR2 DEFAULT GET_PARAM('GRANULARITY'), 
   cascade          BOOLEAN  DEFAULT to_cascade_type(get_param('CASCADE')),
   stattab          VARCHAR2 DEFAULT NULL, 
   statid           VARCHAR2 DEFAULT NULL,
   statown          VARCHAR2 DEFAULT NULL,
   no_invalidate    BOOLEAN  DEFAULT  to_no_invalidate_type (
                                     get_param('NO_INVALIDATE')),
   force            BOOLEAN DEFAULT FALSE);

And until the analyze is complete, the view tables below may not produce the accurate results (Especially the last_analyzed and num_rows columns)

Note: Try replace all_ as dba_ in table names, if you have access to it, you can try them.

You can also try to get SELECT_CATALOG_ROLE for your development id you use, so that you can SELECT the data dictionary views, and this reduces the dependency over DBA over such queries.(Still DBA are the right persons for few issues!!)

Query to identify the partition table, partition name, number of rows and last Analysed date!

select 
      all_part.owner as schema_name,
      all_part.table_name,
      NVL(all_tab.partition_name,'N/A'),
      all_tab.num_rows,
      all_tab.last_analyzed
from
      all_part_tables all_part,
      all_tab_partitions all_tab
where all_part.table_name = all_tab.table_name and
      all_tab.partition_name = all_tab.partition_name and
      all_part.owner=all_tab.table_owner and
      all_part.owner in ('SCHEMA1','SCHEMA2','SCHEMA3')
order by all_part.table_name,all_tab.partition_name;

The Below Query returns the index/table name that are UNUSABLE

SELECT INDEX_NAME,
  TABLE_NAME,
  STATUS
FROM ALL_INDEXES
WHERE status NOT IN ('VALID','N/A');

The Below Query returns the index/table (PARTITION) name that are UNUSABLE

SELECT INDEX_NAME,
  PARTITION_NAME,
  STATUS ,
  GLOBAL_STATS
FROM ALL_IND_PARTITIONS
WHERE status != 'USABLE';

Otros consejos

Normally there is no need to identify objects that need statistics gathered. Oracle automatically gathers statistics for stale objects, unless the task has been manually disabled. This is usually good enough for OLTP systems. Use this query to find the status of the task:

select status
from dba_autotask_client
where client_name = 'auto optimizer stats collection';

STATUS
------
ENABLED

For data warehouse systems there is also not much need to query the data dictionary for stale stats. In a data warehouse statistics need to be considered after almost every operation. Developers need to get in the habit of always thinking about statistics after a truncate, insert, swap, etc. Eventually they will "just know" when to gather statistics.

But if you still want to see how Oracle determines if statistics are stale, look at DBA_TAB_STATISTICS and DBA_TAB_MODIFICATIONS.

Here is an example of an initial load with statistics gathering. The table and partitions are not stale.

create table test1(a number, b number) partition by list(a)
(
    partition p1 values (1),
    partition p2 values (2)
);
insert into test1 select 1, level from dual connect by level <= 50000;
begin
    dbms_stats.gather_table_stats(user, 'test1');
    dbms_stats.flush_database_monitoring_info;
end;
/

select table_name, partition_name, num_rows, last_analyzed, stale_stats
from user_tab_statistics
where table_name = 'TEST1'
order by 1, 2;

TABLE_NAME  PARTITION_NAME  NUM_ROWS  LAST_ANALYZED  STALE_STATS
----------  --------------  --------  -------------  -----------
TEST1       P1                 50000     2014-01-22           NO
TEST1       P2                     0     2014-01-22           NO
TEST1                          50000     2014-01-22           NO

Now add a large number of rows and the statistics are stale.

begin
    insert into test1 select 2, level from dual connect by level <= 25000;
    commit;
    dbms_stats.flush_database_monitoring_info;
end;
/

select table_name, partition_name, num_rows, last_analyzed, stale_stats
from user_tab_statistics
where table_name = 'TEST1'
order by 1, 2;

TABLE_NAME  PARTITION_NAME  NUM_ROWS  LAST_ANALYZED  STALE_STATS
----------  --------------  --------  -------------  -----------
TEST1       P1                 50000     2014-01-22           NO
TEST1       P2                     0     2014-01-22          YES
TEST1                          50000     2014-01-22          YES

USER_TAB_MODIFICATIONS gives more specific information on table staleness.

--Stale statistics.
select user_tables.table_name, user_tab_modifications.partition_name
    ,inserts+updates+deletes modified_rows, num_rows, last_analyzed
    ,case when num_rows = 0 then null
        else (inserts+updates+deletes) / num_rows * 100 end percent_modified
from user_tab_modifications
join user_tables
    on user_tab_modifications.table_name = user_tables.table_name
where user_tables.table_name = 'TEST1';

TABLE_NAME  PARTITION_NAME  MODIFIED_ROWS  NUM_ROWS  LAST_ANALYZED  PERCENT_MODIFIED
----------  --------------  -------------  --------  -------------  ----------------
TEST1       P2                      25000     50000     2014-01-22                50
TEST1                               25000     50000     2014-01-22                50
  1. Yes, you can generate a list of partitioned tables, and a lot of related data which you would like to see, by using ALL_PART_TABLES or USER_PART_TABLES (provided you have access). ALL_TAB_PARTITIONS can be used to get number of rows per partition, alongwith other details.

Check other views Oracle has for gathering details about partitioned tables.

  1. I would suggest that you should analyze the tables, and possibly rebuild the indexes, every day after your data load. If your data load is affecting a lot of records in the table, and is going to affect the existing indexes, it's a good idea to proactively update the statistics for the table and index.

  2. You can use on the system views to get this information (Check http://docs.oracle.com/cd/E18283_01/server.112/e16541/part_admin005.htm)

I had a some what similar problem and I solved it by gathering stats on stale partitions only using 11g new INCREMENTAL option.

It's the reverse approach to your problem but it might worth investigating (specifically - how oracle determines what's a "stale" partition is).

dbms_stats.set_table_prefs('DWH','FACT_TABLE','INCREMENTAL','TRUE')

I always prefer the pro active approach - meaning, gather stats on stale partition at the last step of my etl, rather then giving the developer stronger privs.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top