Google it ....

Monday, April 24, 2023

Tuning is null query in oracle

When there is some simple query which is using just is null criteria on big table, oracle cost based optimizer making table access full, so query running slow, here is demonstration how to tune similar queries:
create table my_test_table as select * from dba_objects;

insert into my_test_table  select * from dba_objects;
commit;

UPDATE my_test_table set object_name=null where rownum<=100;
commit;

create index my_test_table_i1 on my_test_table(object_name);

begin
  dbms_stats.gather_table_stats(ownname => 'QOBESA',
                                tabname => 'MY_TEST_TABLE',
                                cascade => true);
end;


select * from my_test_table where object_name is null;


------------------------------------------------------------------------------
| Id  | Operation           | Name          | Rows | Bytes | Cost | Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |               |  100 | 12500 |  108 | 00:00:01 |
| * 1 |   TABLE ACCESS FULL | MY_TEST_TABLE |  100 | 12500 |  108 | 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter("OBJECT_NAME" IS NULL)
So we have table with more than 100 000 rows and in 100 rows column object_name is null, which is indexed column, but optimizer doesn't using it and making full table scan, if your table is huge and it contains many gigabytes of data it will be big problem. Many believes that there is no way to tune this type of statement, because oracle does not store NULL values in indexes, but here is little trick to use index on not null columns
create index my_test_table_i2 on my_test_table(object_name, -1);


begin
  dbms_stats.gather_table_stats(ownname => 'QOBESA',
                                tabname => 'MY_TEST_TABLE',
                                cascade => true);
end;


select * from my_test_table where object_name is null;


---------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name             | Rows | Bytes | Cost | Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |                  |  100 | 12900 |   78 | 00:00:01 |
|   1 |   TABLE ACCESS BY INDEX ROWID BATCHED | MY_TEST_TABLE    |  100 | 12900 |   78 | 00:00:01 |
| * 2 |    INDEX RANGE SCAN                   | MY_TEST_TABLE_I2 |  100 |       |    3 | 00:00:01 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 2 - access("OBJECT_NAME" IS NULL)
So solution is to add some constant to the end of the index to be sure null values are stored.

Friday, March 17, 2023

ORA-01873: the leading precision of the interval is too small

 Hello,

Today we faced below error when quering dba_jobs:

SQL> select * from dba_jobs where job=4474623;
select * from dba_jobs where job=4474623

ORA-01873: the leading precision of the interval is too small

SQL> 
Oracle database is on 19c version so this dbms_job automatically converted in scheduler so this way it is correctly working:

select * from dba_scheduler_jobs where job_name='DBMS_JOB$_4474623';
so problem is dba_jobs view, we can see how it looks like :

