Better Way of Looking at Dynamic Performance (v$) Views

Oracle database’s dynamic performance views, better known as v$ views, have loads of useful information related to the internals of Oracle database. But you have to admit, selecting from them especially using SQL*Plus produces an unreadable stream of texts on the screen that make them hard to use, unless using an IDE that puts the output into a nice looking table. Even then, you do have to scroll left and right to get what you want!

This made me wonder if there was an easy way to show the columns as rows, and Yes, according to the “column to rows” blog post in AskTOM there is an easy workaround for this solution. I checked it out and it works perfectly for what I need it to do, but I noticed after running the original solution that the RNUM column in the generated output returns the value 1 for all the rows. I checked and I think the l_rnum that’s being incremented by 1 on line 44 of the original solution should be moved to the inner loop after line 42. This little adjustment takes care of that issue, but other than that the function works brilliantly.

Definitely checkout the original question and answer, but I’m pasting the updated solution below for myself so I don’t have to search for this over and over! Come to think of it, it might be a good idea to add this little function to the list of scripts I run after each new database install to make my DBA life a bit easier!

CREATE OR replace TYPE myscalartype AS object (
  rnum  NUMBER,
  cname VARCHAR2(30),
  val   VARCHAR2(4000) )

/
CREATE OR replace TYPE mytabletype
  AS TABLE OF MYSCALARTYPE

/
CREATE OR replace FUNCTION Cols_as_rows(p_query IN VARCHAR2)
RETURN MYTABLETYPE
-- this function is designed to be installed ONCE per database, and
-- it is nice to have ROLES active for the dynamic sql, hence the
-- AUTHID CURRENT_USER
authid current_user
-- this function is a pipelined function -- meaning, it'll send
-- rows back to the client before getting the last row itself
-- in 8i, we cannot do this
pipelined
AS
  l_thecursor   INTEGER DEFAULT dbms_sql.open_cursor;
  l_columnvalue VARCHAR2(4000);
  l_status      INTEGER;
  l_colcnt      NUMBER DEFAULT 0;
  l_desctbl     dbms_sql.desc_tab;
  l_rnum        NUMBER := 1;
BEGIN
    -- parse, describe and define the query.  Note, unlike print_table
    -- i am not altering the session in this routine.  the
    -- caller would use TO_CHAR() on dates to format and if they
    -- want, they would set cursor_sharing.  This routine would
    -- be called rather infrequently, I did not see the need
    -- to set cursor sharing therefore.
    dbms_sql.Parse(l_thecursor, p_query, dbms_sql.native);

    dbms_sql.Describe_columns(l_thecursor, l_colcnt, l_desctbl);

    FOR i IN 1 .. l_colcnt LOOP
        dbms_sql.Define_column(l_thecursor, i, l_columnvalue, 4000);
    END LOOP;

    -- Now, execute the query and fetch the rows.  Iterate over
    -- the columns and "pipe" each column out as a separate row
    -- in the loop.  increment the row counter after each
    -- dbms_sql row
    l_status := dbms_sql.EXECUTE(l_thecursor);

    WHILE ( dbms_sql.Fetch_rows(l_thecursor) > 0 ) LOOP
        FOR i IN 1 .. l_colcnt LOOP
            dbms_sql.Column_value(l_thecursor, i, l_columnvalue);

            pipe ROW (Myscalartype( l_rnum, L_desctbl(i).col_name, l_columnvalue
            ));

            l_rnum := l_rnum + 1;
        END LOOP;
    END LOOP;

    -- clean up and return...
    dbms_sql.Close_cursor(l_thecursor);

    RETURN;
END cols_as_rows;

/ 

Now that the function and types are created, let’s take a look at the beautified output of some of the important dynamic performance views, v$instance, v$database, and v$instance_log_group, that DBAs use frequently. I honestly think this output is much more readable:

SQL> select * from TABLE(cols_as_rows('select * from v$instance') );

      RNUM CNAME                          VAL
---------- ------------------------------ ---------------------------------------
         1 INST_ID                        1
         2 INSTANCE_NUMBER                1
         3 INSTANCE_NAME                  SBX21C
         4 HOST_NAME                      jester.localdomain
         5 VERSION                        21.0.0.0.0
         6 VERSION_LEGACY                 21.0.0.0.0
         7 VERSION_FULL                   21.7.0.0.0
         8 STARTUP_TIME                   27-AUG-22
         9 STATUS                         OPEN
        10 PARALLEL                       NO
        11 THREAD#                        1
        12 ARCHIVER                       STOPPED
        13 LOG_SWITCH_WAIT
        14 LOGINS                         ALLOWED
        15 SHUTDOWN_PENDING               NO
        16 DATABASE_STATUS                ACTIVE
        17 INSTANCE_ROLE                  PRIMARY_INSTANCE
        18 ACTIVE_STATE                   NORMAL
        19 BLOCKED                        NO
        20 CON_ID                         0
        21 INSTANCE_MODE                  REGULAR
        22 EDITION                        EE
        23 FAMILY
        24 DATABASE_TYPE                  SINGLE

