Sunday, July 13, 2014

Pipelined Functions in Oracle

USE : 
--------------------------
Pipelined functions are useful if there is a need for a data source other than a table in a select statement.

What is pipelined function :
--------------------------
Pipelining negates the need to build huge collections by piping rows out of the function as they are created, 
saving memory and allowing subsequent processing to start before all the rows are generated.
Pipelined table functions include the PIPELINED clause and use the PIPE ROW call to push rows out of the function
as soon as they are created, rather than building up a table collection. Notice the empty RETURN call, since there 
is no collection to return from the function.
 
  if you mean "pipelined functions" it would be the fact that you are streaming data from a cursor to a procedure process (the pipelined function) and then another process retrieves this. and you can skip all of the heinous IO that a global temporary table would likely incur by just streaming the data. 
  and the stream is nice because the pipelined function is constantly returning data to the client as it produces it - nice "pipeline" gets going instead of a series of monolithic steps that require large amounts of resources. This constant return is vary from tool to tool.

Demo :


--------------------------------------------------------------
Normal method of doing passing data to application.
--------------------------------------------------------------

Table functions are used to return PL/SQL collections that mimic tables.They can be queried like a regular table by using the TABLE function in the FROM clause.Regular table functions require collections to be fully populated before they are returned.Since collections are held in memory, this can be a problem as large collections can waste a lot of memory and take a long time to return the first row. 
These potential bottlenecks make regular table functions unsuitable for large Extraction Transformation Load (ETL) operations.
Regular table functions require named row and table types to be created as database objects.

create table album_scalar_table  
(a_id VARCHAR2(10), 
flags VARCHAR2(1) 
) ;

 
CREATE OR REPLACE FUNCTION flags_etl_table 
RETURN varchar2   AS
v_a_id VARCHAR2(10);
v_a_flag VARCHAR2(10);
v_flg VARCHAR2(1);
BEGIN
LOOP
  FOR I IN 1..100000000000000000000000000000
  LOOP
  insert into album_scalar_table values  (I, I);
  END LOOP;
END LOOP;
RETURN 'A';
END;
/
declare
ret_val varchar(200);
begin
ret_val:=flags_etl_table;
end;
/
select * from album_scalar_table;
-- it should wait the completion of this function and transmite the data;
----------------------------------------------------------------------------------------------------------------------------
Normal method of doing passing data to application. with table functions : Table Functions
----------------------------------------------------------------------------------------------------------------------------

 
create or replace type album_scalar_type as object 
(a_id VARCHAR2(10), 
flags VARCHAR2(1) 
); 

create or replace type album_table_type as table of album_scalar_type; 

-- Build the table function itself.
CREATE OR REPLACE FUNCTION get_tab_tf  RETURN album_table_type AS
  l_tab  album_table_type := album_table_type();
BEGIN
  FOR i IN 1 .. 100000000000000000000000000000 LOOP
    l_tab.extend;
    l_tab(l_tab.last) := album_scalar_type(i, 1);
  END LOOP;

  RETURN l_tab;
END;
/

select * from table(get_tab_tf);

Note : both the case the the end select statement would wait the calling function to complete and return the rows .

--------------------------------------------------------------
pipelined method of doing passing data to application.
--------------------------------------------------------------

