Before 11g virtual columns where created when you created a function based index
They were also hidden. On virtual columns statistics can be created witch is usefull but
you had to create an index for it.
As of 11g you can define virtual columns and are visible in the table definition.
SQL>create table aap as select rownum a1,
'AHH' a2
FROM DUAL CONNECT BY LEVEL <= 100000;
SQL>CREATE INDEX aap_i ON aap(a2);
SQL> insert into aap values(100001,'GIN');
1 row created.
SQL> insert into aap values(100002,'Gin');
1 row created.
SQL> insert into aap values(100003,'GiN');
1 row created.
SQL> commit;
SQL>begin
dbms_stats.gather_table_stats(ownname=>'GDA001',
tabname=> 'AAP',
cascade=> true,
estimate_percent=>null,
method_opt=> 'FOR ALL COLUMNS SIZE 1');
end;
/
SQL> SELECT * FROM AAP WHERE UPPER(a2)='GIN';
A1 A2
---------- ---
100001 GIN
100002 Gin
100003 GiN
Execution Plan
----------------------------------------------------------
Plan hash value: 3829027638
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 9000 | 54 (6)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| AAP | 1000 | 9000 | 54 (6)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(UPPER("A2")='GIN')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
216 consistent gets
0 physical reads
0 redo size
664 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed
As you see the index is not used because of the UPPER function.
Let create the function based index.
SQL> create index f_aap_a2_i on aap(UPPER(a2)) compute statistics;
Index created.
A1 A2
---------- ---
100001 GIN
100002 Gin
100003 GiN
Execution Plan
----------------------------------------------------------
Plan hash value: 2746435280
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 9000 | 50 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| AAP | 1000 | 9000 | 50 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | F_AAP_A2_I | 400 | | 105 (0)| 00:00:02 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(UPPER("A2")='GIN')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
5 consistent gets
0 physical reads
0 redo size
664 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed
As you see the index is now used.
SQL> select table_name, column_name, num_distinct,
density, virtual_column, hidden_column
from dba_tab_cols
where table_name = 'AAP';
TABLE COLUMN_NAME NUM_DISTINCT DENSITY VIR HID
----- --------------- ------------ ---------- --- ---
AAP SYS_NC00003$ 2 .5 NO NO
AAP A2 4 .25 NO NO
AAP A1 100003 9.9997E-06 NO NO
As you see there is a virtual column that is hidden.
and no statistics also
SQL> begin
dbms_stats.gather_table_stats(ownname=>'GDA001',
tabname=> 'AAP',
cascade=> true,
estimate_percent=>null,
method_opt=> 'FOR ALL HIDDEN COLUMNS SIZE 3');
end;
/
SQL> select table_name, column_name, num_distinct,
density, virtual_column, hidden_column
from dba_tab_cols
where table_name = 'AAP';
TABLE COLUMN_NAME NUM_DISTINCT DENSITY VIR HID
----- --------------- ------------ ---------- --- ---
AAP SYS_NC00003$ 2 .5 YES YES
AAP A2 4 .25 NO NO
AAP A1 100003 9.9997E-06 NO NO
The virtual statistics are now in place.
Lets run the statement again
SQL> SELECT * FROM AAP WHERE UPPER(a2)='GIN';
A1 A2
---------- ---
100001 GIN
100002 Gin
100003 GiN
Execution Plan
----------------------------------------------------------
Plan hash value: 2746435280
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 39 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| AAP | 3 | 39 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | F_AAP_A2_I | 3 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(UPPER("A2")='GIN')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
5 consistent gets
0 physical reads
0 redo size
664 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed
Al you now see also the statiscts are now much more accurate. there are 100000 rows with AHH and only
3 with GIN. The rows are now 3 before that is was 100000 and with the index 400.
Now the above was the method before 11g.
This is how you can do it in 11g
SQL> drop index F_AAP_A2_I;
Index dropped.
SQL> alter table aap add (upper_naam as (UPPER(a2)));
Table altered.
SQL>begin
dbms_stats.gather_table_stats(ownname=>'GDA001',
tabname=> 'AAP',
cascade=> true,
estimate_percent=>null,
method_opt=> 'FOR ALL COLUMNS SIZE 1');
end;
/
SQL> select table_name, column_name, num_distinct,
density, virtual_column, hidden_column
from dba_tab_cols
where table_name = 'AAP';
TABLE COLUMN_NAME NUM_DISTINCT DENSITY VIR HID
----- --------------- ------------ ---------- --- ---
AAP UPPER_NAAM 2 .5 YES NO
AAP A2 4 .25 NO NO
AAP A1 100003 9.9997E-06 NO NO
As you see the virtual column upper_naam is not hidding more.
SQL> select table_name, column_name
from dba_tab_columns
where table_name = 'AAP';
TABLE COLUMN_NAME
----- ---------------
AAP A1
AAP A2
AAP UPPER_NAAM
SQL> SELECT * FROM AAP WHERE UPPER(a2)='GIN';
A1 A2 UPP
---------- --- ---
100001 GIN GIN
100002 Gin GIN
100003 GiN GIN
Execution Plan
----------------------------------------------------------
Plan hash value: 3829027638
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50002 | 634K| 56(9)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| AAP | 50002 | 634K| 56 (9)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("AAP"."UPPER_NAAM"='GIN')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
216 consistent gets
0 physical reads
0 redo size
744 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed
SQL> create index upper_naam_i on aap(upper(a2));
create index upper_naam_i on aap(upper(upper(a2))
*
ERROR at line 1:
ORA-54018: A virtual column exists for this expression
So you can't create the index because there is virtual column
SQL> create index upper_naam_i on aap(upper_naam);
Index created.
But we can create a normal index on the virtual column
SQL> SELECT index_name, index_type FROM user_indexes WHERE index_name='UPPER_NAAM_I';
INDEX_NAME INDEX_TYPE
------------------------------ ---------------------------
UPPER_NAAM_I FUNCTION-BASED NORMAL
As you see the index type is function based
SQL> SELECT index_name, column_expression
FROM user_ind_expressions
WHERE index_name = 'UPPER_NAAM_I';
INDEX_NAME COLUMN_EXP
------------------------------ ----------
UPPER_NAAM_I UPPER("A2")
SQL> select * from aap where upper_naam = 'GIN';
A1 A2 UPP
---------- --- ---
100001 GIN GIN
100002 Gin GIN
100003 GiN GIN
Execution Plan
----------------------------------------------------------
Plan hash value: 2505477614
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 39 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| AAP | 3 | 39 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | UPPER_NAAM_I | 3 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("UPPER_NAAM"='GIN')
Statistics
----------------------------------------------------------
28 recursive calls
144 db block gets
28 consistent gets
0 physical reads
0 redo size
744 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
3 rows processed
And there is the index on the virtual column
Thats it
Wednesday, August 1, 2012
IGNORE_ROW_ON_DUPKEY_INDEX HINT
In oracle 11gr2 there is a new hint call IGNORE_ROW_ON_DUPKEY_INDEX.
It does wat it says ignore duplicate rows violation.
SQL> create table aap(id number constraint aap_pk_idx primary key
using index(create index aap_pk_idx on aap(id)), a1 varchar2(3));
Table created.
SQL> insert into aap select rownum, 'AHH' from dual connect by level <= 10;
10 rows created.
SQL> commit;
Commit complete
SQL> insert into aap select rownum, 'AHH' from dual connect by level <= 12;
insert into aap select rownum, 'AHH' from dual connect by level <= 12
*
ERROR at line 1:
ORA-00001: unique constraint (GDA001.AAP_PK_IDX) violated
Oke now that is what was expected. Lets use the hint.
SQL>insert /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
into aap select rownum, 'AHH'
from dual connect by level <= 12;
into aap select rownum, 'AHH'
*
ERROR at line 2:
ORA-38913: Index specified in the index hint is invalid
Why doesn't the hint gives this messages Well
SQL> select index_name, uniqueness, table_name
from dba_indexes
where index_name='AAP_PK_IDX';
INDEX_NAME UNIQUENES TABLE_NAME
------------------------------ --------- ------------------------------
AAP_PK_IDX NONUNIQUE AAP
The index in non unique and for the hint to work is has to be.
SQL>create table aap(id number constraint aap_pk_idx primary key
using index(create unique index aap_pk_idx on aap(id)), a1 varchar2(3));
.table created
SQL> select index_name, uniqueness, table_name
from dba_indexes
where index_name='AAP_PK_IDX';
INDEX_NAME UNIQUENES TABLE_NAME
------------------------------ --------- ------------------------------
AAP_PK_IDX UNIQUE AAP
SQL> insert into aap select rownum, 'AHH' from dual connect by level <= 10;
SQL commit;
SQL> insert /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
into aap select rownum, 'AHH'
from dual connect by level <= 12;
2 rows created.
So with this hint duplicate are ignored.
SQL> select * from aap;
ID A1
---------- ---
1 AHH
2 AHH
3 AHH
4 AHH
5 AHH
6 AHH
7 AHH
8 AHH
9 AHH
10 AHH
11 AHH
ID A1
---------- ---
12 AHH
12 rows selected.
And there is 1 thing. The hint doesn't work with the update statement.
SQL> update /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
aap set id = 13 where id = 5;
update /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
*
ERROR at line 1:
ORA-38917: IGNORE_ROW_ON_DUPKEY_INDEX hint disallowed for this operation
Thats it.
It does wat it says ignore duplicate rows violation.
SQL> create table aap(id number constraint aap_pk_idx primary key
using index(create index aap_pk_idx on aap(id)), a1 varchar2(3));
Table created.
SQL> insert into aap select rownum, 'AHH' from dual connect by level <= 10;
10 rows created.
SQL> commit;
Commit complete
SQL> insert into aap select rownum, 'AHH' from dual connect by level <= 12;
insert into aap select rownum, 'AHH' from dual connect by level <= 12
*
ERROR at line 1:
ORA-00001: unique constraint (GDA001.AAP_PK_IDX) violated
Oke now that is what was expected. Lets use the hint.
SQL>insert /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
into aap select rownum, 'AHH'
from dual connect by level <= 12;
into aap select rownum, 'AHH'
*
ERROR at line 2:
ORA-38913: Index specified in the index hint is invalid
Why doesn't the hint gives this messages Well
SQL> select index_name, uniqueness, table_name
from dba_indexes
where index_name='AAP_PK_IDX';
INDEX_NAME UNIQUENES TABLE_NAME
------------------------------ --------- ------------------------------
AAP_PK_IDX NONUNIQUE AAP
The index in non unique and for the hint to work is has to be.
SQL>create table aap(id number constraint aap_pk_idx primary key
using index(create unique index aap_pk_idx on aap(id)), a1 varchar2(3));
.table created
SQL> select index_name, uniqueness, table_name
from dba_indexes
where index_name='AAP_PK_IDX';
INDEX_NAME UNIQUENES TABLE_NAME
------------------------------ --------- ------------------------------
AAP_PK_IDX UNIQUE AAP
SQL> insert into aap select rownum, 'AHH' from dual connect by level <= 10;
SQL commit;
SQL> insert /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
into aap select rownum, 'AHH'
from dual connect by level <= 12;
2 rows created.
So with this hint duplicate are ignored.
SQL> select * from aap;
ID A1
---------- ---
1 AHH
2 AHH
3 AHH
4 AHH
5 AHH
6 AHH
7 AHH
8 AHH
9 AHH
10 AHH
11 AHH
ID A1
---------- ---
12 AHH
12 rows selected.
And there is 1 thing. The hint doesn't work with the update statement.
SQL> update /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
aap set id = 13 where id = 5;
update /*+ ignore_row_on_dupkey_index(aap,aap_pk_idx) */
*
ERROR at line 1:
ORA-38917: IGNORE_ROW_ON_DUPKEY_INDEX hint disallowed for this operation
Thats it.
On demand segments Oracle 11gr2
Before 11gr2 when you created a table, index and so on there was ALWAYS allocated 1 initail extent
Example
SQL> create table aap (a number, a2 varchar2(100))
storage (initial 10m) tablespace users;
Table created.
SQL> select blocks, bytes/1024/1024, segment_name,
segment_type
from dba_segments
where segment_name = 'AAP';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
-------- --------------- ------------------- ----------------
1280 10 AAP TABLE
You see there is 1 segment from 10Mb
Now the same but now in Oracle 11gr2
SQL> create table aap (a number, a2 varchar2(100))
storage (initial 10m) tablespace users;
Table created.
SQL> select blocks, bytes/1024/1024, segment_name, segment_type
from dba_segments where segment_name = 'AAP';
no rows selected
As you see no initial extent is created.Only when you insert 1 or more rows the first extent is created.
SQL> insert into aap values (1234,'AAP');
1 row created.
SQL> select blocks, bytes/1024/1024, segment_name, segment_type from dba_segments where segment_name = 'AAP';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
------- - ------------- ---------------------- --------------
1280 10 AAP TABLE
As you see when the first row is inserted then then the fist extent is created.
It als means that the if you have an index on the table this also get its first extent.
So there is a slide overhead when the first rows are inserted.
SQL> create table noaap (a number, a2 varchar2(100))
storage (initial 10m) tablespace users; 2
Table created.
SQL> create index noaap_1 on noaap(a);
Index created.
SQL> create index noaap_2 on noaap(a2);
Index created.
SQL> select blocks, bytes/1024/1024, segment_name,
segment_type
from dba_segments
where segment_name like'NOAAP%';
no rows selected
SQL> insert into noaap values (1234,'AAP');
1 row created.
SQL> select blocks, bytes/1024/1024, segment_name,
segment_type
from dba_segments
where segment_name like'NOAAP%';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
---------- --------------- --------------- ---------------
8 .0625 NOAAP_2 INDEX
1280 10 NOAAP TABLE
8 .0625 NOAAP_1 INDEX
Now what is the advantage.
large applications can created a lot of segments that are not used.(SAP is one of those one's).
Tables can have many indexes that may never be used. Which can result in wasted storage.
If you don't want this then set the following parameter on false
SQL> alter system set deferred_segment_creation = FALSE;
Now does this mean when you truncate the table you don't have any extent anymore.
SQL> truncate table aap;
SQL> select blocks, bytes/1024/1024, segment_name, segment_type
from dba_segments where segment_name = 'AAP';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
------- - ------------- ---------------------- --------------
1280 10 AAP TABLE
The answer is no. The initial extent is kept.
That it
Example
SQL> create table aap (a number, a2 varchar2(100))
storage (initial 10m) tablespace users;
Table created.
SQL> select blocks, bytes/1024/1024, segment_name,
segment_type
from dba_segments
where segment_name = 'AAP';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
-------- --------------- ------------------- ----------------
1280 10 AAP TABLE
You see there is 1 segment from 10Mb
Now the same but now in Oracle 11gr2
SQL> create table aap (a number, a2 varchar2(100))
storage (initial 10m) tablespace users;
Table created.
SQL> select blocks, bytes/1024/1024, segment_name, segment_type
from dba_segments where segment_name = 'AAP';
no rows selected
As you see no initial extent is created.Only when you insert 1 or more rows the first extent is created.
SQL> insert into aap values (1234,'AAP');
1 row created.
SQL> select blocks, bytes/1024/1024, segment_name, segment_type from dba_segments where segment_name = 'AAP';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
------- - ------------- ---------------------- --------------
1280 10 AAP TABLE
As you see when the first row is inserted then then the fist extent is created.
It als means that the if you have an index on the table this also get its first extent.
So there is a slide overhead when the first rows are inserted.
SQL> create table noaap (a number, a2 varchar2(100))
storage (initial 10m) tablespace users; 2
Table created.
SQL> create index noaap_1 on noaap(a);
Index created.
SQL> create index noaap_2 on noaap(a2);
Index created.
SQL> select blocks, bytes/1024/1024, segment_name,
segment_type
from dba_segments
where segment_name like'NOAAP%';
no rows selected
SQL> insert into noaap values (1234,'AAP');
1 row created.
SQL> select blocks, bytes/1024/1024, segment_name,
segment_type
from dba_segments
where segment_name like'NOAAP%';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
---------- --------------- --------------- ---------------
8 .0625 NOAAP_2 INDEX
1280 10 NOAAP TABLE
8 .0625 NOAAP_1 INDEX
Now what is the advantage.
large applications can created a lot of segments that are not used.(SAP is one of those one's).
Tables can have many indexes that may never be used. Which can result in wasted storage.
If you don't want this then set the following parameter on false
SQL> alter system set deferred_segment_creation = FALSE;
Now does this mean when you truncate the table you don't have any extent anymore.
SQL> truncate table aap;
SQL> select blocks, bytes/1024/1024, segment_name, segment_type
from dba_segments where segment_name = 'AAP';
BLOCKS BYTES/1024/1024 SEGMENT_NAME SEGMENT_TYPE
------- - ------------- ---------------------- --------------
1280 10 AAP TABLE
The answer is no. The initial extent is kept.
That it
Subscribe to:
Posts (Atom)