{
  "date": "2015-06-12T10:17:22",
  "slug": "can-you-have-pending-system-statistics",
  "link": "https://www.dbi-services.com/blog/can-you-have-pending-system-statistics/",
  "title": {
    "rendered": "Can you have pending system statistics?"
  },
  "content": {
    "rendered": "<h2>By Franck Pachot</h2>\n<p>.<br />\nYour system statistics seems to be wrong and you want to gather or set more relevant ones. But you don&#8217;t want to see all your application execution plans changing between nested loops and hash joins. For object statistics, we can gather statistics in a pending mode, test them in a few sessions, and publish them when we are ok with them. But for system statistics, can you do the same? It can be risky to try it, so I&#8217;ve done it for you in my lab.</p>\n<h3>Test case in 11g</h3>\n<pre><code>SQL&gt; select banner from v$version where rownum=1;\n\nBANNER\n--------------------------------------------------------------------------------\nOracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production\n\nSQL&gt; create table DEMO as\n           select rownum id , ora_hash(rownum,10) a , ora_hash(rownum,10) b , lpad('x',650,'x') c \n           from xmltable('1 to 100000');\n\nTable created.\n\n</code></pre>\n<p>Here are my system statistics:</p>\n<pre><code>SQL&gt; select '' savtime,sname,pname,pval1,pval2 from sys.aux_stats$ where pval1 is not null or pval2\nis not null order by 1,2 desc,3;\n\nSAVTIME              SNAME            PNAME           PVAL1 PVAL2\n-------------------- ---------------- ---------- ---------- --------------------\n                     SYSSTATS_MAIN    CPUSPEEDNW       2719\n                     SYSSTATS_MAIN    IOSEEKTIM          10\n                     SYSSTATS_MAIN    IOTFRSPEED       4096\n                     SYSSTATS_INFO    DSTART                06-10-2015 08:11\n                     SYSSTATS_INFO    DSTOP                 06-10-2015 08:11\n                     SYSSTATS_INFO    FLAGS               0\n                     SYSSTATS_INFO    STATUS                COMPLETED\n\n</code></pre>\n<p>I check a full table scan cost:</p>\n<pre><code>SQL&gt; set autotrace trace explain\nSQL&gt; select * from DEMO DEMO1;\n\nExecution Plan\n----------------------------------------------------------\nPlan hash value: 4000794843\n\n--------------------------------------------------------------------------\n| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |\n--------------------------------------------------------------------------\n|   0 | SELECT STATEMENT  |      | 88550 |    30M|  2752   (1)| 00:00:34 |\n|   1 |  TABLE ACCESS FULL| DEMO | 88550 |    30M|  2752   (1)| 00:00:34 |\n--------------------------------------------------------------------------\n\n</code></pre>\n<p>No surprise here. I&#8217;ve 10000 blocks in my tables, SREATDIM= IOSEEKTIM + db_block_size / IOTFRSPEED= 12 ms and MREADTIM= IOSEEKTIM + db_block_size * MBRC / IOTFRSPEED = 26 ms. Then the cost based on a MBRC of 8 is ( 26 * 10000 / 8 ) / 12 = 2700</p>\n<p>&nbsp;</p>\n<h3>Pending stats in 11g</h3>\n<p>I set &#8216;PUBLISH&#8217; to false in order to have pending statistics:</p>\n<pre><code>SQL&gt; exec dbms_stats.SET_GLOBAL_PREFS('PUBLISH', 'FALSE') ;\n\nPL/SQL procedure successfully completed.\n\n</code></pre>\n<p>Then I set some system statistics manually to simulate a fast storage:</p>\n<pre><code>17:14:38 SQL&gt; exec dbms_stats.set_system_stats('IOSEEKTIM',1);\n\nPL/SQL procedure successfully completed.\n\n17:14:38 SQL&gt; exec dbms_stats.set_system_stats('IOTFRSPEED','204800');\n\nPL/SQL procedure successfully completed.</code></pre>\n<p>and I run the same explain plan:</p>\n<pre><code>Execution Plan\n----------------------------------------------------------\nPlan hash value: 4000794843\n\n--------------------------------------------------------------------------\n| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |\n--------------------------------------------------------------------------\n|   0 | SELECT STATEMENT  |      | 88550 |    30M|  1643   (2)| 00:00:02 |\n|   1 |  TABLE ACCESS FULL| DEMO | 88550 |    30M|  1643   (2)| 00:00:02 |\n--------------------------------------------------------------------------\n\n</code></pre>\n<p>The cost is better. I&#8217;m not using pending statistics, which means that the published stats have been changed &#8211; despie the PUBLISH global preference set to FALSE:</p>\n<pre><code>SQL&gt; select '' savtime,sname,pname,pval1,pval2 from sys.aux_stats$ where pval1 is not null or pval2 i\ns not null order by 1,2 desc,3;\n\nSAVTIME              SNAME            PNAME           PVAL1 PVAL2\n-------------------- ---------------- ---------- ---------- --------------------\n                     SYSSTATS_MAIN    CPUSPEEDNW       2719\n                     SYSSTATS_MAIN    IOSEEKTIM 1\n                     SYSSTATS_MAIN    IOTFRSPEED 204800\n                     SYSSTATS_INFO    DSTART                06-10-2015 08:14\n                     SYSSTATS_INFO    DSTOP                 06-10-2015 08:14\n                     SYSSTATS_INFO    FLAGS               1\n                     SYSSTATS_INFO    STATUS                COMPLETED\n\n</code></pre>\n<p>As you see, the SYS.AUX_STATS$ show my modified values (note that the date/time did not change by the way). So be careful, when you set or gather or delete system statistics in 11g you don&#8217;t have the pending/publish mechanism. It&#8217;s the kind of change that may have a wide impact changing all your execution plans.</p>\n<p>&nbsp;</p>\n<p>With the values I&#8217;ve set the SREADTIM is near 1 ms and MREADTIM is about 1.3 ms so the cost is ( 1.3 * 10000 / 8 ) / 1 = 1625 which is roughly what has been calculated by the CBO on my new not-so-pending statistics.</p>\n<h3>12c</h3>\n<p>If you look at 12c you will see new procedures in dbms_stats which suggest that you can have pending system statistics:</p>\n<pre><code>SQL&gt; select banner from v$version where rownum=1;\n\nBANNER\n--------------------------------------------------------------------------------\nOracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production\n\nSQL&gt; select procedure_name from dba_procedures where object_name='DBMS_STATS' and procedure_name like '%PENDIN\nG_SYSTEM_STATS';\n\nPROCEDURE_NAME\n--------------------------------------------\nDELETE_PENDING_SYSTEM_STATS\nEXPORT_PENDING_SYSTEM_STATS\nPUBLISH_PENDING_SYSTEM_STATS\n</code></pre>\n<p>but be careful, they are not documented. Let&#8217;s try it anyway. I start as I did above, with a demo table and default statistics:</p>\n<pre><code>SQL&gt; select '' savtime,sname,pname,pval1,pval2 from sys.aux_stats$ where pval1 is not null or pval2 is not nul\nl order by 1,2 desc,3;\n\nSAVTIME              SNAME            PNAME           PVAL1 PVAL2\n-------------------- ---------------- ---------- ---------- --------------------\n                     SYSSTATS_MAIN    CPUSPEEDNW       2725\n                     SYSSTATS_MAIN    IOSEEKTIM          10\n                     SYSSTATS_MAIN    IOTFRSPEED       4096\n                     SYSSTATS_INFO    DSTART                06-10-2015 17:25\n                     SYSSTATS_INFO    DSTOP                 06-10-2015 17:25\n                     SYSSTATS_INFO    FLAGS               0\n                     SYSSTATS_INFO    STATUS                COMPLETED\n\nSQL&gt; set autotrace trace explain\nSQL&gt; select * from DEMO DEMO1;\n\nExecution Plan\n----------------------------------------------------------\nPlan hash value: 4000794843\n\n--------------------------------------------------------------------------\n| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |\n--------------------------------------------------------------------------\n|   0 | SELECT STATEMENT  |      | 80500 |    28M|  2752   (1)| 00:00:01 |\n|   1 |  TABLE ACCESS FULL| DEMO | 80500 |    28M|  2752   (1)| 00:00:01 |\n--------------------------------------------------------------------------\n\n</code></pre>\n<p>I set PUBLISH to false and set manual system stats:</p>\n<pre><code>SQL&gt; exec dbms_stats.SET_GLOBAL_PREFS('PUBLISH', 'FALSE') ;\n\nPL/SQL procedure successfully completed.\n\nSQL&gt; exec dbms_stats.set_system_stats('IOSEEKTIM',1);\n\nPL/SQL procedure successfully completed.\n\nSQL&gt; exec dbms_stats.set_system_stats('IOTFRSPEED','204800');\n\nPL/SQL procedure successfully completed.\n\n</code></pre>\n<p>and I check the SYS.AUX_STATS$ table:</p>\n<pre><code>SQL&gt; select '' savtime,sname,pname,pval1,pval2 from sys.aux_stats$ where pval1 is not null or pval2 is not nul\nl order by 1,2 desc,3;\n\nSAVTIME              SNAME            PNAME           PVAL1 PVAL2\n-------------------- ---------------- ---------- ---------- --------------------\n                     SYSSTATS_MAIN    CPUSPEEDNW       2725\n                     SYSSTATS_MAIN    IOSEEKTIM          10\n                     SYSSTATS_MAIN    IOTFRSPEED       4096\n                     SYSSTATS_INFO    DSTART                06-10-2015 17:25\n                     SYSSTATS_INFO    DSTOP                 06-10-2015 17:25\n                     SYSSTATS_INFO    FLAGS               0\n                     SYSSTATS_INFO    STATUS                COMPLETED\n\n</code></pre>\n<p>Good ! I still have the previous values here. The new stats have not been published.</p>\n<p>&nbsp;</p>\n<p>The pending stats are stored in the history table, with a date in the future:</p>\n<pre><code>SQL&gt; select savtime,sname,pname,pval1,pval2 from sys.wri$_optstat_aux_history where pval1 is not null or pval2\n is not null and savtime&gt;sysdate-30/24/60/60 order by 1,2 desc,3;\n\nSAVTIME              SNAME            PNAME           PVAL1 PVAL2\n-------------------- ---------------- ---------- ---------- --------------------\n01-dec-3000 01:00:00 SYSSTATS_MAIN    CPUSPEEDNW       2725\n01-dec-3000 01:00:00 SYSSTATS_MAIN IOSEEKTIM 10\n01-dec-3000 01:00:00 SYSSTATS_MAIN IOTFRSPEED 204800\n01-dec-3000 01:00:00 SYSSTATS_INFO    DSTART                06-10-2015 17:29\n01-dec-3000 01:00:00 SYSSTATS_INFO    DSTOP                 06-10-2015 17:29\n01-dec-3000 01:00:00 SYSSTATS_INFO    FLAGS               1\n01-dec-3000 01:00:00 SYSSTATS_INFO    STATUS                COMPLETED\n\n</code></pre>\n<p>That&#8217;s perfect. It seems that I can gather system statistics without publishing them. And I don&#8217;t care about the Y3K bug yet.</p>\n<p>&nbsp;</p>\n<h3>12c use pending stats = true</h3>\n<p>First, I&#8217;ll check that a session can use the pending stats if chosen explicitly:</p>\n<pre><code>SQL&gt; alter session set optimizer_use_pending_statistics=true;\n\nSession altered.\n\n</code></pre>\n<p>the I run the query:</p>\n<pre><code>SQL&gt; set autotrace trace explain\nSQL&gt; select * from DEMO DEMO2;\n\nExecution Plan\n----------------------------------------------------------\nPlan hash value: 4000794843\n\n--------------------------------------------------------------------------\n| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |\n--------------------------------------------------------------------------\n|   0 | SELECT STATEMENT  |      | 80500 |    28M|  1308   (1)| 00:00:01 |\n|   1 |  TABLE ACCESS FULL| DEMO | 80500 |    28M|  1308   (1)| 00:00:01 |\n--------------------------------------------------------------------------\n\n</code></pre>\n<p>Cost is lower. This is exacly what I expected with my new &#8211; unpublished &#8211; statistics. Good. I don&#8217;t know what it&#8217;s lower than in 11g. Maybe the formula has changed. This is another place for comments 😉</p>\n<p>&nbsp;</p>\n<h3>12c use pending stats = false</h3>\n<p>Ok I checked that the published statistics are the same as before, but let&#8217;s try to use them:</p>\n<pre><code>SQL&gt; alter session set optimizer_use_pending_statistics=false;\n\nSession altered.\n\n</code></pre>\n<p>and once again run the same query:</p>\n<pre><code>SQL&gt; set autotrace trace explain\n\nSQL&gt; select * from DEMO DEMO3;\n\nExecution Plan\n----------------------------------------------------------\nPlan hash value: 4000794843\n\n----------------------------------------------------------\n| Id  | Operation         | Name | Rows  | Bytes | Cost  |\n----------------------------------------------------------\n|   0 | SELECT STATEMENT  |      | 80500 |    28M|  1541 |\n|   1 |  TABLE ACCESS FULL| DEMO | 80500 |    28M|  1541 |\n----------------------------------------------------------\n\nNote\n-----\n   - cpu costing is off (consider enabling it)\n\n</code></pre>\n<p>Oh. There is a problem here. &#8216;cpu costing is off&#8217; means that there are no system statistics. The cost has been calculated as it were in old versions whithout system statistics. This is bad. I have gathered pending statistics, not published, but all sessions have their costing changed now.</p>\n<p>&nbsp;</p>\n<h3>10053</h3>\n<p>Just a look at the 10053 trace show that I have a problem:</p>\n<pre><code>-----------------------------\nSYSTEM STATISTICS INFORMATION\n-----------------------------\nSystem Stats are INVALID.\n...\n  Table: DEMO  Alias: DEMO3\n    Card: Original: 80500.000000  Rounded: 80500  Computed: 80500.000000  Non Adjusted: 80500.000000\n  Scan IO  Cost (Disk) =   1541.000000\n  Scan CPU Cost (Disk) =   0.000000\n  Total Scan IO  Cost  =   1541.000000 (scan (Disk))\n                       =   1541.000000\n  Total Scan CPU  Cost =   0.000000 (scan (Disk))\n                       =   0.000000\n  Access Path: TableScan\n    Cost:  1541.000000  Resp: 1541.000000  Degree: 0\n      Cost_io: 1541.000000  Cost_cpu: 0\n      Resp_io: 1541.000000  Resp_cpu: 0\n  Best:: AccessPath: TableScan\n         Cost: 1541.000000  Degree: 1  Resp: 1541.000000  Card: 80500.000000  Bytes: 0.000000\n\n</code></pre>\n<p>It seems that with pending statistics the optimizer can&#8217;t simply get the published values, and falls back as if there were no system statistics. This is a bug obviously. I&#8217;ve not used the undocumented new functions. They were used in the background, but it&#8217;s totally supported to set PUBLISH to FALSE and the gather system statistics. The behavior should be either the same as in 11g &#8211; publishing the gathered stats &#8211; or gathering into pending stats only and session continue to use the published ones by default.</p>\n<p>&nbsp;</p>\n<h3>Conclusion</h3>\n<p>In 11g, be careful, system statistic changes are always published.</p>\n<p>In 12c, don&#8217;t gather system statistics when PUBLISH is set to false. We can expect that nice new feature in further versions, but for the moment it messes up everything. I&#8217;ll not open an SR yet but hope it&#8217;ll be fixed in future versions.</p>\n<h3>update</h3>\n<p>Further investigations done by Stefan Koehler on this twitter conversation:</p>\n<blockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\">\n<p lang=\"en\" dir=\"ltr\">My latest blog post is about pending system statistics. <a href=\"https://t.co/yJ0NSfmS6g\">https://t.co/yJ0NSfmS6g</a></p>\n<p>&mdash; Franck Pachot (@FranckPachot) <a href=\"https://twitter.com/FranckPachot/status/608727297672228864?ref_src=twsrc%5Etfw\">June 10, 2015</a></p></blockquote>\n<p><script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script></p>\n<p>&nbsp;</p>\n",
    "protected": false
  }
}