create or replace type album_scalar_type as object 
(a_id VARCHAR2(10), 
flags VARCHAR2(1) 

create or replace type album_table_type as table of album_scalar_type; 


CREATE OR REPLACE FUNCTION flags_etl 
RETURN album_table_type PIPELINED AS
v_a_id VARCHAR2(10);
v_a_flag VARCHAR2(10);
v_flg VARCHAR2(1);
BEGIN
LOOP
  FOR I IN 1..100000000000000000000000000000 
  LOOP
  
  pipe row( album_scalar_type(I, 1) );
 
  END LOOP;
END LOOP;
RETURN;
END;
/

select * from table(flags_etl());

-- this will return the rows immediately when the return interval reaches, means that whenever the rows are getting inserted into the array , oracle automatically transfer the data. so this will avoid the I/O of sending the bulk data in one shot.


--------------------------------------------------------------------------
Demo -- will that entire loop getting executed ????
--------------------------------------------------------------------------


CREATE OR REPLACE FUNCTION flags_etl 
RETURN album_table_type PIPELINED AS
v_a_id VARCHAR2(10);
v_a_flag VARCHAR2(10);
v_flg VARCHAR2(1);
BEGIN
LOOP
  FOR I IN 1..1000
  LOOP
      DBMS_LOCK.sleep(seconds =>.1);
  pipe row( album_scalar_type(I, 1) );
  insert into album_scalar_table values  (I, I);
  END LOOP;
END LOOP;
RETURN;
END;
/

select * from table(flags_etl())
where rownum <=20

-- result of error.. cannot perform a DML operation inside a query.

--advantage of no need of wait until the function completes.

CREATE OR REPLACE FUNCTION flags_etl 
RETURN album_table_type PIPELINED AS
v_a_id VARCHAR2(10);
v_a_flag VARCHAR2(10);
v_flg VARCHAR2(1);
BEGIN
LOOP
  FOR I IN 1..1000
  LOOP
     
  pipe row( album_scalar_type(I, 1) );
 dbms_output.put_line  (I);
  END LOOP;
END LOOP;
RETURN;
END;
/

select * from table(flags_etl())
where rownum <=100;

select * from table(flags_etl())A 
where rownum <=100
order by a.a_id desc 

-- so the loop will get terminated only 100 times.
-- so this wont wait until function completes

--------------------------------------------------------------------------
Demo --  NO_DATA_NEEDED
--------------------------------------------------------------------------

A pipelined table function may create more data than is needed by the process querying it. When this happens, 
the pipelined table function execution stops, raising the NO_DATA_NEEDED exception. 
This doesn't need to be explicitly handled provided you do not include an OTHERS exception handler.

CREATE OR REPLACE FUNCTION flags_etl 
RETURN album_table_type PIPELINED AS
v_a_id VARCHAR2(10);
v_a_flag VARCHAR2(10);
v_flg VARCHAR2(1);
BEGIN
LOOP
  FOR I IN 1..1000
  LOOP
     
  pipe row( album_scalar_type(I, 1) );
 dbms_output.put_line  (I);
  END LOOP;
END LOOP;
RETURN;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.put_line('OTHERS Handler');
    RAISE;
END;
/

select * from table(flags_etl())
where rownum <=100;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
OTHERS Handler

Thursday, July 3, 2014

Oracle Long to varchar2 conversion and substr of long columns

=======================================================================
-- Create table
=======================================================================

create table DBA_CONSTRAINTS_DUMMY
(
  CONSTRAINT_NAME  VARCHAR2(4000),
  TABLE_NAME       VARCHAR2(4000),
  CONSTRAINT_TYPE  VARCHAR2(4000),
  SEARCH_CONDITION VARCHAR2(4000)
)
/
=======================================================================
method 1 -- for all table values
=======================================================================
declare
long_var LONG;
var_var  VARCHAR2(2000);
begin

select search_condition into long_var
from dba_CONSTRAINTS where rownum<=1;
   
   var_var := substr(long_var,1,4000);
   
insert into dba_CONSTRAINTS_dummy values ( long_var,long_var,long_var,long_var);

end;
/

select * from dba_CONSTRAINTS_dummy ;

=======================================================================
method2 : if its a direct select from a single table 
=======================================================================
create or replace function convert_long_to_varchar2
(
p_rowid in rowid,
column_name varchar2,
table_name  varchar2)
return varchar2 is
long_var long;
v_sql varchar2(3000);
begin
v_sql := 'select '||column_name||' from '||table_name||' where rowid='||p_rowid;
execute immediate v_sql return into long_var;
  return substr( long_var, 1, 4000 );
end;

/

select  convert_long_to_varchar2(rowid) form table;

=======================================================================
Method 3 : using xmltype
=======================================================================
select *
from
xmltable('/ROWSET/ROW'
passing dbms_xmlgen.getXMLType('
select
table_name
,column_name
,data_type
,data_default
from user_tab_columns
where data_default is not null
'
)
columns
table_name varchar2(30)
,column_name varchar2(30)
,data_type varchar2(106)
,data_default varchar2(4000)
)
=======================================================================
Method 4 :TO_LOB
=======================================================================
select SUBSTR(CONSTRAINT_NAME, 1, 30) AS CONSTNAME,
SUBSTR(TABLE_NAME, 1, 30) AS TABNAME, constraint_type,
 TO_LOB(SEARCH_CONDITION   ) SEARCH_CONDITION
FROM  dba_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'C'

ORA-00932: inconsistent datatypes: expected - got LONG

 CREATE TABLE nullability_snapshot
   AS
   SELECT table_name
    ,      column_name
     ,      constraint_name
     ,      TO_LOB(search_condition) AS search_condition
     FROM   nullability_view;
=======================================================================
Method 5 :WITH EXTERNAL TABLE :
=======================================================================
  CREATE TABLE all_objects_Long
  ORGANIZATION EXTERNAL
  (
     TYPE ORACLE_DATAPUMP
      DEFAULT DIRECTORY DATA_PUMP_DIR
     LOCATION ( 'long.dmp' )
  )
    PARALLEL 4
   AS
   select  CONSTRAINT_NAME  , TABLE_NAME , constraint_type
    , to_lob(SEARCH_CONDITION) SEARCH_CONDITION FROM dba_CONSTRAINTS x;

=======================================================================
Method 6 :Pipeline function
=======================================================================
CREATE TYPE nullability_ot AS OBJECT
    ( CONSTNAME       VARCHAR2(1000)
     , TABNAME      VARCHAR2(100)
     ,constraint_type VARCHAR2(100)
    , search_condition CLOB
   );
  
CREATE TYPE nullability_ntt AS TABLE OF nullability_ot;
 
CREATE FUNCTION nullability_pipelined RETURN nullability_ntt PIPELINED AS
     BEGIN
      FOR r IN (select SUBSTR(CONSTRAINT_NAME, 1, 30) AS CONSTNAME,
SUBSTR(TABLE_NAME, 1, 30) AS TABNAME, constraint_type,
  SEARCH_CONDITION   
FROM  user_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'C') LOOP
         PIPE ROW ( nullability_ot(r.CONSTNAME,
                                   r.TABNAME,
                                    r.constraint_type,
                                    r.SEARCH_CONDITION) );
       END LOOP;
       RETURN;
END;
SELECT 
CONSTNAME ,     
 TABNAME    ,
constraint_type,
substr(search_condition,1,100)
    FROM   TABLE(nullability_pipelined)
    WHERE  UPPER(search_condition) LIKE '%IS NOT NULL%';

 

Tuesday, July 1, 2014

பெரிய தாதம்பாளையம் ஏரி : சீமைகருவேல மரம்

பெரிய தாதம்பாளையம் ஏரி , இது கரூர் - தாராபுரம் சாலையில் 11 வது Kilometeril உள்ளது. இந்த ஏரியின் பரப்பளவு கிட்டத்தட்ட 300 acres.

 

இந்த ஏரியின் எல்லைகளாக பெரிய தாதம்பாளையம் , சின்ன தாதம்பாளையம் ,பள்ளமருதபட்டி, கொத்தம்பாளையம் உள்ளன.
இதன் பெரிய மதகு பெரிய தாதம்பாளையத்திலும்  , அவசர கால மதகு சின்ன  தாதம்பாளையத்திலும் உள்ளது. இந்த ஏரிக்கு வரும் வாய்க்கால் சின்னதாராபுரம் அருகே தொடங்கி  கொத்தம்பாளையம் அருகே முடிகிறது(30 Kilometers).
( Google Map)

 


15 வருடங்களுக்கு முன்பு வரை , மழை காலங்களில் இங்கு ஏராளமான கொக்கு, நாரை மட்டும் சில வெளிநாட்டுப் பறைவகளும் இங்கு வந்து தங்கி இனப்பெருக்கம் செய்தன. இப்பொழுது எதுவுமே இங்கு வருவதில்லை. இந்த ஏரியில் படகில் மீன் பிடித்த காலமும் உண்டு என்பது குறிப்பிடத்தக்கது.


பெரிய மதகு  (photo)



( தூர்ந்த நிலையில் இன்று இருக்கும் பெரிய மதகு)


(எவ்வளவு நீர் ஏரியில் இருந்து வெளியேறுகிறது என்பதை அளக்கும் அளவுகோல், தூர்ந்த நிலையில் இன்று)


அவசர கால மதகு (photo)








( மிக உறுதியான கருங்கல் சுவர்,ஏரியின் கரைகள்.)



நீர் வரத்து வாய்க்கால் (photo)












( ஒரு காலத்தில் இங்கு தண்ணீர் வந்ததற்கான சான்று, இந்த ஆற்று மண், சுமார் 5-7 அடி வரை ஆற்று மண் நிரம்பி உள்ளது)..

ஏரியின் தோற்றம்(photo).





















20 வருடங்களுக்கு முன்பு  வரை இந்த ஏரியில்  தண்ணீர் தேங்கி சுற்று  வட்டார கிராமங்களின் தண்ணீர் தேவையை பூர்த்தி செய்தது.
இந்த மதகு நீர் பெரிய தாதம்பாளையம் ,கரூர் ராஜவாய்காலில்  சென்று  முடிகிறது. இதன் மூலம் 1000 கணக்கான acre விவசாய நிலங்களும், கரூர் வரையிலான  நிலத்தடி நீரும் நன்கு இருந்தன.

இந்த ஏரிக்கு தண்ணீர் வரத்து அமராவதி ஆற்றில் சின்ன தாராபுரம் அருகே தொடங்கி, வரும் வழியில் 50 க்கும் மேற்பட்ட குளங்களை
 நிரப்பி இறுதியில் இங்கு வந்து சேருகிறது. வரும் வழியில் உள்ள 30+ ஊர்களின் மழை நீர் வடிகாலாகவும் இது இருந்து வந்தது.
 

இதன் இப்போதைய நிலை, ஆற்றில் இருந்து வரும் வாய்க்கால் மண் மூடியும், நில ஆக்கிரமப்பாலர்களால் அபகரிக்கப்பட்டும், தூர் வாரப்படாமலும் கிடக்கிறது. சில இடங்களில் இந்த வாய்க்காலின் தொடர்ச்சி அற்றுப்போயும் உள்ளது.

அத்துடன், இந்த ஏரியும் 100க் கணக்கான  வருடங்களாக  தூர் வாரப்படாமல், மறு  புணரமைப்பு பன்னாமலும் தூர்ந்து போய் உள்ளது.  இதனால் ஏரி  முழுவதும் சீமை கருவேல மரங்கள் முளைத்துக்கிடக்கிறது.

 இதனால் சுற்றுவட்டார  அளவில்  நிலத்தடி நீர் அதளாபாலத்துக்கு சென்று விட்டது.இதனால் கிணற்று நீர் மட்டமும் குறைந்து விட்டது.வறட்சி , கடுமையான வெப்பம் , மற்றும் குடிநீர் பற்றாக்குறை இங்கு தலை விரித்தாடுகிறது. சில ஆண்டுகளுக்கு முன்னால் இந்த ஏரி , ஃபாரெஸ்ட் கட்டுப்பாட்டுக்கு  கொண்டு வரப்பட்டு , சில பகுதிகளில் இந்த சீமை கருவேல மரங்கள் அழிக்கப்பட்டு வேறு மரங்கள் நடப்பட்டன. இருந்தும் மழை இல்லாத காரணத்தால் அவை நான்கு வளரவில்லை, சில இடங்களில் அழிந்தும் போய்விட்டன.இதன் விதைகள் காற்றில் பரவி , விவசாய நிலம் முழுவதும் முளைத்து விடுகின்றன.


இந்த ஏரியை மீண்டும் சீரமைப்பதான் மூலம், கரூர் மற்றும் அதன் சுற்று வட்டார கிராமங்கல் குடிநீர் வசதி பெறலாம், நிலத்தடி மட்டம் நன்கு உயரும், சின்ன தாரபுரம் முதல் கரூர் வரையிலான மானாவாரி நிலங்கள் பாசன வசதி பெரும்.


இந்த முயற்ச்சியை , எங்கள் ஊர் விவசாய நண்பர்கள் ஆக்கப் பூர்வமாக செய்கின்றாம். கலெக்டர் மட்டும் வீவசாய  அதிகாரீகளை சந்தித்து மனுக்கள் கொடுத்து உள்ளன. இதை பற்றி தினமலர் நாளிதழில் செய்தியும் வந்தது.ஆனால் இது வரை எந்த பயனும்   இல்லை .இயற்கை ஆர்வலர்கள் இதற்கு உதவுமாறு எங்கள் ஊர் மக்கள் சார்பாக கேட்டு கொள்கிறேன்.


குறிப்பு : இன்று நாம் சிந்தும் ஒவ்வொரு வியர்வைக்கும் மூல காரணமாக இருப்பவை இந்த கருவேல மரங்கள் தான். 
கருவேல மரங்களின் இலை, காய், விதை போன்றவை எந்த உயிரினத்திற்கும் பயன்படாதவை. இம்மரத்தின் நிழலில் கட்டிவைக்கப்படும் கால்நடைகள் "மலடாக' மாறும் என்பது, சமீபத்தில் கண்டறியப்பட்டுள்ளது. இவற்றின் வேர் நிலத்தடி நீரை விஷமாக மாற்றும் தன்மை கொண்டது. அதே நேரத்தில் இவை முளைத்துள்ள பகுதியில் வேறு செடிகள் வளரமுடியாது. இவற்றின் விஷத்தன்மை அறிந்தே, இதன் மீது எந்த பறவையும் கூடுகட்டுவது இல்லை. ஐந்தறிவு கொண்ட உயிரினங்கள் அனைத்தும், கருவேல மரங்களை ஒட்டுமொத்தமாக புறக்கணித்து வருகின்றன.
எந்த வறட்சியிலும் வளரக்கூடிய தன்மை கருவேல மரங்களுக்கு உண்டு. மழை இல்லாமல் போனாலும் நிலத்தடி நீரை உறிஞ்சி , தனது இலைகளை வாழவிடாமல் பார்த்துக்கொள்கிறது
தன்னை சுற்றி தழுவி வரும் காற்றில் உள்ள ஈரப்பதத்தையும் உறிஞ்சிவிடுகின்றன. இதனால் அப்பகுதியில் வறட்சி என்பது தவிர்க்க முடியாததாகவும், நிலையானதாகவும் மாறிவிடுகிறது.
 

Performence : Tune stat gather and Index rebuild.

Issue :  Running Index stat and table stat gather on the huge database take long time to finish. This
process can be further tunned with the following way.

Pre request :

1)  Grant DBMS_SCHEDULAR Permission to 
-----------------------------------------------------

  Connect to sys user and execute below permission to
       grant all on DBA_SCHEDULER_JOB_RUN_DETAILS to ;
       grant all on DBMS_LOCK to ;
       grant all on DBMS_ISCHED to ;
       grant all on DBMS_SCHEDULER to ;
       grant CREATE ANY JOB to ;