24 rows selected.

SQL> select * from TABLE(cols_as_rows('select * from v$database') );

      RNUM CNAME                          VAL
---------- ------------------------------ ---------------------------------------
         1 DBID                           501335790
         2 NAME                           SBX21C
         3 CREATED                        27-AUG-22
         4 RESETLOGS_CHANGE#              1
         5 RESETLOGS_TIME                 27-AUG-22
         6 PRIOR_RESETLOGS_CHANGE#        0
         7 PRIOR_RESETLOGS_TIME
         8 LOG_MODE                       NOARCHIVELOG
         9 CHECKPOINT_CHANGE#             2483585
        10 ARCHIVE_CHANGE#                1256845
        11 CONTROLFILE_TYPE               CURRENT
        12 CONTROLFILE_CREATED            27-AUG-22
        13 CONTROLFILE_SEQUENCE#          611
        14 CONTROLFILE_CHANGE#            2586020
        15 CONTROLFILE_TIME               27-AUG-22
        16 OPEN_RESETLOGS                 NOT ALLOWED
        17 VERSION_TIME                   27-AUG-22
        18 OPEN_MODE                      READ WRITE
        19 PROTECTION_MODE                MAXIMUM PERFORMANCE
        20 PROTECTION_LEVEL               UNPROTECTED
        21 REMOTE_ARCHIVE                 ENABLED
        22 ACTIVATION#                    501328366
        23 SWITCHOVER#                    501328366
        24 DATABASE_ROLE                  PRIMARY
        25 ARCHIVELOG_CHANGE#             0
        26 ARCHIVELOG_COMPRESSION         DISABLED
        27 SWITCHOVER_STATUS              NOT ALLOWED
        28 DATAGUARD_BROKER               DISABLED
        29 GUARD_STATUS                   NONE
        30 SUPPLEMENTAL_LOG_DATA_MIN      NO
        31 SUPPLEMENTAL_LOG_DATA_PK       NO
        32 SUPPLEMENTAL_LOG_DATA_UI       NO
        33 FORCE_LOGGING                  NO
        34 PLATFORM_ID                    13
        35 PLATFORM_NAME                  Linux x86 64-bit
        36 RECOVERY_TARGET_INCARNATION#   1
        37 LAST_OPEN_INCARNATION#         1
        38 CURRENT_SCN                    2586037
        39 FLASHBACK_ON                   NO
        40 SUPPLEMENTAL_LOG_DATA_FK       NO
        41 SUPPLEMENTAL_LOG_DATA_ALL      NO
        42 DB_UNIQUE_NAME                 SBX21C
        43 STANDBY_BECAME_PRIMARY_SCN     0
        44 FS_FAILOVER_MODE               DISABLED
        45 FS_FAILOVER_STATUS             DISABLED
        46 FS_FAILOVER_CURRENT_TARGET
        47 FS_FAILOVER_THRESHOLD          0
        48 FS_FAILOVER_OBSERVER_PRESENT
        49 FS_FAILOVER_OBSERVER_HOST
        50 CONTROLFILE_CONVERTED          NO
        51 PRIMARY_DB_UNIQUE_NAME
        52 SUPPLEMENTAL_LOG_DATA_PL       NO
        53 MIN_REQUIRED_CAPTURE_CHANGE#
        54 CDB                            YES
        55 CON_ID                         0
        56 PENDING_ROLE_CHANGE_TASKS      NOT APPLICABLE
        57 CON_DBID                       501335790
        58 FORCE_FULL_DB_CACHING          NO
        59 SUPPLEMENTAL_LOG_DATA_SR       NO
        60 GOLDENGATE_BLOCKING_MODE       DISABLED

60 rows selected.

SQL> select * from TABLE(cols_as_rows('select * from V$INSTANCE_LOG_GROUP') );

      RNUM CNAME                          VAL
---------- ------------------------------ ---------------------------------------
         1 THREAD#                        1
         2 STATUS                         OPEN
         3 ENABLED                        PUBLIC
         4 GROUPS                         3
         5 INSTANCE                       SBX21C
         6 OPEN_TIME                      27-AUG-22
         7 CURRENT_GROUP#                 1
         8 SEQUENCE#                      10
         9 CHECKPOINT_CHANGE#             2483585
        10 CHECKPOINT_TIME                27-AUG-22
        11 ENABLE_CHANGE#                 1
        12 ENABLE_TIME                    27-AUG-22
        13 DISABLE_CHANGE#                0
        14 DISABLE_TIME
        15 CON_ID                         0

15 rows selected.