3

I have applications that insert rows into table A concurrently. Each application inserts rows in batch mode (using a JDBC prepared statement) using a single transaction per batch (to avoid rebuilding index after each INSERT). The rows present in each batch are completely independent, the transaction is used only for optimization. Each inserted row has its primary key set automatically (AUTO_INCREMENT).

I have another application that processes the rows from table A based on their IDs. The application processes range [ID1,ID2], then processes range [ID2+1,ID3], [ID3+1,ID4] and so on. Each range, e.g. [ID1,ID2] may contain rows inserted during different transactions, and possibly some of these transactions may not be committed yet. For example, in range [ID1,ID2], rows [ID1,ID1+N] may have been inserted during a not yet committed transaction while rows [ID1+N+1,ID2] may have been inserted during an already committed transaction. Therefore, when selecting rows in range [ID1,ID2], the transaction isolation level is set to READ_UNCOMMITTED so that uncommitted rows are visible.

The issue is that sometimes, the non committed rows are not visible and therefore are never processed.

The issue seems to appear when the SELECT is executed a very short time after the INSERTs. I made a test where one connection inserts multiple rows in a batch wrapped as a transaction, and before committing the transaction, after waiting some time, another connection queries the rows with READ_UNCOMMITTED as transaction isolation level, and the rows are visible. Therefore, I conclude that even if a row has been inserted and the auto increment counter lock released, the row may not be visible to other transactions although READ_UNCOMMITTED is set as transaction isolation level.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
manash
  • 6,985
  • 12
  • 65
  • 125
  • Could it be that the "Next key locking" feature of InnoDB is the culprit? – Alex Monthy Jun 17 '14 at 07:09
  • I thought about this but as I understand from the docs, the AUTO_INCREMENT counter lock is acquired before the INSERT and released after it. Therefore, if I see rows after the invisible ones, the lock must be released. Am I right? – manash Jun 17 '14 at 07:14
  • Have you learned anything new regarding this issue? I have posted a related, slightly more general issue: https://stackoverflow.com/questions/59106154/ – Timo Nov 29 '19 at 13:57

1 Answers1

0

With my small test script no records show up before the commit if I login from another console. I can select the just inserted records in the same session, though. So I assume that before the commit you might access rows which are already in the table, but now new rows or changes before they are committed.

<?php

require_once('db.php');

q( 'drop table if exists t' );
q( 'create table t (id integer not null auto_increment primary key, v datetime) engine=innodb' );

q( 'set transaction isolation level read uncommitted' );
q( 'start transaction' );
q( 'insert into t (v) values (now()),(now()),(now())' );

echo q1( 'count(*)', 't', 'true'); // translates to "select count(*) from t where true"; 
// echoes "3" to the console

// wait for input
$handle = fopen ("php://stdin","r");
$line = fgets($handle);

// with a mysql client from a 2nd console at this point no new records show in table t

q( 'commit' );

// after this point all new records show up in table t from a 2nd session.
Alex Monthy
  • 1,827
  • 1
  • 14
  • 24
  • 1
    I just made the same test and I do see the new records. I conclude the time since the rows are inserted until they are queried is important. It seems like one cannot suppose ALL changes performed during not yet committed transactions are visible. For example, the changes may be visible only after some time. – manash Jun 17 '14 at 12:54
  • 1
    In your case, you set the transaction isolation level for the INSERT transaction. It won't help you. You need to set the isolation level for the transaction that queries for the rows. – manash Jun 18 '14 at 11:17