{
  "date": "2014-07-18T19:59:14",
  "slug": "drilling-down-vrecoveryareausage",
  "link": "https://www.dbi-services.com/blog/drilling-down-vrecoveryareausage/",
  "title": {
    "rendered": "Drilling down V$RECOVERY_AREA_USAGE"
  },
  "content": {
    "rendered": "<h2>By Franck Pachot</h2>\n<p>.<br />\nIn a previous post I used X$KCCAGF to get more information about <a href=\"https://www.dbi-services.com/index.php/blog/entry/archivelog-deletion-policy-for-standby-database-in-oracle-data-guard\">reclaimable archived logs in FRA</a>, because there is a bug in standby (not opened) databases where archivelog deletion policy is ignored. I explained that the view V$RECOVERY_AREA_USAGE has only aggregated information about space reclaimable without the details about which files are reclaimable or not. Here I&#8217;ll explain how I came to X$KCCAGF and I&#8217;ll give the query to get all the detailed information that is hidden behind V$RECOVERY_AREA_USAGE.</p>\n<p>Here is what is exposed by V$RECOVERY_AREA_USAGE:</p>\n<pre><code>SQL&gt; set linesize 200 pagesize 1000\nSQL&gt; select * from v$recovery_area_usage;\n\nFILE_TYPE               PERCENT_SPACE_USED PERCENT_SPACE_RECLAIMABLE NUMBER_OF_FILES\n----------------------- ------------------ ------------------------- ---------------\nCONTROL FILE                           .21                         0               1\nREDO LOG                                 0                         0               0\nARCHIVED LOG                           .44                       .37              15\nBACKUP PIECE                           .37                         0               1\nIMAGE COPY                               0                         0               0\nFLASHBACK LOG                            0                         0               0\nFOREIGN ARCHIVED LOG                     0                         0               0\nAUXILIARY DATAFILE COPY                  0                         0               0\n\n8 rows selected.\n</code></pre>\n<p>and this is a good overview about space usage. But now I want to see which are those archived logs that are reclaimable and which are not. Because I want to compare with backups, standby shipping, retention, etc.</p>\n<p>Here is the information that I want:</p>\n<pre><code>FILE_TYPE    FILE_NAME                                                     BYTES REC COMPLETIO\n------------ ------------------------------------------------------------------- --- ---------\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_9_9v5cn1kv_.arc       81408 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_7_9v59wnsb_.arc      599552 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_4_9v57fdtn_.arc    10725376 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_8_9v5cd035_.arc      112640 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_11_9v5ffd57_.arc    2515968 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_12_9v5fqd0k_.arc     112640 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_13_9v5fz8z1_.arc     529408 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_14_9v5hgkqr_.arc      94208 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_5_9v598zsz_.arc     2663424 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_10_9v5cxtr4_.arc     312832 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_6_9v59lvv7_.arc      127488 YES 01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_17_9v5jcds8_.arc     126464 NO  01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_16_9v5j2968_.arc     634368 NO  01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_15_9v5hrgtv_.arc    2430976 NO  01-JUL-14\nARCHIVED LOG /fra/demo/archivelog/2014_07_01/o1_mf_1_18_9v5kny3b_.arc     190976 NO  01-JUL-14\nBACKUP PIECE /fra/demo/backupset/2014_07_18/o1_mf_annnn_TAG20140718T... 17882624 NO  18-JUL-14\nCONTROL FILE /fra/demo/controlfile/o1_mf_9v506z2f_.ctl                  10027008 NO\n\n17 rows selected.\n</code></pre>\n<p>I&#8217;ll show the query to get that, at the end of this post. But I&#8217;m also going to show you how I came to the right query, using undocumented information. The first idea was to get the V$RECOVERY_AREA_USAGE definition and see if there is any &#8216;group by&#8217; that we can get rid of. V$ views definition is exposed in V$FIXED_VIEW_DEFINITION:</p>\n<pre><code>SQL&gt; select * from v$fixed_view_definition where view_name='V$RECOVERY_AREA_USAGE';\n\nVIEW_NAME\n------------------------------\nVIEW_DEFINITION\n--------------------------------------------------------------------------------\n    CON_ID\n----------\nV$RECOVERY_AREA_USAGE\nselect fusg.file_type,\n decode(nvl2(ra.name, ra.space_limit, 0), 0, 0,\n  round(nvl(fusg.space_used, 0)/ra.space_limit, 4)                          * 10\n0),                                                            decode(nvl2(ra.na\n...\n                                    from v$archived_log,\n                                   (select /*+ no_merge */ ceilasm from x$krasga\n)                      where is_recovery_dest_file = 'YES'\n                   and name is not null) al,\n         0\n</code></pre>\n<p>but this is not enough because the view definition is limited to 4000 characters and the query is much larger than that. Note that I&#8217;ve not reproduced all the 4000 characters here.</p>\n<pre><code>SQL&gt; desc v$fixed_view_definition\n Name               Null?    Type\n ------------------ -------- ----------------\n VIEW_NAME                   VARCHAR2(30)\n VIEW_DEFINITION             VARCHAR2(4000)\n</code></pre>\n<p>So how to get the whole query? The fixed view definition is hardcoded in the oracle code. So let&#8217;s try to get it from the oracle binary. I have the beginning and I will try to find the full line from that pattern:</p>\n<pre><code>$ strings $ORACLE_HOME/bin/oracle | grep \"select fusg.file_type,\"\n</code></pre>\n<p>And bingo, I have the full query. Once again, I reproduce only the first and last lines:</p>\n<pre><code>select fusg.file_type,                                                           decode(nvl2(ra.name, ra.space_limit, 0), 0, 0,                                   \n...\nunion all                                                                select 'AUXILIARY DATAFILE COPY'        file_type,                               sum(adc.file_size)               space_used,                              sum(case when adc.purgable = 1 then adc.file_size                                  else 0 end)             space_reclaimable,                       count(*)                         number_of_files                     from (select case when ceilasm = 1 and adfcnam like '+%'                               then                                                                         ceil(((adfcnblks*adfcbsz)+1)/1048576)*1048576                          else                                                                         adfcnblks*adfcbsz                                                      end file_size,                                                            adfcrecl purgable                                                    from x$kccadfc,                                                                (select /*+ no_merge */ ceilasm from x$krasga)                      where bitand(adfcflg, 1) = 1                                                and adfcnam is not null)adc)fusg\n</code></pre>\n<p>Here we get the whole query in one line. Then I&#8217;ve just to put it in the SQLDeveloper formatter, replace the aggregate functions for PERCENT_SPACE_USED, PERCENT_SPACE_RECLAIMABLE and NUMBER_OF_FILES by the file name and size, and the &#8216;reclaimable&#8217; flag. Here is the whole query I used to get the result above:</p>\n<pre><code>set linesize 200 pagesize 1000\ncolumn file_name format a100\nSELECT file_type,\n  name file_name,\n  space_used bytes,\n  CASE\n    WHEN space_reclaimable&gt;=space_used\n    THEN 'YES'\n    ELSE 'NO'\n  END reclaimable,\n  completion_time\nFROM\n  (SELECT 'CONTROL FILE' file_type,\n    name,\n    CAST(NULL AS DATE) completion_time,\n    (\n    CASE\n      WHEN ceilasm = 1\n      AND name LIKE '+%'\n      THEN ceil(((block_size*file_size_blks)+1)/1048576)*1048576\n      ELSE block_size       *file_size_blks\n    END) space_used,\n    0 space_reclaimable,\n    1 number_of_files\n  FROM v$controlfile,\n    (SELECT /*+ no_merge */\n      ceilasm FROM x$krasga\n    )\n  WHERE is_recovery_dest_file = 'YES'\n  UNION ALL\n  SELECT 'REDO LOG' file_type,\n    member,\n    CAST(NULL AS DATE),\n    (\n    CASE\n      WHEN ceilasm = 1\n      AND member LIKE '+%'\n      THEN ceil((l.bytes+1)/1048576)*1048576\n      ELSE l.bytes\n    END) space_used,\n    0 space_reclaimable,\n    1 number_of_files\n  FROM\n    (SELECT group#, bytes FROM v$log\n    UNION\n    SELECT group#, bytes FROM v$standby_log\n    ) l,\n    v$logfile lf,\n    (SELECT /*+ no_merge */\n      ceilasm FROM x$krasga\n    )\n  WHERE l.group#               = lf.group#\n  AND lf.is_recovery_dest_file = 'YES'\n  UNION ALL\n  SELECT 'ARCHIVED LOG' file_type,\n    name,\n    completion_time,\n    (al.file_size) space_used,\n    (\n    CASE\n      WHEN dl.rectype = 11\n      THEN al.file_size\n      ELSE 0\n    END) space_reclaimable,\n    1 number_of_files\n  FROM\n    (SELECT recid,\n      name,\n      completion_time,\n      CASE\n        WHEN ceilasm = 1\n        AND name LIKE '+%'\n        THEN ceil(((blocks*block_size)+1)/1048576)*1048576\n        ELSE blocks       * block_size\n      END file_size\n    FROM v$archived_log,\n      (SELECT /*+ no_merge */\n        ceilasm FROM x$krasga\n      )\n    WHERE is_recovery_dest_file = 'YES'\n    AND name                   IS NOT NULL\n    ) al,\n    x$kccagf dl\n  WHERE al.recid    = dl.recid(+)\n  AND dl.rectype(+) = 11\n  UNION ALL\n  SELECT 'BACKUP PIECE' file_type,\n    handle,\n    completion_time,\n    (bp.file_size) space_used,\n    (\n    CASE\n      WHEN dl.rectype = 13\n      THEN bp.file_size\n      ELSE 0\n    END) space_reclaimable,\n    1 number_of_files\n  FROM\n    (SELECT recid,\n      handle,\n      completion_time,\n      CASE\n        WHEN ceilasm = 1\n        AND handle LIKE '+%'\n        THEN ceil((bytes+1)/1048576)*1048576\n        ELSE bytes\n      END file_size\n    FROM v$backup_piece,\n      (SELECT /*+ no_merge */\n        ceilasm FROM x$krasga\n      )\n    WHERE is_recovery_dest_file = 'YES'\n    AND handle                 IS NOT NULL\n    ) bp,\n    x$kccagf dl\n  WHERE bp.recid    = dl.recid(+)\n  AND dl.rectype(+) = 13\n  UNION ALL\n  SELECT 'IMAGE COPY' file_type,\n    name,\n    completion_time,\n    (dc.file_size) space_used,\n    (\n    CASE\n      WHEN dl.rectype = 16\n      THEN dc.file_size\n      ELSE 0\n    END) space_reclaimable,\n    1 number_of_files\n  FROM\n    (SELECT recid,\n      name,\n      completion_time,\n      CASE\n        WHEN ceilasm = 1\n        AND name LIKE '+%'\n        THEN ceil(((blocks*block_size)+1)/1048576)*1048576\n        ELSE blocks       * block_size\n      END file_size\n    FROM v$datafile_copy,\n      (SELECT /*+ no_merge */\n        ceilasm FROM x$krasga\n      )\n    WHERE is_recovery_dest_file = 'YES'\n    AND name                   IS NOT NULL\n    ) dc,\n    x$kccagf dl\n  WHERE dc.recid    = dl.recid(+)\n  AND dl.rectype(+) = 16\n  UNION ALL\n  SELECT 'FLASHBACK LOG' file_type,\n    name,\n    first_time,\n    NVL(fl.space_used, 0) space_used,\n    NVL(fb.reclsiz, 0) space_reclaimable,\n    NVL(fl.number_of_files, 0) number_of_files\n  FROM\n    (SELECT name,\n      first_time,\n      (\n      CASE\n        WHEN ceilasm = 1\n        AND name LIKE '+%'\n        THEN ceil((fl.bytes+1)/1048576)*1048576\n        ELSE bytes\n      END)space_used,\n      1 number_of_files\n    FROM v$flashback_database_logfile fl,\n      (SELECT /*+ no_merge */\n        ceilasm FROM x$krasga\n      )\n    ) fl,\n    (SELECT SUM(to_number(fblogreclsiz)) reclsiz FROM x$krfblog\n    )fb\n  UNION ALL\n  SELECT 'FOREIGN ARCHIVED LOG' file_type,\n    rlnam,\n    CAST(NULL AS DATE),\n    (rlr.file_size) space_used,\n    (\n    CASE\n      WHEN rlr.purgable = 1\n      THEN rlr.file_size\n      ELSE 0\n    END) space_reclaimable,\n    1 number_of_files\n  FROM\n    (SELECT rlnam,\n      CASE\n        WHEN ceilasm = 1\n        AND rlnam LIKE '+%'\n        THEN ceil(((rlbct*rlbsz)+1)/1048576)*1048576\n        ELSE rlbct       *rlbsz\n      END file_size,\n      CASE\n        WHEN bitand(rlfl2, 4096) = 4096\n        THEN 1\n        WHEN bitand(rlfl2, 8192) = 8192\n        THEN 1\n        ELSE 0\n      END purgable\n    FROM x$kccrl,\n      (SELECT /*+ no_merge */\n        ceilasm FROM x$krasga\n      )\n    WHERE bitand(rlfl2, 64) = 64\n    AND rlnam              IS NOT NULL\n    )rlr\n  UNION ALL\n  SELECT 'AUXILIARY DATAFILE COPY' file_type,\n    adfcnam,\n    CAST(NULL AS DATE),\n    (adc.file_size) space_used,\n    (\n    CASE\n      WHEN adc.purgable = 1\n      THEN adc.file_size\n      ELSE 0\n    END) space_reclaimable,\n    1 number_of_files\n  FROM\n    (SELECT adfcnam,\n      CASE\n        WHEN ceilasm = 1\n        AND adfcnam LIKE '+%'\n        THEN ceil(((adfcnblks*adfcbsz)+1)/1048576)*1048576\n        ELSE adfcnblks       *adfcbsz\n      END file_size,\n      adfcrecl purgable\n    FROM x$kccadfc,\n      (SELECT /*+ no_merge */\n        ceilasm FROM x$krasga\n      )\n    WHERE bitand(adfcflg, 1) = 1\n    AND adfcnam             IS NOT NULL\n    )adc\n  )fusg\nORDER BY completion_time nulls last;\n</code></pre>\n<p>Don&#8217;t hesitate to add more information as I did when investigating the archivelog deletion policy.</p>\n",
    "protected": false
  }
}
