{
  "date": "2017-09-05T19:21:23",
  "slug": "12c-dbms_stats-gather_table_stats-on-gtt-do-not-commit",
  "link": "https://www.dbi-services.com/blog/12c-dbms_stats-gather_table_stats-on-gtt-do-not-commit/",
  "title": {
    "rendered": "12c dbms_stats.gather_table_stats on GTT do not commit"
  },
  "content": {
    "rendered": "<h2>By Franck Pachot</h2>\n<p>.<br />\nIn my UKOUG OracleScene <a href=\"http://viewer.zmags.com/publication/07edc028#/07edc028/46\" target=\"_blank\" rel=\"noopener noreferrer\">article</a> on 12<em>c</em> online statistics and GTT I mentioned the following:</p>\n<p><em>A final note about those 12c changes in statistics gathering on GTT. In 11g the dbms_stats did a commit at the start. So if you did gather stats after the load, you had to set the GTT as ON COMMIT PRESERVE ROWS. Or you just vacuum what you’ve loaded. That has changed in 12c. If you now choose to do a conventional insert followed by dbms_stats (having set private stats of course) then you don’t need to set on commit preserve rows anymore.</em></p>\n<p>Today, I realized that I&#8217;ve never explained exactly when dbms_stats.gather_table_stats commits the transaction or not. Because, of course, it depends. In summary: 12<em>c</em> non-SYS owner GTT with private statistics.<br />\n<!--more--></p>\n<p>Here is an example. I connect as non-SYS user:</p>\n<pre><code>\nSQL&gt; connect demo/demo@//localhost/pdb1\nConnected.\nSQL&gt; show user\nUSER is \"DEMO\"\n</code></pre>\n<p>I create a permanent table and a global temporary table:</p>\n<pre><code>\nSQL&gt; create table DEMO(text varchar2(20));\nTable created.\n&nbsp;\nSQL&gt; create global temporary table DEMOGTT(text varchar2(20));\nTable created.\n</code></pre>\n<p>In the permanent table, I insert my row. The goal is to be sure that this insert is not commited and can be rolled back at the end:</p>\n<pre><code>\nSQL&gt; insert into DEMO values('Forget me, please!');\n1 row created.\n</code></pre>\n<p>In the global temporary table I insert one row. The goal is to be sure that the row remains until the end of my transaction (on commit delete rows):</p>\n<pre><code>\nSQL&gt; insert into DEMOGTT values('Preserve me, please!');\n1 row created.\n</code></pre>\n<p>Here it is:</p>\n<pre><code>\nSQL&gt; select * from DEMO;\n&nbsp;\nTEXT\n--------------------\nForget me, please!\n&nbsp;\nSQL&gt; select * from DEMOGTT;\n&nbsp;\nTEXT\n--------------------\nPreserve me, please!\n</code></pre>\n<p>Then, I gather statistics on the GTT:</p>\n<pre><code>\nSQL&gt; exec dbms_stats.gather_table_stats(user,'DEMOGTT');\nPL/SQL procedure successfully completed.\n</code></pre>\n<p>I check that my rows in the GTT are still there, which is a proof that no commit happened:</p>\n<pre><code>\nSQL&gt; select * from DEMOGTT;\n&nbsp;\nTEXT\n--------------------\nPreserve me, please!\n</code></pre>\n<p>And I check that, as no commit happened, I can rollback my previous insert on the permanent table:</p>\n<pre><code>\nSQL&gt; rollback;\nRollback complete.\n&nbsp;\nSQL&gt; select * from DEMO;\nno rows selected\n</code></pre>\n<p>This is the new behavior in 12<i>c</i>. The same in 11<i>g</i> would have committed my transaction before and after the call to dbms_stats.</p>\n<h3>GTT only</h3>\n<p>Here is the same example when gathering the stats on the permanent table:</p>\n<pre><code>SQL&gt; show user\nUSER is \"DEMO\"\nSQL&gt; exec dbms_stats.gather_table_stats(user,'DEMO');\nPL/SQL procedure successfully completed.\n&amp;nbsp:\nSQL&gt; select * from DEMOGTT;\nno rows selected\n&amp;nbsp:\nSQL&gt; rollback;\nRollback complete.\n&amp;nbsp:\nSQL&gt; select * from DEMO;\n&amp;nbsp:\nTEXT\n--------------------\nForget me, please!\n</code></pre>\n<p>The transaction was committed by dbms_stats here: no rows from GTT (on commit delete rows), and the insert in permanent table was commited before my rollback.</p>\n<h3>Not for SYS</h3>\n<p>When connected as SYS:</p>\n<pre><code>SQL&gt; show user\nUSER is \"SYS\"\nSQL&gt; exec dbms_stats.gather_table_stats(user,'DEMOGTT');\nPL/SQL procedure successfully completed.\n&nbsp;\nSQL&gt; select * from DEMOGTT;\nno rows selected\n&nbsp;\nSQL&gt; rollback;\nRollback complete.\n&nbsp;\nSQL&gt; select * from DEMO;\n&nbsp;\nTEXT\n--------------------\nForget me, please!\n</code></pre>\n<p>The transaction was committed by dbms_stats here: when the table is owned by SYS, dbms_stats commits.</p>\n<h3>I mean, not for SYS owner</h3>\n<p>If I&#8217;m connected by SYS but gather stats on a non-SYS table, dbms_stats do not commit:</p>\n<pre><code>\nSQL&gt; show user\nUSER is \"SYS\"\nSQL&gt; exec dbms_stats.gather_table_stats('DEMO','DEMOGTT');\nPL/SQL procedure successfully completed.\n&nbsp;\nSQL&gt; select * from DEMOGTT;\n&nbsp;\nTEXT\n--------------------\nPreserve me, please!\n&nbsp;\nSQL&gt; rollback;\nRollback complete.\n&nbsp;\nSQL&gt; select * from DEMO;\nno rows selected\n</code></pre>\n<p>The behaviour is not related to the user who runs dbms_stats, but the owner of the GTT.</p>\n<h3>Private statistics only</h3>\n<p>The default in 12<i>c</i> for GTT is private statistics, visible to session only. Trying the same with shared statistics (as in 11<i>g</i>):</p>\n<pre><code>SQL&gt; show user\nUSER is \"DEMO\"\n&nbsp;\nSQL&gt; select dbms_stats.get_prefs(ownname=&gt;user,tabname=&gt;'DEMO_GTT',pname=&gt;'GLOBAL_TEMP_TABLE_STATS') from dual;\n&nbsp;\nDBMS_STATS.GET_PREFS(OWNNAME=&gt;USER,TABNAME=&gt;'DEMO_GTT',PNAME=&gt;'GLOBAL_TEMP_TABLE\n--------------------------------------------------------------------------------\nSESSION\n&nbsp;\nSQL&gt; exec dbms_stats.set_table_prefs(user,'DEMO_GTT','GLOBAL_TEMP_TABLE_STATS','SHARED' );\nPL/SQL procedure successfully completed.\n&nbsp;\nSQL&gt; exec dbms_stats.gather_table_stats(user,'DEMOGTT');\nPL/SQL procedure successfully completed.\n&amp;nbsp:\nSQL&gt; select * from DEMOGTT;\nno rows selected\n&amp;nbsp:\nSQL&gt; rollback;\nRollback complete.\n&amp;nbsp:\nSQL&gt; select * from DEMO;\n&amp;nbsp:\nTEXT\n--------------------\nForget me, please!\n&nbsp;\nSQL&gt; exec dbms_stats.set_table_prefs(user,'DEMO_GTT', 'GLOBAL_TEMP_TABLE_STATS',null);\nPL/SQL procedure successfully completed.\n</code></pre>\n<p>The dbms_stats did commit my transaction here.</p>\n<h3>So what?</h3>\n<p>Private session statistics for GTT is a great feature. Use it: gather statistics after filling the GTT. And don&#8217;t worry about on commit delete rows GTT (the default) because this statistic gathering do not commit the transation.</p>\n",
    "protected": false
  }
}
