Bug #28534 | INSERT INTO ... SELECT FROM doesn't care about REPEATABLE READ | ||
---|---|---|---|
Submitted: | 19 May 2007 10:41 | Modified: | 10 Sep 2007 18:29 |
Reporter: | Peufeu Peufeu | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Documentation | Severity: | S3 (Non-critical) |
Version: | 5.0.44, 5.0.38 | OS: | Linux (Gentoo) |
Assigned to: | Paul DuBois | CPU Architecture: | Any |
[19 May 2007 10:41]
Peufeu Peufeu
[6 Jul 2007 1:26]
KimSeong Loh
I had some other problem, but I believe is cause by the same reason. I found that the INSERT .. SELECT .. actually place a READ LOCK on the selected table, more like a LOCK IN SHARE MODE. This can be the reason why the rows read is not from the REPEATABLE-READ isolation, but looks like READ-COMMITTED, since LOCK IN SHARE MODE always get the latest committed data. I tested using MySQL 5.0.41 community on Windows.
[6 Jul 2007 1:35]
KimSeong Loh
Steps to show there is a read lock Connection 1: mysql> create table t (i int) engine=innodb; Query OK, 0 rows affected (0.09 sec) mysql> create table t2 like t; Query OK, 0 rows affected (0.10 sec) mysql> insert t values (1),(2),(3); Query OK, 3 rows affected (0.09 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t for update; +------+ | i | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) This will place a write lock on the rows with the SELECT .. FOR UPDATE Connection 2: mysql> select * from t; +------+ | i | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) mysql> insert t2 select * from t; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction This shows that the SELECT is non-blocking, but the INSERT .. SELECT is blocking. I suspect it is trying to do a SELECT .. LOCK IN SHARE MODE. I also tested with LOCK IN SHARE MODE in connection 1 instead of FOR UPDATE, this does not block the INSERT .. SELECT which means the INSERT .. SELECT is not trying to get a write lock on the selected table, but a read lock.
[6 Jul 2007 9:10]
Sergei Golubchik
This is expected. When binary logging is enabled, InnoDB uses stronger locks for INSERT ... SELECT. Otherwise an UPDATE, for example, that started after INSERT ... SELECT started, may finish faster and will be written in the binlog before INSERT ... SELECT. So, on the slave UPDATE will be executed before INSERT ... SELECT and will affect the results. Which will break replication. There's a variable @@innodb_locks_unsafe_for_binlog that would disable this behaviour. Alternatively, if you use row-based replication, InnoDB won't use stronger locks either.
[8 Jul 2007 5:20]
Valeriy Kravchuk
Original test case is repeatable with 5.0.44. But I am still not sure it is a bug. SELECT will still give you results in a state before the autocommitted transaction from client 2. Second INSERT ... SELECT will insert the same results as first (because first will lock table from further updates). Reads are repeatable by subsequent SELECTs, and by subsequent INSERT ... SELECTs. It is not clear from http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html should they be consistent with respect to each other though. It can be an intended behaviour, but it should just be documented in more details.
[8 Jul 2007 9:25]
Peufeu Peufeu
Well, setting isolation to REPEATABLE READ is supposed to give, ahem, repeatable reads, which it doesn't. So this is a bug.
[10 Sep 2007 18:29]
Paul DuBois
Thank you for your bug report. This issue has been addressed in the documentation. The updated documentation will appear on our website shortly, and will be included in the next release of the relevant products. Serg's explanation is correct. I've added this para to the consistent-read page: InnoDB uses a consistent read for select in clauses like INSERT INTO ... SELECT and UPDATE ... (SELECT) that do not specify FOR UPDATE or IN SHARE MODE if the innodb_locks_unsafe_for_binlog option is set and the isolation level of the transaction is not set to serializable. Thus no locks are set to rows read from selected table. Otherwise, InnoDB uses stronger locks and the SELECT part acts like READ COMMITTED, where each consistent read, even within the same transaction, sets and reads its own fresh snapshot. This will appear at: http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html