Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Daniel.

Asked: April 18, 2014 - 2:59 pm UTC

Last updated: April 23, 2014 - 9:50 pm UTC

Version: 11.2.0

Viewed 10K+ times! This question is

You Asked

Hi Tom.

I have a table with following definition:

SQL> desc OAUTH2_REFRESH_TOKEN
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL RAW(16)
TOKEN_ID VARCHAR2(255 CHAR)
TOKEN BLOB
AUTHENTICATION BLOB

ID is a primary key.

Looks like there are many deletes on this table using ID. I've noticed that they are are doing a lot of consistent gets.

DELETE
FROM OAUTH2_REFRESH_TOKEN
WHERE "ID"= '8A81B295444C2881014452803709648E'SQL> 2 3
4
SQL> /

1 row deleted.


Execution Plan
----------------------------------------------------------
Plan hash value: 2420547146

--------------------------------------------------------------------------------
---------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| T
ime |

--------------------------------------------------------------------------------
---------

| 0 | DELETE STATEMENT | | 1 | 50 | 10377 (1)| 0
0:02:05 |

| 1 | DELETE | OAUTH2_REFRESH_TOKEN | | | |
|

|* 2 | INDEX FULL SCAN| SYS_C00203982 | 1 | 50 | 10377 (1)| 0
0:02:05 |

--------------------------------------------------------------------------------
---------


Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter(RAWTOHEX("ID")='8A81B295444C2881014452803709648E')


Statistics
----------------------------------------------------------
0 recursive calls
10 db block gets
10592 consistent gets
0 physical reads
3548 redo size
833 bytes sent via SQL*Net to client
846 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
1 rows processed


I rebuilt PK index and the size of it went from 88MB to 10MB. Number of GETS also decreased.
Before:
SQL> select bytes/1024/1024 from dba_segments where segment_name = 'SYS_C00203982';

BYTES/1024/1024
---------------
88


After:
SQL> select bytes/1024/1024 from dba_segments where segment_name = 'SYS_C00203982';

BYTES/1024/1024
---------------
10


DELETE
FROM dice."OAUTH2_REFRESH_TOKEN"
WHERE "ID"= '8A81B295444C2881014452803709648E'SQL> 2 3
4 /

1 row deleted.

Elapsed: 00:00:00.18

Execution Plan
----------------------------------------------------------
Plan hash value: 2420547146

-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 1 | 50 | 1242 (2)| 00:00:15 |
| 1 | DELETE | OAUTH2_REFRESH_TOKEN | | | | |
|* 2 | INDEX FULL SCAN| SYS_C00203982 | 1 | 50 | 1242 (2)| 00:00:15 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter(RAWTOHEX("ID")='8A81B295444C2881014452803709648E')


Statistics
----------------------------------------------------------
0 recursive calls
10 db block gets
1228 consistent gets
0 physical reads
3460 redo size
845 bytes sent via SQL*Net to client
846 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
1 rows processed

I don't want to be rebulding this index all the time and was wondring if there is a better way to set it up.

and Tom said...

it is doing an index FULL scan.


see the filter:

filter(RAWTOHEX("ID")='8A81B295444C2881014452803709648E')


we are applying an implicit conversion in there on ID, effectively rendering the index useless for finding "a row".


Your developers want to

a) bind a RAW type
b) use "id = hextoraw( :x )" if they continue to bind a string.


that way, this will become an index unique scan.

Rating

  (7 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Daniel Blondowski, April 25, 2014 - 1:51 pm UTC

Bingo. They are using a string in the code. Hopefully I can get them to change it:)

A reader, April 26, 2014 - 4:04 pm UTC

Developers are telling me that they can't change their code to bind raw or use the rawtohex/hextoraw functions in their queries…for whatever unknown reason.

When we originally talked about setting up Primary Keys using GUID, they wanted to store them as varchars, but I insisted on using raw…mainly because that requires less storage and less IO when quering those columns.

However those deletes have a measurable impact on the server performance, so I'm thinking about letting them convert the PK to varchar. Is this a horrible idea? Besides increases storage, I"m also concerned that my cache will become less effective long term, as we would be storing more blocks for the same data.

I wouldn't be so worried if it was just a couple of tables, but long term this would be approach for all the tables.

Querying UUIDs

Keith, May 19, 2014 - 8:52 pm UTC

While Tom is 100% correct, I also believe Oracle has some culpability. A UUID is a blob. The string representation is just a human convenience. I believe Oracle should implicitly cast the string to a raw not the other way around (either way Oracle is performing an implicit cast). If you are going to do an implicit cast do the one that is desired 99.9% of the time.

A reader, May 27, 2014 - 1:03 pm UTC

You could also leave the column as raw and either add an index on hextoraw(id) or change the primary key to be hextoraw(id).

A reader, May 27, 2014 - 1:04 pm UTC

meant rawtohex, not hextoraw

A reader, November 03, 2014 - 3:47 pm UTC

analyze the table and indexes. That should resolve. Or try rebuilding the primary key

A reader, November 17, 2014 - 7:06 pm UTC

Create a function based index. That should solve the issue

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here