Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Ravi.

Asked: November 03, 2017 - 8:42 pm UTC

Last updated: November 04, 2017 - 1:33 am UTC

Version: Oracle 12.1.0.2

Viewed 1000+ times

You Asked

Hi,

I have a data warehouse application running to "Enqueue TX row lock contention waits".

Here is the situation:

Table has 50 hash partitions on point_id column. the data load process is trying to delete rows using ROWID values, it is locking multiple partitions with TX row lock contention. this is preventing other sessions to perform any action against this table.

SQL> desc odr.v_accnt_r_0000411
Name Null? Type
----------------------------------------- -------- ----------------------------
POINT_ID NOT NULL NUMBER(10)
START_TIME_INT NOT NULL NUMBER(10)
END_TIME_INT NOT NULL NUMBER(10)
BATCH_ID NOT NULL NUMBER(10)
PARENT_POINT_ID NOT NULL NUMBER(10)

Here is the delete statement.

delete /*+ dynamic_sampling(gt 3) */ from V_ACCNT_R_0000411 where rowid IN (select core_row_id from gtt_pid_relation gt)


We want to understand why the above delete is causing row locking issues.

thanks a lot,
Ravi

and Connor said...

TX row contention is literally that, ie, for a particular row. Hash partitioning is not going to change that. For example

SQL> create table t
  2  partition by hash ( object_id)
  3  partitions 8
  4  as select * from dba_objects
  5  where object_id is not null;

Table created.

SQL>
SQL> select dbms_rowid.rowid_Object(rowid), count(*)
  2  from t
  3  group by dbms_rowid.rowid_Object(rowid);

DBMS_ROWID.ROWID_OBJECT(ROWID)   COUNT(*)
------------------------------ ----------
                        162760       9947
                        162759       9897
                        162758       9851
                        162761       9744
                        162762       9743
                        162763       9660
                        162764       9948
                        162765       9762

8 rows selected.

SQL>
SQL> select partition_name from user_tab_partitions where table_name = 'T';

PARTITION_NAME
------------------------------
SYS_P4910
SYS_P4911
SYS_P4912
SYS_P4913
SYS_P4914
SYS_P4915
SYS_P4916
SYS_P4917

8 rows selected.

SQL>
SQL> create table gtt ( r rowid );

Table created.

SQL>
SQL> begin
  2    for i in ( select partition_name from user_tab_partitions where table_name = 'T' and rownum <= 4 )
  3    loop
  4      execute immediate
  5        'insert into gtt select rowid from t partition ('||i.partition_name||') where rownum <= 500';
  6    end loop;
  7  end;
  8  /

PL/SQL procedure successfully completed.

SQL>
SQL> select count(*) from gtt;

  COUNT(*)
----------
      2000

1 row selected.

SQL>
SQL> delete from t where rowid in ( select r from gtt ) ;

2000 rows deleted.

SQL>


So I've got 8 partitions and I've deleted rows from 4 of them. In another session, I then try some deletes

SQL> delete from t partition ( SYS_P4916 );

9948 rows deleted.


That works because it does not clash with the partitions that have some active transactions. But this one:

SQL> delete from t partition ( SYS_P4912 );

[waiting]


and I'm blocked by the deletes. But these are still *row* level locks. For example, if I pick a row that was not in the deleted set, I'm fine

SQL> delete from t partition ( SYS_P4912 )
  2  where object_id = 162203;

1 row deleted.


btw, you want to have an power of 2 hash partitions, otherwise your data will not be evenly spaced between them

Rating

  (1 rating)

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

Comments

Hash partition question

Ravi Arumugam, November 06, 2017 - 5:00 pm UTC

Hi Connor,

thanks a lot for your response. We will check your example with our code and data to validate.

Appreciate your time and quick response.

Sincerely,
Ravi

More to Explore

Design

New to good database design? Check out Chris Saxon's full fundamentals class.