Thursday, March 14, 2024

Top useful SQL queries for PostgreSQL

 There are a lot of articles about working with PostgreSQL and its advantages, but it is not always clear from them how to monitor the  and metrics that affect its optimal work. In the article, we will take a detailed look at SQL queries that will help you track these indicators and can be useful for regular users.



Why do you need to monitor the state of PostgreSQL?

Database monitoring is important as monitoring your applications. It is necessary to monitor processes in more detail than at the system level. To do this, you can track the following metrics:

  1. How efficient is the database cache?
  2. What is the size of the tables in your database?
  3. Are your indexes used?
  4. Etc.

Monitoring the size of the database and its elements

1. Size of tablespaces

SELECT spcname, pg_size_pretty(pg_tablespace_size(spcname)) 
FROM pg_tablespace
WHERE spcname<>'pg_global';

After running the query, you will receive information about the size of all tablespaces created in your database. The pg_tablespace_size function provides information about the size of the tablespace in bytes, so we also use the pg_size_pretty function to make it readable. The pg_global space is excluded, since it is used for shared system directories.

2. Size of databases

SELECT pg_database.datname,
pg_size_pretty(pg_database_size(pg_database.datname)) AS size
FROM pg_database
ORDER BY pg_database_size(pg_database.datname) DESC;

After running the query, you will receive information about the size of each database created within your PostgreSQL instance.

3. Size of schemas in the database

SELECT A.schemaname,
pg_size_pretty (SUM(pg_relation_size(C.oid))) as table,
pg_size_pretty (SUM(pg_total_relation_size(C.oid)-pg_relation_size(C.oid))) as index,
pg_size_pretty (SUM(pg_total_relation_size(C.oid))) as table_index,
SUM(n_live_tup)
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C .relnamespace)
INNER JOIN pg_stat_user_tables A ON C.relname = A.relname
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C .relkind <> 'i'
AND nspname !~ '^pg_toast'
GROUP BY A.schemaname;

After running the query, you will receive detailed information about each schema in your database: the total size of all tables, the total size of all indexes, the total size of the schema and the total number of rows in all schema tables.

4. Size of tables

SELECT schemaname,
C.relname AS "relation",
pg_size_pretty (pg_relation_size(C.oid)) as table,
pg_size_pretty (pg_total_relation_size (C.oid)-pg_relation_size(C.oid)) as index,
pg_size_pretty (pg_total_relation_size (C.oid)) as table_index,
n_live_tup
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C .relnamespace)
LEFT JOIN pg_stat_user_tables A ON C.relname = A.relname
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind <> 'i'
AND nspname !~ '^pg_toast'
ORDER BY pg_total_relation_size (C.oid) DESC

After running the query, you will receive detailed information about each table indicating its schema, size without indexes, size of indexes, total size of the table and indexes, as well as the number of rows in the table.

Control of deadlocks

If more than one user uses your database, there is always a risk of deadlocks of queries and the appearance of a queue with numerous of queries that will be pending. Most often, this can occur when processing many queries using the same tables. They will prevent each other from completing and prevent other queries from starting. You can read more about this in the official documentation. We will consider ways to find locks and remove them.

1. Monitoring of deadlocks

SELECT COALESCE(blockingl.relation::regclass::text, blockingl.locktype) AS locked_item,
now() - blockeda.query_start AS waiting_duration,
blockeda.pid AS blocked_pid,
blockeda.query AS blocked_query,
blockedl.mode AS blocked_mode,
blockinga.pid AS blocking_pid,
blockinga.query AS blocking_query,
blockingl.mode AS blocking_mode
FROM pg_locks blockedl
JOIN pg_stat_activity blockeda ON blockedl.pid = blockeda.pid
JOIN pg_locks blockingl ON (blockingl.transactionid = blockedl.transactionid OR
blockingl.relation = blockedl.relation AND
blockingl.locktype = blockedl.locktype) AND blockedl.pid <> blockingl.pid
JOIN pg_stat_activity blockinga ON blockingl.pid = blockinga.pid AND blockinga.datid = blockeda.datid
WHERE NOT blockedl.granted AND blockinga.datname = current_database();

