Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
13.1
-
None
-
Related to performance
-
Q4/2026 Server Maintenance
Description
Consider the following
CREATE TABLE t1 (id INT PRIMARY KEY, sec INT, pad CHAR(100), KEY i1(sec)) |
ENGINE=InnoDB;
|
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_10000; |
SELECT sec,id FROM t1 FOR UPDATE; |
The SELECT statement is a covering scan on the secondary index i1. After MDEV-24813 it acquires a table X-lock. However, instead of doing only a scan on i1, it lock and reads the clustered records:
/* in row_search_mvcc: */
|
if (index != clust_index && prebuilt->need_to_access_clustered) { |
if (row_search_with_covering_prefix(prebuilt, rec, offsets)) { |
goto use_covering_index; |
}
|
requires_clust_rec:
|
|
|
/* in row_search_with_covering_prefix: */
|
/* In ha_innobase::build_template() we choose to access the |
whole row when using exclusive row locks or In case of fts
|
query, we need to read from clustered index */
|
if (prebuilt->select_lock_type == LOCK_X || prebuilt->in_fts_query |
|| !index->is_btree()) {
|
return false; |
}
|
This is not the case for S-lock, which contributes to the discrepancy in performance gains between FOR UPDATE and LOCK IN SHARE MODE for full index scans, see https://jira.mariadb.org/browse/TODO-6178?focusedCommentId=336460&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-336460.
With innodb_table_lock_on_full_scan on, we save on the clustered locks, but FOR UPDATE still suffers from extra clustered reads.
This can be observed in the following testcase:
--source include/have_innodb.inc
|
--source include/have_sequence.inc
|
SET GLOBAL innodb_monitor_enable='lock_rec_lock_created'; |
CREATE TABLE t1 (id INT PRIMARY KEY, sec INT, pad CHAR(100), KEY i1(sec)) |
ENGINE=InnoDB;
|
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_10000; |
let $bp= SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS |
WHERE VARIABLE_NAME='INNODB_BUFFER_POOL_READ_REQUESTS'; |
let $lk= SELECT COUNT FROM information_schema.INNODB_METRICS |
WHERE NAME='lock_rec_lock_created'; |
|
|
set innodb_table_lock_on_full_scan=0; |
|
|
let $r1= `$bp`;
|
let $l1= `$lk`;
|
--disable_result_log
|
SELECT sec,id FROM t1 FOR UPDATE; |
--enable_result_log
|
let $r2= `$bp`;
|
let $l2= `$lk`;
|
--disable_result_log
|
SELECT sec,id FROM t1 LOCK IN SHARE MODE; |
--enable_result_log
|
let $r3= `$bp`;
|
let $l3= `$lk`;
|
|
|
set innodb_table_lock_on_full_scan=1; |
|
|
--disable_result_log
|
SELECT sec,id FROM t1 FOR UPDATE; |
--enable_result_log
|
let $r4= `$bp`;
|
let $l4= `$lk`;
|
--disable_result_log
|
SELECT sec,id FROM t1 LOCK IN SHARE MODE; |
--enable_result_log
|
let $r5= `$bp`;
|
let $l5= `$lk`;
|
|
|
--echo # read requests
|
eval SELECT ($r2 - $r1) as x_off, ($r3 - $r2) as s_off, ($r4 - $r3) as x_on, ($r5 - $r4) as s_on; |
|
|
--echo # locks
|
eval SELECT ($l2 - $l1) as x_off, ($l3 - $l2) as s_off, ($l4 - $l3) as x_on, ($l5 - $l4) as s_on; |
|
|
DROP TABLE t1; |
SET GLOBAL innodb_monitor_enable=default; |
it prints:
# read requests |
# [... 1 lines elided]
|
x_off s_off x_on s_on
|
20011 11 20011 11
|
# locks
|
# [... 1 lines elided]
|
x_off s_off x_on s_on
|
96 10 0 0
|
Attachments
Issue Links
- relates to
-
MDEV-24813 Locking full table scan fails to use table-level locking
-
- Closed
-