An AskTom contributor brought to my attention, that direct mode insert on index organized tables now appears possible in 12c.  We can see the difference by running a simple script in both v11 and v12


SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0      Production
TNS for 64-bit Windows: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

5 rows selected.

SQL> drop table t purge;

Table dropped.

SQL> create table t(x int primary key, y int) organization index;

Table created.

SQL> insert /*+ append */ into t select 1 x, 1 y from dual;

1 row created.

SQL> select * from t;  -- no error, so no direct mode was done

         X          Y
---------- ----------
         1          1

1 row selected.


SQL> select * from v$version;

BANNER                                                                               CON_ID
-------------------------------------------------------------------------------- ----------
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production              0
PL/SQL Release 12.1.0.2.0 - Production                                                    0
CORE    12.1.0.2.0      Production                                                        0
TNS for 64-bit Windows: Version 12.1.0.2.0 - Production                                   0
NLSRTL Version 12.1.0.2.0 - Production                                                    0

5 rows selected.

SQL> drop table t purge;

Table dropped.

SQL> create table t(x int primary key, y int) organization index;

Table created.

SQL> insert /*+ append */ into t select 1 x, 1 y from dual;

1 row created.

SQL> select * from t;  -- now we do get the error, so append hint was respected
select * from t
              *
ERROR at line 1:
ORA-12838: cannot read/modify an object after modifying it in parallel

So that looks pretty cool. People may recall an older blog post of mine where it was not possible to do a large scale IOT population without a large underlying sort operation. So I thought I’d revisit that, and see what we can discover.

In this case, we are using table T_SOURCE as the source of our data. It was created simply as:


SQL> create table T_SOURCE ( n , r , constraint T_SOURCE_PK primary key( n ))
  2  organization index
  3  as select rownum, rpad(rownum,128)
  4  from dual
  5  connect by level <= 1000000
  6  /

Table created.

SQL>
SQL> exec dbms_stats.gather_table_stats('','t_source')

PL/SQL procedure successfully completed.

So we are going to copy those 1million rows from T_SOURCE to a new table, and try to avoid having to sort the rows by asking the optimizer to “walk” the source data in index order.

So let’s try direct mode first. You’ll references to a script called “mystat”, that’s simply a query to v$mystat to pick up session level statistics that might be relevant.

We’ll run these before and after to see what deltas pop out.


SQL> truncate table t_tgt;

Table truncated.

SQL> alter table T_TGT nologging;

Table altered.

SQL> @mystat
Enter value for statname: redo size

NAME                                                    VALUE
-------------------------------------------------- ----------
redo size                                              135736
redo size for lost write detection                          0
redo size for direct writes                                 0

3 rows selected.

SQL> @mystat
Enter value for statname: sorts

NAME                                                    VALUE
-------------------------------------------------- ----------
sorts (memory)                                            117
sorts (disk)                                                0
sorts (rows)                                              359

3 rows selected.

SQL> set timing on
SQL> insert /*+ APPEND */ into T_TGT select /*+ index_asc(t_source) */ * from T_SOURCE order by 1  ;

1000000 rows created.

Elapsed: 00:00:46.30

SQL> select count(*) from t_tgt where rownum < 10;
select count(*) from t_tgt where rownum < 10
                     *
ERROR at line 1:
ORA-12838: cannot read/modify an object after modifying it in parallel


SQL> commit;

Commit complete.

SQL> @mystat
Enter value for statname: redo size

NAME                                                    VALUE
-------------------------------------------------- ----------
redo size                                           497096676
redo size for lost write detection                          0
redo size for direct writes                                 0

3 rows selected.

SQL> @mystat
Enter value for statname: sorts

NAME                                                    VALUE
-------------------------------------------------- ----------
sorts (memory)                                            122
sorts (disk)                                                1
sorts (rows)                                          1000436

3 rows selected.

SQL> @mystat
Enter value for statname: direct

NAME                                                    VALUE
-------------------------------------------------- ----------
db block gets direct                                        0
consistent gets direct                                      0
physical reads direct                                   19231
physical writes direct                                  19231
physical reads direct temporary tablespace              19231
physical writes direct temporary tablespace             19231

 

So we can make the following deductions

  • Direct mode seems to have been activated, due to the ORA-12838 error.
  • I didn’t avoid the sorting, because I sorted 1,000,000 rows
  • The NOLOGGING attribute seems of no benefit here – still consumed 500megabytes of redo