2) connect to schema and run the script
--linux session , cd to file folder where the table_analysis_with_index.sql is placed.

sql> @./table_analysis_with_index.sql

3) calculate the no.of degree and parellal based on the below.

Parallel session can be calculated by using
select * from v$parameter
PARALLEL_DEGREE_POLICY
select * from v$parameter where name like '%cpu%'
select * from v$parameter where name like 'para%'
select * from v$parameter where name like 'para%' or name like '%cpu%'
For a single instance, DOP = PARALLEL_THREADS_PER_CPU x CPU_COUNT
For an Oracle RAC configuration, DOP = PARALLEL_THREADS_PER_CPU x CPU_COUNT x INSTANCE_COUNT
       ALTER SESSION FORCE PARALLEL DDL PARALLEL 8;
       ALTER SESSION FORCE PARALLEL DML PARALLEL 8;
       Note : this will force the DDL/DML operation to run in parallel.
4) script.
copy the below text and make the file table_analysis_with_index.sql

spool ./runstat_details.txt
select systimestamp from dual;
drop table schema_runstat_job_details;
create table schema_runstat_job_details ( job_name varchar2(1000),details varchar2(4000)) ;
alter table schema_runstat_job_details add constraint   schema_runstat_pk primary key  ( job_name); 
 

declare
  p_job_name    varchar2(100) := 'schemastat';
  p_exit        number := 20;
  no_of_session number := 20;
  p_count       number := 0;