This query shows all information about blocked queries as well as information about who blocked them.

2. Removing of deadlocks

SELECT pg_cancel_backend(PID_ID);
OR
SELECT pg_terminate_backend(PID_ID);

PID_ID is the ID of the query that blocks other queries. Most often, it is enough to cancel one blocking query to remove the deadlocks and start the entire accumulated queue. The difference between pg_cancel_backend and pg_terminate_backend is that pg_cancel_backend cancels the query, and pg_terminate_backend ends the session and closes the database connection. The pg_cancel_backend command is more gentle and in most cases it will be enough for you. If not, use pg_terminate_backend.


Indicators of optimal performance of your database

1. Cache Hit Ratio

SELECT sum(heap_blks_read) as heap_read,
sum(heap_blks_hit) as heap_hit,
sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio
FROM
pg_statio_user_tables;

The caching coefficient is a measure of read efficiency, measured by the proportion of cache reads compared to the total number of reads from both disk and cache. Except when using data storage, the ideal caching ratio is 99% or higher, which means that at least 99% of reads are performed from the cache and no more than 1% from disk.

2. Using of indexes

SELECT relname,   
100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used,
n_live_tup rows_in_table
FROM pg_stat_user_tables
WHERE seq_scan + idx_scan > 0
ORDER BY n_live_tup DESC;

Adding indexes to your database makes a big difference to query performance. Indexes are especially important for large tables. This query shows the number of rows in tables and the percentage of index usage time compared to reading without indexes. Ideal candidates for adding an index are tables larger than 10,000 rows with zero or low index usage.

3. Index Cache Hit Rate

SELECT sum(idx_blks_read) as idx_read,
sum(idx_blks_hit) as idx_hit,
(sum(idx_blks_hit) - sum(idx_blks_read)) / sum(idx_blks_hit) as ratio
FROM pg_statio_user_indexes;

This coefficient is similar to the usual caching coefficient, but is calculated based on index usage data.

4. Unused indexes

SELECT schemaname, relname, indexrelname
FROM pg_stat_all_indexes
WHERE idx_scan = 0 and schemaname <> 'pg_toast' and schemaname <> 'pg_catalog'

This query finds indexes that were created but not used in SQL queries.

5. Database bloat