So whether it was really a direct mode operation is perhaps up for debate, because all of the direct reads/writes recorded were all against temporary tablespace.

Let’s explore that last one a little.

I repeated the same population script, but before I did so, I set my workarea_size_policy to manual, and cranked up my sort_area_size to 1G.

I’ll save you all the output again, but here’s the stats output


SQL> @mystat
Enter value for statname: direct

NAME                                                    VALUE
-------------------------------------------------- ----------
db block gets direct                                        0
consistent gets direct                                      0
physical reads direct                                       0
physical writes direct                                      0
physical reads direct temporary tablespace                  0
physical writes direct temporary tablespace                 0

So…no direct operations here now. This would appear to confirm that the direct mode operations were simply sorting operations.

Now we’ll perform the same process without using the direct mode hint. We’ll set the table back to logging because we’ve seen that’s of no benefit, and use a fresh session to pick up fresh statistics


SQL> truncate table t_tgt;

Table truncated.

SQL> alter table T_TGT logging;

Table altered.

SQL> @mystat
Enter value for statname: redo size

NAME                                                    VALUE
-------------------------------------------------- ----------
redo size                                              137236
redo size for lost write detection                          0
redo size for direct writes                                 0

3 rows selected.

SQL> @mystat
Enter value for statname: sorts

NAME                                                    VALUE
-------------------------------------------------- ----------
sorts (memory)                                             21
sorts (disk)                                                0
sorts (rows)                                               86

3 rows selected.

SQL> insert into T_TGT select /*+ index_asc(t_source) */ * from T_SOURCE order by 1  ;

1000000 rows created.

Elapsed: 00:00:13.96
SQL> set timing off
SQL> select count(*) from t_tgt where rownum < 10;

  COUNT(*)
----------
         9

1 row selected.

SQL> commit;

Commit complete.

SQL> @mystat
Enter value for statname: redo size

NAME                                                    VALUE
-------------------------------------------------- ----------
redo size                                           500630220
redo size for lost write detection                          0
redo size for direct writes                                 0

3 rows selected.

SQL> @mystat
Enter value for statname: sorts

NAME                                                    VALUE
-------------------------------------------------- ----------
sorts (memory)                                             26
sorts (disk)                                                0
sorts (rows)                                              146

3 rows selected.

SQL> @mystat
Enter value for statname: direct

NAME                                                    VALUE
-------------------------------------------------- ----------
db block gets direct                                        0
consistent gets direct                                      0
physical reads direct                                       0
physical writes direct                                      0
physical reads direct temporary tablespace                  0
physical writes direct temporary tablespace                 0

So for the conventional mode we observe

  • I didn’t have to sort the rows
  • I consumed similar amount of redo
  • It was three times faster than the case where we had to so all that sorting to disk

This just goes to show, that (like everything in software), the advice of “Do ‘X’ and in every case it will be faster” is never a good thing to adhere to.

Direct mode insert is a very cool facility, but it doesn’t mean that it’s going to be the best option in every situation.

8 responses to “Direct mode operations on IOT’s”

  1. Rajeshwaran, jeyabal Avatar
    Rajeshwaran, jeyabal

    The NOLOGGING attribute seems of no benefit here – still consumed 500megabytes of redo.

    but those REDO’s were not against the index, not against the table.

  2. Hi Connor,

    I guess the nologging clause for IOTs is only effective, to reduce redo, in the CTAS.

  3. […] Connor McDonald shared Direct mode operations on IOT’s […]

  4. […] Connor McDonald shared Direct mode operations on IOT’s […]

  5. […] This post is inspired by Connor McDonald and his blog post from a year ago about direct mode operations and IOTs. You can read it here: https://connor-mcdonald.com/2016/07/04/direct-mode-operations-on-iots/amp/ […]

  6. Connor,
    Playing late catch-up thanks to today’s tweet linking to this post.

    May be the potential benefit comes from cases where there’s a lot of data already in place; or when there’s an overflow segment. For an insert when data exists, insert without sorting probably has to take the “single row update” strategy, while /*+ append */ allows for sorting and multiple changes per block in the delayed insert.

  7. […] recent (automatic ?) tweet from Connor McDonald highlighted an article he’d written a couple of years ago about an enhancement introduced in 12c that allowed for direct path inserts […]

  8. […] Lewis opens his blog by saying,”A recent tweet from Connor McDonald highlighted an article he’d written a couple of years ago about an enhancement introduced in 12c that allowed for direct path inserts […]

Got some thoughts? Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Trending

Blog at WordPress.com.