begin
  delete from schema_runstat_job_details;
 
  --- call for big tables  separatly.
 
 
 
  for x in (select table_name
              from user_tables where table_name in (,)
              ) loop
    p_job_name := DBMS_SCHEDULER.GENERATE_JOB_NAME('schemastat_');
 
    insert into schema_runstat_job_details
    values
      (p_job_name, x.table_name);
    commit;
    dbms_scheduler.create_job(job_name   => p_job_name,
                              job_type   => 'PLSQL_BLOCK',
                              job_action => 'begin  execute immediate ' ||
                                            '''ALTER SESSION FORCE PARALLEL DDL PARALLEL 5''' || ';
                            DBMS_STATS.gather_table_stats (
        ownname      => ' ||
                                            '''&SCHEMA_NAME''' ||
                                            ',tabname      => ' || '''' ||
                                            x.table_name || '''' ||
                                            ' ,method_opt   => ' || '''' ||
                                            'for all indexed columns size 254' || '''' ||
                                              ',degree      => 5' ||
                                            ',cascade      => FALSE);' || '
                                        
                          exception
                            when others then
                            null;
                   end;',
                              comments   => 'Thread ' || 1 ||
                                            ' for schemastat_',
                              enabled    => true,
                              auto_drop  => FALSE);
end loop;

  --- call for big tables indexs  separatly. 
 
  for x in (select index_name
              from user_indexes where table_name in (,)
              )
              loop
    p_job_name := DBMS_SCHEDULER.GENERATE_JOB_NAME('schemastat_');
 
    insert into schema_runstat_job_details
    values
      (p_job_name, x.index_name);
    commit;
    dbms_scheduler.create_job(job_name   => p_job_name,
                              job_type   => 'PLSQL_BLOCK',
                              job_action => 'begin  execute immediate ' ||
                                            '''ALTER SESSION FORCE PARALLEL DDL PARALLEL 5''' || ';
                            DBMS_STATS.GATHER_INDEX_STATS (
        ownname      => ' ||
                                            '''&SCHEMA_NAME''' ||
                                            ',indname       => ' || '''' ||
                                            x.index_name || '''' ||
                                            ',degree      => 5 );' ||'                                        
                          exception
                            when others then
                            null;
                   end;',
                              comments   => 'Thread ' || 1 ||
                                            ' for schemastat_',
                              enabled    => true,
                              auto_drop  => FALSE);
end loop;

     
for x in (select table_name
              from user_tables where table_name not in (,)
              ) loop
    p_job_name := DBMS_SCHEDULER.GENERATE_JOB_NAME('schemastat_');
 
    insert into schema_runstat_job_details
    values
      (p_job_name, x.table_name);
    commit;
    dbms_scheduler.create_job(job_name   => p_job_name,
                              job_type   => 'PLSQL_BLOCK',
                              job_action => 'begin  execute immediate ' ||
                                            '''ALTER SESSION FORCE PARALLEL DDL PARALLEL 5''' || ';
                            DBMS_STATS.gather_table_stats (
        ownname      => ' ||
                                            '''&SCHEMA_NAME''' ||
                                            ',tabname      => ' || '''' ||
                                            x.table_name || '''' ||
                                            ' ,method_opt   => ' || '''' ||
                                            'for all indexed columns size 254' || '''' ||
                                            ',degree      => 5' ||
                                            ',cascade      => TRUE);' || '
                                        
                          exception
                            when others then
                            null;
                   end;',
                              comments   => 'Thread ' || 1 ||
                                            ' for schemastat_',
                              enabled    => true,
                              auto_drop  => FALSE);
 
    p_exit := no_of_session;
    WHILE (p_exit >= no_of_session) LOOP
   
      select count(*)
        into p_exit
        from dba_scheduler_jobs
       where job_name in (select job_name from schema_runstat_job_details)
         and state in ('SCHEDULED', 'RUNNING');
   
    END LOOP;
  end loop;
end;

/

declare
  p_exit      number:=1;
  job_count number;
begin
WHILE (p_exit<>0)
    LOOP
    select count(*) into job_count from  schema_runstat_job_details;
     select count(*)-job_count
       into p_exit
     from  dba_scheduler_jobs
     where job_name in ( select job_name from schema_runstat_job_details)
        and state in ( 'SUCCEEDED','FAILED');
        DBMS_LOCK.sleep(seconds => 120);
    END LOOP;
end;
/
select systimestamp from dual;

select ' startdate   || end date || time in total ' from dual;
select max_time-min_time total_duration from
(select  max(b.ACTUAL_START_DATE+b.RUN_DURATION )max_time  ,min(b.ACTUAL_START_DATE+b.RUN_DURATION ) min_time from
 DBA_SCHEDULER_JOB_RUN_DETAILS b
     where job_name in ( select job_name from schema_runstat_job_details)
      );
 select a.*,additional_info ,b.ACTUAL_START_DATE,b.RUN_DURATION  from
(
  select  state , job_name,job_action
     from  USER_SCHEDULER_JOBS
     where job_name in ( select job_name from schema_runstat_job_details)
      )A, DBA_SCHEDULER_JOB_RUN_DETAILS B
     where a.job_name=b.job_name
order by RUN_DURATION desc

select table_name,last_analyzed From user_tables where trunc(last_analyzed ) = trunc(sysdate);
select index_name,last_analyzed  from user_indexes
where  trunc(last_analyzed ) = trunc(sysdate) ;
--drop table schema_runstat_job_details;
 
spool off;

6)

3) checnk the status by using
 select a.*,additional_info ,b.ACTUAL_START_DATE,b.RUN_DURATION  from
(
  select  state , job_name,job_action
     from  USER_SCHEDULER_JOBS
     where job_name in ( select job_name from schema_runstat_job_details)
      )A, DBA_SCHEDULER_JOB_RUN_DETAILS B
     where a.job_name=b.job_name
order by RUN_DURATION desc
  
4) check the running jobs
   
      select count(*)       
        from dba_scheduler_jobs
       where job_name in (select job_name from schema_runstat_job_details)
         and state in ('SCHEDULED', 'RUNNING');

--object which are not analysed.
select table_name,last_analyzed From user_tables where trunc(last_analyzed ) <> trunc(sysdate);
select index_name,last_analyzed  from user_indexes
where  trunc(last_analyzed ) <> trunc(sysdate) ;

5) Recall Analysis for the failed object / or for any specific tables and index
if we want call any object/failed object to do the analysis
the below piece of code will help. Change the table name.

begin
      execute immediate 'ALTER SESSION FORCE PARALLEL DDL PARALLEL 5';
      DBMS_STATS.gather_table_stats (
                         ownname      => '&SCHEMA_NAME',
                         tabname      => '&TABLE_NAME' ,
                         method_opt   => 'for all indexed columns size 254',degree      => 5,
                         cascade      => TRUE);
        exception
       when others then
         null;
  end;
/