SELECT
current_database(), schemaname, tablename, /*reltuples::bigint, relpages::bigint, otta,*/
ROUND((CASE WHEN otta=0 THEN 0.0 ELSE sml.relpages::float/otta END)::numeric,1) AS tbloat,
CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::BIGINT END AS wastedbytes,
iname, /*ituples::bigint, ipages::bigint, iotta,*/
ROUND((CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages::float/iotta END)::numeric,1) AS ibloat,
CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes
FROM (
SELECT
schemaname, tablename, cc.reltuples, cc.relpages, bs,
CEIL((cc.reltuples*((datahdr+ma-
(CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta,
COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta /* very rough approximation, assumes all cols */
FROM (
SELECT
ma,bs,schemaname,tablename,
(datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
(maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
FROM (
SELECT
schemaname, tablename, hdr, ma, bs,
SUM((1-null_frac)*avg_width) AS datawidth,
MAX(null_frac) AS maxfracsum,
hdr+(
SELECT 1+count(*)/8
FROM pg_stats s2
WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
) AS nullhdr
FROM pg_stats s, (
SELECT
(SELECT current_setting('block_size')::numeric) AS bs,
CASE WHEN substring(v,12,3) IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
CASE WHEN v ~ 'mingw32' THEN 8 ELSE 4 END AS ma
FROM (SELECT version() AS v) AS foo
) AS constants
GROUP BY 1,2,3,4,5
) AS foo
) AS rs
JOIN pg_class cc ON cc.relname = rs.tablename
JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = rs.schemaname AND nn.nspname <> 'information_schema'
LEFT JOIN pg_index i ON indrelid = cc.oid
LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
) AS sml
ORDER BY wastedbytes DESC;

Database bloat is disk space that has been used by a table or index and is available for reuse by the database, but has not been freed up. Bloating occurs when tables or indexes are updated. If you have a loaded database with a lot of deletion operations, bloating can leave a lot of unused space in your database and affect performance if it is not removed. The metrics of wastedbytes for tables and wastedibytes for indexes will show you if you have any serious bloat issues. To combat with bloat there is a VACUUM command.

6. Checking VACUUM starts

SELECT relname, 
last_vacuum,
last_autovacuum
FROM pg_stat_user_tables;

The bloat can be reduced using the VACUUM command, but PostgreSQL also supports AUTOVACUUM. You can read about its setup here.

A few more queries that may be useful to you

1. Shows the number of open connections

SELECT COUNT(*) as connections,
backend_type
FROM pg_stat_activity
where state = 'active' OR state = 'idle'
GROUP BY backend_type
ORDER BY connections DESC;

Shows open connections to all databases in your PostgreSQL instance. If you have several databases in one PostgreSQL, then add datname = ‘Your Database’ to the WHERE condition.

2. Shows running queries

SELECT pid, age(clock_timestamp(), query_start), usename, query, state
FROM pg_stat_activity
WHERE state != 'idle' AND query NOT ILIKE '%pg_stat_activity%'
ORDER BY query_start desc;

Shows running queries and their duration.

ORACLE DATABASE SERVER REPORT IN HTML FORMAT

 set pagesize 1100

SET MARKUP HTML ON SPOOL ON PREFORMAT OFF ENTMAP ON

spool ORACLE_DATABASE_INFO.html

set feedback off

set linesize 200;

set pages 50

set lines 1000

set pages 70

set heading on

PROMPT ===============================================================================================================================================

PROMPT                                         ORACLE DATABASE SERVER REPORT

PROMPT ===============================================================================================================================================

PROMPT REPORT DATE:

PROMPT ============

select to_char(sysdate,'DD-MON-YYYY:HH:MI:SS' ) "REPORT RUN DATE" from dual;


PROMPT DATABASE DETAILS:

PROMPT ================

SELECT

    gv.instance_name,

    gv.host_name,

    gv.version,

    gv.status,

    v.NAME,

    v.CREATED,

    v.LOG_MODE,

    v.CHECKPOINT_CHANGE#,

    v.ARCHIVE_CHANGE#

FROM

    gv$instance gv

CROSS JOIN

    v$database v;


PROMPT DATABASE SIZE:

PROMPT =============

select

( select sum(bytes)/1024/1024/1024 data_size from dba_data_files ) +

( select nvl(sum(bytes),0)/1024/1024/1024 temp_size from dba_temp_files ) +

( select sum(bytes)/1024/1024/1024 redo_size from sys.v_$log ) +

( select sum(BLOCK_SIZE*FILE_SIZE_BLKS)/1024/1024/1024 controlfile_size from v$controlfile) "Size in GB"

from

dual;


PROMPT TABLESPACE INFO:

PROMPT ================

set linesize 100

set pagesize 100

set pages 999

set lines 400

SELECT df.tablespace_name tablespace_name,

 max(df.autoextensible) auto_ext,

 round(df.maxbytes / (1024 * 1024), 2) max_ts_size,

 round(df.bytes / (1024 * 1024), 2) curr_ts_size,

 round((df.bytes - sum(fs.bytes)) / (1024 * 1024), 2) used_ts_size,

 round(sum(fs.bytes) / (1024 * 1024), 2) free_ts_size

FROM dba_free_space fs,

 (select tablespace_name,

 sum(bytes) bytes,

 sum(decode(maxbytes, 0, bytes, maxbytes)) maxbytes,

 max(autoextensible) autoextensible

 from dba_data_files

 group by tablespace_name) df

WHERE fs.tablespace_name (+) = df.tablespace_name

GROUP BY df.tablespace_name, df.bytes, df.maxbytes

UNION ALL

SELECT df.tablespace_name tablespace_name,

 max(df.autoextensible) auto_ext,

 round(df.maxbytes / (1024 * 1024), 2) max_ts_size,

 round(df.bytes / (1024 * 1024), 2) curr_ts_size,

 round((df.bytes - sum(fs.bytes)) / (1024 * 1024), 2) used_ts_size,

 round(sum(fs.bytes) / (1024 * 1024), 2) free_ts_size

FROM (select tablespace_name, bytes_used bytes

 from V$temp_space_header

 group by tablespace_name, bytes_free, bytes_used) fs,

 (select tablespace_name,

 sum(bytes) bytes,

 sum(decode(maxbytes, 0, bytes, maxbytes)) maxbytes,

 max(autoextensible) autoextensible

 from dba_temp_files

 group by tablespace_name) df

WHERE fs.tablespace_name (+) = df.tablespace_name

GROUP BY df.tablespace_name, df.bytes, df.maxbytes

ORDER BY 4 DESC;


PROMPT TEMP TABLESPACE USAGE:

PROMPT =====================

set feedback off echo off

set linesize 200

set pagesize 200

set colsep |

SET TRIM ON

SELECT A.tablespace_name tablespace, D.mb_total,

SUM (A.used_blocks * D.block_size)/1024/1024 mb_used,

D.mb_total - SUM (A.used_blocks * D.block_size)/1024/1024 mb_free

FROM v$sort_segment A,

(

SELECT B.name, C.block_size, SUM (C.bytes) / 1024 / 1024 mb_total

FROM v$tablespace B, v$tempfile C

WHERE B.ts#= C.ts#

GROUP BY B.name, C.block_size

) D

WHERE A.tablespace_name = D.name

GROUP by A.tablespace_name, D.mb_total;


PROMPT SESSION INFORMATION:

PROMPT ====================

SELECT

    CASE

        WHEN status = 'ACTIVE' THEN 'Active'

        WHEN status = 'INACTIVE' THEN 'Inactive'

        ELSE 'Total'

    END AS status,

    COUNT(status) AS Count

FROM

    v$session

GROUP BY

    CASE

        WHEN status = 'ACTIVE' THEN 'Active'

        WHEN status = 'INACTIVE' THEN 'Inactive'

        ELSE 'Total'

    END

ORDER BY

    CASE

        WHEN status = 'Total' THEN 2

        ELSE 1

    END;


PROMPT CPU AND MEMORY LIMIT OF DATABASE SERVER:

PROMPT ========================================

set pagesize 299

set lines 299

SELECT STAT_NAME, TO_CHAR(VALUE) AS VALUE

FROM v$osstat

WHERE stat_name IN ('NUM_CPUS','NUM_CPU_CORES','NUM_CPU_SOCKETS')

UNION

SELECT STAT_NAME, VALUE/1024/1024/1024 || ' GB'

FROM v$osstat

WHERE stat_name = 'PHYSICAL_MEMORY_BYTES';


PROMPT CURRENT SGA USAGE:

PROMPT ==================

SET MARKUP HTML ON SPOOL ON PREFORMAT OFF ENTMAP ON

select round(used.bytes /1024/1024 ,2) used_mb

, round(free.bytes /1024/1024 ,2) free_mb

, round(tot.bytes /1024/1024 ,2) total_mb

from (select sum(bytes) bytes

from v$sgastat

where name != 'free memory') used

, (select sum(bytes) bytes

from v$sgastat

where name = 'free memory') free

, (select sum(bytes) bytes

from v$sgastat) tot;


PROMPT PGA TARGET AND HARD LIMIT:

PROMPT ===========================

SELECT name,

       TO_CHAR(value / (1024 * 1024), '999,999,999.99') || ' MB' AS value_in_mb

FROM v$parameter

WHERE name IN ('pga_aggregate_target', 'pga_aggregate_limit');


PROMPT RESOURCE UTILIZATION IN DATABASE:

PROMPT =================================

select resource_name, current_utilization, max_utilization, limit_value from v$resource_limit where resource_name in ('sessions', 'processes');


PROMPT INVALID OBJECTS:

PROMPT ===============

Select count(*) "INVALID OBJECTS",OWNER,object_type from all_objects where status='INVALID' group by owner,object_type order by 2;


PROMPT REDO LOGS AND ARCHIVE STATUS:

PROMPT =============================

COLUMN member_name HEADING 'MEMBER_NAME';

COL MEMBER FOR A40;

SELECT vlf.member "MEMBER_NAME",

vl.group# "GROUP",

vl.status "STATUS",

vl.archived "ARCHIVED",

vl.bytes / 1024 "Size (K)",

vl.sequence# "SEQUENCE"

FROM v$logfile vlf,

v$log vl

WHERE vlf.group# = vl.group#

ORDER BY 1, vl.group#, vlf.member;


PROMPT SESSION I/O BY USERS:

PROMPT =====================

column USERNAME format a10

column OS_USER format a10

column PID format a10

set lines 200

select nvl(ses.USERNAME,'ORACLE PROC') username,

OSUSER os_user,

PROCESS pid,

ses.SID sid,

SERIAL#,

PHYSICAL_READS,

BLOCK_GETS,

CONSISTENT_GETS,

BLOCK_CHANGES,

CONSISTENT_CHANGES

from v$session ses,

v$sess_io sio

where ses.SID = sio.SID

order by PHYSICAL_READS, ses.USERNAME;


PROMPT INACTIVE SESSIONS IN DATABASE:

PROMPT ==============================

PROMPT **********************************************************

PROMPT  Copy and Past in Cmd prompt as sys user to kill it

PROMPT **********************************************************

set feedback off

select 'alter system kill session ''' ||sid|| ',' || serial#|| ''' immediate;' from v$session where status='INACTIVE';


PROMPT DATABSE LOCK INFORMATION:

PROMPT =========================

col OBJECT_NAME for a13

col OSUSER for a10

col owner for a10

col username for a10

select c.sid,c.serial#,c.osuser,c.username,a.owner,a.object_name,a.object_id

from dba_objects a,v$locked_object b, v$session c

where a.object_id=b.object_id and c.sid=b.session_id;


select 'alter system kill session ''' || sid || ',' || serial# || '''immediate;'

from v$session where sid in (select SESSION_ID from v$locked_object);


PROMPT TOP 5 SQL CONSUMING CPU RESOURCE:

PROMPT =================================

set feedback off

SELECT username,

       buffer_gets,

       disk_reads,

       executions,

       buffer_get_per_exec,

       parse_calls,

       sorts,

       rows_processed,

       hit_ratio,

       module,

       sql_text

       -- elapsed_time, cpu_time, user_io_wait_time, ,

  FROM (SELECT sql_text,

               b.username,

               a.disk_reads,

               a.buffer_gets,

               trunc(a.buffer_gets / a.executions) buffer_get_per_exec,

               a.parse_calls,

               a.sorts,

               a.executions,

               a.rows_processed,

               100 - ROUND (100 * a.disk_reads / a.buffer_gets, 2) hit_ratio,

               module

               -- cpu_time, elapsed_time, user_io_wait_time

          FROM v$sqlarea a, dba_users b

         WHERE a.parsing_user_id = b.user_id

           AND b.username NOT IN ('SYS', 'SYSTEM', 'RMAN','SYSMAN')

           AND a.buffer_gets > 10000

         ORDER BY buffer_get_per_exec DESC)

 WHERE ROWNUM <= 5;


PROMPT SQL PERFORMANCE MONITORING REPORT:

PROMPT ==================================

SELECT

    s.STATUS,

    ROUND((TO_DATE(s.END_TIME, 'DD-MON-YYYY HH24:MI:SS') - TO_DATE(s.START_TIME, 'DD-MON-YYYY HH24:MI:SS')) * 24 * 60 * 60) AS DURATION_SECONDS,

    s.START_TIME,

    s.END_TIME,  -- Include START_TIME and END_TIME here

    s.SQL_ID,

    s.USERNAME AS "USER",

    s.IN_DBOP_NAME AS TYPE,

    s.BUFFER_GETS AS "Buffer Gets",

    ROUND((s.ELAPSED_TIME / 1000000), 2) AS "Elapsed (s)",

    ROUND((s.CPU_TIME / 1000000), 2) AS "CPU (s)",

    ROUND((s.PHYSICAL_READ_BYTES / (1024 * 1024)), 2) AS "Phys reads (MB)",

    ROUND((s.PHYSICAL_WRITE_BYTES / (1024 * 1024)), 2) AS "Phys writes (MB)",

    REGEXP_REPLACE(LISTAGG(t.SQL_TEXT, ' ') WITHIN GROUP (ORDER BY t.ADDRESS, t.HASH_VALUE, t.PIECE), '\s+', ' ') AS SQL_TEXT

FROM

    (SELECT

        s.STATUS,

        TO_CHAR(s.SQL_EXEC_START, 'DD-MON-YYYY HH24:MI:SS') AS START_TIME,

        TO_CHAR(s.SQL_EXEC_START + (s.ELAPSED_TIME / 1000000) / (24 * 60 * 60), 'DD-MON-YYYY HH24:MI:SS') AS END_TIME,

        s.SQL_ID,

        s.USERNAME,

        s.IN_DBOP_NAME,

        s.BUFFER_GETS,

        s.ELAPSED_TIME,

        s.CPU_TIME,

        s.PHYSICAL_READ_BYTES,

        s.PHYSICAL_WRITE_BYTES

    FROM

        V$SQL_MONITOR s

    WHERE

        s.USERNAME <> 'SYS' -- Exclude SQLs executed by SYS user

    ) s

JOIN

    V$SQLTEXT_WITH_NEWLINES t ON s.SQL_ID = t.SQL_ID

GROUP BY

    s.STATUS,

    s.SQL_ID,

    s.USERNAME,

    s.IN_DBOP_NAME,

    s.BUFFER_GETS,

    s.START_TIME,

    s.END_TIME,

    s.ELAPSED_TIME,

    s.CPU_TIME,

    s.PHYSICAL_READ_BYTES,

    s.PHYSICAL_WRITE_BYTES

ORDER BY

    s.START_TIME DESC;



PROMPT RMAN BACKUP DETAILS SYSDATE-180 DAYS:

PROMPT =====================================

set feedback off

set lines 220

set pages 1000

col cf for 9,999

col df for 9,999

col elapsed_seconds heading "ELAPSED|SECONDS"

col i0 for 9,999

col i1 for 9,999

col l for 9,999

col output_mbytes for 9,999,999 heading "OUTPUT|MBYTES"

col session_recid for 999999 heading "SESSION|RECID"

col session_stamp for 99999999999 heading "SESSION|STAMP"

col status for a10 trunc

col time_taken_display for a10 heading "TIME|TAKEN"

col output_instance for 9999 heading "OUT|INST"

select

  j.session_recid, j.session_stamp,

  to_char(j.start_time, 'yyyy-mm-dd hh24:mi:ss') start_time,

  to_char(j.end_time, 'yyyy-mm-dd hh24:mi:ss') end_time,

  (j.output_bytes/1024/1024) output_mbytes, j.status, j.input_type,

  decode(to_char(j.start_time, 'd'), 1, 'Sunday', 2, 'Monday',

                                     3, 'Tuesday', 4, 'Wednesday',

                                     5, 'Thursday', 6, 'Friday',

                                     7, 'Saturday') dow,

  j.elapsed_seconds, j.time_taken_display,

  x.cf, x.df, x.i0, x.i1, x.l,

  ro.inst_id output_instance

from V$RMAN_BACKUP_JOB_DETAILS j

  left outer join (select

                     d.session_recid, d.session_stamp,

                     sum(case when d.controlfile_included = 'YES' then d.pieces else 0 end) CF,

                     sum(case when d.controlfile_included = 'NO'

                               and d.backup_type||d.incremental_level = 'D' then d.pieces else 0 end) DF,

                     sum(case when d.backup_type||d.incremental_level = 'D0' then d.pieces else 0 end) I0,

                     sum(case when d.backup_type||d.incremental_level = 'I1' then d.pieces else 0 end) I1,

                     sum(case when d.backup_type = 'L' then d.pieces else 0 end) L

                   from

                     V$BACKUP_SET_DETAILS d

                     join V$BACKUP_SET s on s.set_stamp = d.set_stamp and s.set_count = d.set_count

                   where s.input_file_scan_only = 'NO'

                   group by d.session_recid, d.session_stamp) x

    on x.session_recid = j.session_recid and x.session_stamp = j.session_stamp

  left outer join (select o.session_recid, o.session_stamp, min(inst_id) inst_id

                   from GV$RMAN_OUTPUT o

                   group by o.session_recid, o.session_stamp)

    ro on ro.session_recid = j.session_recid and ro.session_stamp = j.session_stamp

where j.start_time > trunc(sysdate) - 180

order by j.start_time;


PROMPT NUMBER OF INDEXES ANALYZED IN LAST 5 DAYS:

PROMPT =========================================

PROMPT ***************************************************************************

PROMPT  the below count indicates that index which had their stats gathered

PROMPT ***************************************************************************

set feedback off

column min(last_Analyzed) format a18

column max(last_Analyzed) format a18

select owner,min(last_Analyzed), max(last_analyzed) from dba_indexes where last_analyzed > sysdate-5 group by owner order by 1;


PROMPT DB USERS WHO ARE EXPIRED OR LOCKED IN LAST 7 DAYS:

PROMPT ==================================================

set feedback on

select USERNAME,ACCOUNT_STATUS,CREATED,LAST_LOGIN,EXPIRY_DATE,DEFAULT_TABLESPACE from dba_users where ACCOUNT_STATUS NOT LIKE 'OPEN' and EXPIRY_DATE > sysdate -7;


PROMPT SCHEMA SIZES

PROMPT ==================================================

col OWNER for a20;

select owner,round(sum(bytes/1024/1024/1024)) "Size in GB" from dba_segments group by owner;


PROMPT LARGE TABLES

PROMPT ==================================================

Col OWNER for a30;

col SEGMENT_NAME for a30;

select OWNER,SEGMENT_NAME,SEGMENT_TYPE,round(BYTES/1024/1024/1024) "SIZE (GB)"from dba_segments where SEGMENT_TYPE='TABLE' and BYTES/1024/1024/1024 > 10 order by 4 desc;


PROMPT THE COUNT OF STALE STATISTICS TABLE SCHEMAWISE

PROMPT ==================================================

select OWNER,count(1) STALE_CNT from dba_tab_statistics where STALE_STATS='YES' GROUP BY OWNER;


PROMPT CHECK FOR TOP 10 TABLES

PROMPT ==================================================

SELECT * FROM (SELECT OWNER,SEGMENT_NAME,SEGMENT_TYPE,round(SUM(BYTES/1024/1024)) "SIZE MB" FROM DBA_SEGMENTS WHERE SEGMENT_TYPE like 'TABLE%' AND SEGMENT_NAME NOT LIKE 'BIN%' AND OWNER IN ( SELECT USERNAME FROM DBA_USERS WHERE ACCOUNT_STATUS='OPEN' AND USERNAME NOT IN ('SYS','SYSTEM','SYSMAN','DBSNMP')) GROUP BY OWNER, SEGMENT_NAME, SEGMENT_TYPE ORDER BY "SIZE MB" DESC) WHERE ROWNUM<=10;


PROMPT CHECK FOR TOP 10 INDEXES

PROMPT ==================================================

Col OWNER for a20;

col SEGMENT_NAME for a30;

SELECT * FROM (SELECT OWNER,SEGMENT_NAME,SEGMENT_TYPE,round(BYTES/1024/1024) "SIZE MB" FROM DBA_SEGMENTS WHERE SEGMENT_TYPE='INDEX' AND SEGMENT_NAME NOT LIKE 'BIN%' AND OWNER IN ( SELECT USERNAME FROM DBA_USERS WHERE ACCOUNT_STATUS='OPEN' AND USERNAME NOT IN ('SYS','SYSTEM','SYSMAN','DBSNMP') ) ORDER BY BYTES/1024/1024 DESC) WHERE ROWNUM<=10;


*************************************EOD*****************************************

In Oracle How to shrink Securefile LOB tables

As per Oracle support, if the table uses securefile LOB the traditional shrink method ALTER TABLE MODIFY LOB (XMLRECORD) (SHRINK SPACE) will...