create or replace view dba_jobs as
select
    m.dbms_job_number JOB, j.creator LOG_USER, u.name PRIV_USER,
    u.name SCHEMA_USER,
    CAST(j.last_start_date AS DATE) LAST_DATE,
    substr(to_char(j.last_start_date,'HH24:MI:SS'),1,8) LAST_SEC,
    CAST(
      DECODE(BITAND(j.job_status,2), 2, j.last_start_date, NULL)
    AS DATE) THIS_DATE,
    DECODE(BITAND(j.job_status,2), 2,
           substr(to_char(j.last_start_date,'HH24:MI:SS'),1,8), NULL) THIS_SEC,
    CAST(j.next_run_date AS DATE) NEXT_DATE,
    substr(to_char(j.next_run_date,'HH24:MI:SS'),1,8) NEXT_SEC,
    (CASE WHEN j.last_end_date>j.last_start_date THEN
     extract(day from (j.last_end_date-j.last_start_date)*86400) ELSE 0 END)
     TOTAL_TIME, -- Scheduler does not track total time
    DECODE(BITAND(j.job_status,1),0,'Y','N') BROKEN,
    DECODE(BITAND(j.flags,1024+4096+134217728),
                  0, j.schedule_expr, NULL) INTERVAL,
    j.failure_count FAILURES, j.program_action WHAT,
    j.nls_env NLS_ENV, j.env MISC_ENV, NVL(j.instance_id, 0) INSTANCE
  from
    sys.scheduler$_dbmsjob_map m
    left outer join sys.obj$ o on (o.name = m.job_name)
    left outer join sys.user$ u on (u.name = m.job_owner)
    left outer join sys.scheduler$_job j on (j.obj# = o.obj#)
  where
    o.owner# = u.user#
;
comment on table DBA_JOBS is 'All jobs in the database';
comment on column DBA_JOBS.JOB is 'Identifier of job.  Neither import/export nor repeated executions change it.';
comment on column DBA_JOBS.LOG_USER is 'USER who was logged in when the job was submitted';
comment on column DBA_JOBS.PRIV_USER is 'USER whose default privileges apply to this job';
comment on column DBA_JOBS.SCHEMA_USER is 'select * from bar  means  select * from schema_user.bar ';
comment on column DBA_JOBS.LAST_DATE is 'Date that this job last successfully executed';
comment on column DBA_JOBS.LAST_SEC is 'Same as LAST_DATE.  This is when the last successful execution started.';
comment on column DBA_JOBS.THIS_DATE is 'Date that this job started executing (usually null if not executing)';
comment on column DBA_JOBS.THIS_SEC is 'Same as THIS_DATE.  This is when the last successful execution started.';
comment on column DBA_JOBS.NEXT_DATE is 'Date that this job will next be executed';
comment on column DBA_JOBS.NEXT_SEC is 'Same as NEXT_DATE.  The job becomes due for execution at this time.';
comment on column DBA_JOBS.TOTAL_TIME is 'Total wallclock time spent by the system on this job, in seconds';
comment on column DBA_JOBS.BROKEN is 'If Y, no attempt is being made to run this job.  See dbms_jobq.broken(job).';
comment on column DBA_JOBS.INTERVAL is 'A date function, evaluated at the start of execution, becomes next NEXT_DATE';
comment on column DBA_JOBS.FAILURES is 'How many times has this job started and failed since its last success?';
comment on column DBA_JOBS.WHAT is 'Body of the anonymous PL/SQL block that this job executes';
comment on column DBA_JOBS.NLS_ENV is 'alter session parameters describing the NLS environment of the job';
comment on column DBA_JOBS.MISC_ENV is 'a versioned raw maintained by the kernel, for other session parameters';
comment on column DBA_JOBS.INSTANCE is 'Instance number restricted to run the job';
So there is important comment on total time that -- Scheduler does not track total time.
Solution : 
we can change dba_jobs view with this query to solve this problem or you can query from dba_Scheduler_jobs, we are changing just total_time field calculation with this:


( CASE
              WHEN j.last_end_date > j.last_start_date THEN
                 --EXTRACT (
                 --DAY FROM (j.last_end_date - j.last_start_date) * 86400)
          (CAST(j.last_end_date AS DATE)-CAST(j.last_start_date AS DATE)) * 86400
              ELSE
                 0
           END )
     TOTAL_TIME, -- Scheduler does not track total time

So whole view will be like that :
create or replace view dba_jobs as
select
    m.dbms_job_number JOB, j.creator LOG_USER, u.name PRIV_USER,
    u.name SCHEMA_USER,
    CAST(j.last_start_date AS DATE) LAST_DATE,
    substr(to_char(j.last_start_date,'HH24:MI:SS'),1,8) LAST_SEC,
    CAST(
      DECODE(BITAND(j.job_status,2), 2, j.last_start_date, NULL)
    AS DATE) THIS_DATE,
    DECODE(BITAND(j.job_status,2), 2,
           substr(to_char(j.last_start_date,'HH24:MI:SS'),1,8), NULL) THIS_SEC,
    CAST(j.next_run_date AS DATE) NEXT_DATE,
    substr(to_char(j.next_run_date,'HH24:MI:SS'),1,8) NEXT_SEC,
    ( CASE
              WHEN j.last_end_date > j.last_start_date THEN
                 --EXTRACT (
                 --DAY FROM (j.last_end_date - j.last_start_date) * 86400)
          (CAST(j.last_end_date AS DATE)-CAST(j.last_start_date AS DATE)) * 86400
              ELSE
                 0
           END )
     TOTAL_TIME, -- Scheduler does not track total time
    DECODE(BITAND(j.job_status,1),0,'Y','N') BROKEN,
    DECODE(BITAND(j.flags,1024+4096+134217728),
                  0, j.schedule_expr, NULL) INTERVAL,
    j.failure_count FAILURES, j.program_action WHAT,
    j.nls_env NLS_ENV, j.env MISC_ENV, NVL(j.instance_id, 0) INSTANCE
  from
    sys.scheduler$_dbmsjob_map m
    left outer join sys.obj$ o on (o.name = m.job_name)
    left outer join sys.user$ u on (u.name = m.job_owner)
    left outer join sys.scheduler$_job j on (j.obj# = o.obj#)
  where
    o.owner# = u.user#
;
comment on table DBA_JOBS is 'All jobs in the database';
comment on column DBA_JOBS.JOB is 'Identifier of job.  Neither import/export nor repeated executions change it.';
comment on column DBA_JOBS.LOG_USER is 'USER who was logged in when the job was submitted';
comment on column DBA_JOBS.PRIV_USER is 'USER whose default privileges apply to this job';
comment on column DBA_JOBS.SCHEMA_USER is 'select * from bar  means  select * from schema_user.bar ';
comment on column DBA_JOBS.LAST_DATE is 'Date that this job last successfully executed';
comment on column DBA_JOBS.LAST_SEC is 'Same as LAST_DATE.  This is when the last successful execution started.';
comment on column DBA_JOBS.THIS_DATE is 'Date that this job started executing (usually null if not executing)';
comment on column DBA_JOBS.THIS_SEC is 'Same as THIS_DATE.  This is when the last successful execution started.';
comment on column DBA_JOBS.NEXT_DATE is 'Date that this job will next be executed';
comment on column DBA_JOBS.NEXT_SEC is 'Same as NEXT_DATE.  The job becomes due for execution at this time.';
comment on column DBA_JOBS.TOTAL_TIME is 'Total wallclock time spent by the system on this job, in seconds';
comment on column DBA_JOBS.BROKEN is 'If Y, no attempt is being made to run this job.  See dbms_jobq.broken(job).';
comment on column DBA_JOBS.INTERVAL is 'A date function, evaluated at the start of execution, becomes next NEXT_DATE';
comment on column DBA_JOBS.FAILURES is 'How many times has this job started and failed since its last success?';
comment on column DBA_JOBS.WHAT is 'Body of the anonymous PL/SQL block that this job executes';
comment on column DBA_JOBS.NLS_ENV is 'alter session parameters describing the NLS environment of the job';
comment on column DBA_JOBS.MISC_ENV is 'a versioned raw maintained by the kernel, for other session parameters';
comment on column DBA_JOBS.INSTANCE is 'Instance number restricted to run the job';


after change dba_jobs view we can query that job without any error:
SQL> select * from dba_jobs where job=4474623;

Saturday, February 25, 2023

Disable or enable auto task jobs in oracle database

Automatic database maintenance tasks is used by oracle for tunning SQL queries, gather stale or non existing statistics on objects and space advisory. 

These Automatic maintenance jobs is configured default in Oracle Database :

  • Automatic Optimizer Statistics Collection - Gathers stale or missing statistics
  • Automatic Segment Advisor – Identifies segments that reorganized to save space
  • Automatic SQL Tuning Advisor – Tune high load SQL
How to disable automatic jobs in oracle?

To disable all these jobs you can :
begin
DBMS_AUTO_TASK_ADMIN.disable;
end;
/
How to enable automatic jobs in oracle?
begin
DBMS_AUTO_TASK_ADMIN.enable;
end;
/
How to disable sql tuning advisor, auto space advisor and auto optimizer stats collection separately one by one:
SQL> SELECT client_name, status FROM dba_autotask_client;

CLIENT_NAME                           STATUS
-------------------------------       ---------
auto optimizer stats collection       ENABLED
auto space advisor                    ENABLED
sql tuning advisor                    ENABLED

SQL> EXEC DBMS_AUTO_TASK_ADMIN.DISABLE(client_name=>'sql tuning advisor', operation=>NULL, window_name=>NULL);

SQL> EXEC DBMS_AUTO_TASK_ADMIN.DISABLE(client_name=>'auto space advisor', operation=>NULL, window_name=>NULL);

SQL> EXEC DBMS_AUTO_TASK_ADMIN.DISABLE(client_name=>'auto optimizer stats collection', operation=>NULL, window_name=>NULL);

PL/SQL procedure successfully completed.

3. Check the status again for auto task jobs

SQL> SELECT client_name, status FROM dba_autotask_client;

 CLIENT_NAME                             STATUS
----------------------------------       ---------------
auto optimizer stats collection          DISABLED
auto space advisor                       DISABLED
sql tuning advisor                       DISABLED
How to enable sql tuning advisor, auto space advisor and auto optimizer stats collection separately one by one:
SQL> EXEC DBMS_AUTO_TASK_ADMIN.ENABLE(client_name=>'sql tuning advisor', operation=>NULL, window_name=>NULL);

SQL> EXEC DBMS_AUTO_TASK_ADMIN.ENABLE(client_name=>'auto space advisor', operation=>NULL, window_name=>NULL);

SQL> EXEC DBMS_AUTO_TASK_ADMIN.ENABLE(client_name=>'auto optimizer stats collection', operation=>NULL, window_name=>NULL);

PL/SQL procedure successfully completed.

Wednesday, August 31, 2022

ORA-01000: maximum open cursors exceeded oracle.sysman.emSDK.emd.comm.MetricGetException: ORA-01000: maximum open cursors exceeded

Sometimes we are not getting alerts from OEM(Oracle Enterprise Manager) and if we try to check some metric values it is throwing error:
ORA-01000: maximum open cursors exceeded oracle.sysman.emSDK.emd.comm.MetricGetException: ORA-01000: maximum open cursors exceeded 
I Found interesting Doc about this issue on metalink: 
ORA-01000: MAXIMUM OPEN CURSORS EXCEEDED (Doc ID 2751726.1).
It seems it is Bug 31542357 - Use of setTimeToLiveTimeout causes leak of cursors and ORA-01000 eventually 
Solution: 
For 13.4 Cloud Control the patch will be included in the 13.4 RU7 and newer patches. 
The work around from development is: On agent side add this property in emd.properties and restart the agent. The following property will kill the seesion on db and avoid the cursor leak.
SqlConnectionCache._TimeToLiveTimeout=0

Saturday, May 7, 2022

Oracle Database World 2022

If you missed biggest database event of the year 2022 here you can access 18 sessions and 3 hands on lab: Oracle Database World 2022