Bug #102722 | Unmatched second indexes are locked when index_condition_pushdown=ON | ||
---|---|---|---|
Submitted: | 24 Feb 2021 10:50 | Modified: | 12 Jul 2022 1:12 |
Reporter: | Cheng Zhou | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Documentation | Severity: | S3 (Non-critical) |
Version: | 8.0 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[24 Feb 2021 10:50]
Cheng Zhou
[25 Feb 2021 13:18]
MySQL Verification Team
Hi Mr. Zhou, Thank you for your bug report. However, this is a behaviour that is very well known for the index pushdowns. However, we do not see it properly documented in our Reference Manual. Hence, we are verifying your report as a documentation bug.
[26 Feb 2021 1:28]
Cheng Zhou
Well, I guess it would be better to unlock those unmatched second index records properly. In our production environment, we executed 'select ... for update limit 50000' in a transaction, but more than 1000000 second indexes were locked, which caused severe lock conflicts.
[26 Feb 2021 13:04]
MySQL Verification Team
Hi Mr. Zhou, We do agree with you , which is why this report will get a wider discussion .......
[23 Jul 2021 14:12]
Jakub Lopuszanski
Posted by developer: The testcase from the original report expressed as MTR: SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; show variables like '%isolation%'; create table ts(a int primary key, b int, c int, d int, index(b,c)); insert into ts values(1,1,1,1),(2,2,2,2),(3,3,3,3),(4,4,4,4),(5,5,5,5),(6,6,6,6),(7,7,7,7),(8 ,8,8,8),(9,9,9,9); --let $i=0 while($i<2){ SELECT @@optimizer_switch LIKE '%index_condition_pushdown=on%'; explain select b,c,d from ts where b>=5 and b<8 and c=7 for update; begin; select b,c,d from ts where b>=5 and b<8 and c=7 for update; select INDEX_NAME,LOCK_TYPE,LOCK_MODE,LOCK_STATUS,LOCK_DATA from performance_schema.data_locks; commit; SET @@optimizer_switch='index_condition_pushdown=off'; --inc $i } DROP TABLE ts; SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
[26 Jul 2021 15:32]
Jakub Lopuszanski
Posted by developer: Just calling the row_unlock_for_mysql(prebuilt,trx) in the case reported in this issue, will not be enough, because this function returns early if we didn't lock the clustered index (just the secondary index). It does so because it doesn't know how to establish if the row was modified by current transaction or not, which it usually does by looking at the clustered index record's TRX_ID field. My current idea is to somehow use the hint from the caller, who should know if the row was or wasn't modified, but I need to think it through and test it.
[27 Jul 2021 11:47]
MySQL Verification Team
Hi Jakub, Thank you for your contribution. We do not see how could this be achieved without locking the clustered index in InnoDB. The only possibility is to have a TIMESTAMP that changes on any write. But, we can not make a special algorithm for some small part of cases.
[27 Jul 2021 13:00]
Jakub Lopuszanski
Posted by developer: I'm sorry, the MTR I've shown above is wrong: while it looks like it sets the GLOBAL TRANSACTION ISOLATION LEVEL to READ COMMITTED, it doesn't apply to the current connection itself, which still uses REPEATABLE READ. A (hopefully) proper version of the test is: create table ts(a int primary key, b int, c int, d int, index(b,c)); insert into ts values(1,1,1,1),(2,2,2,2),(3,3,3,3),(4,4,4,4),(5,5,5,5),(6,6,6,6),(7,7,7,7),(8 ,8,8,8),(9,9,9,9); ANALYZE TABLE ts; --let $i=0 while($i<2){ SELECT @@optimizer_switch LIKE '%index_condition_pushdown=on%'; explain select b,c,d from ts where b>=5 and b<8 and c=7 for update; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; begin; select b,c,d from ts where b>=5 and b<8 and c=7 for update; select INDEX_NAME,LOCK_TYPE,LOCK_MODE,LOCK_STATUS,LOCK_DATA from performance_schema.data_locks; commit; SET @@optimizer_switch='index_condition_pushdown=off'; --inc $i } DROP TABLE ts;
[12 Jul 2022 1:12]
Jon Stephens
Documented fix as follows in the MySQL 8.0.28 as follows: With index_condition_pushdown=ON and transaction_isolation='READ-COMMITTED', locks on secondary indexes were not released until the transaction was committed or rolled back, even though the secondary indexes were unmatched. Closed.