| Bug #63751 | "SELECT ... WHERE w_id%4=1 FOR UPDATE" locks whole table | ||
|---|---|---|---|
| Submitted: | 14 Dec 2011 20:06 | Modified: | 21 Dec 2011 20:55 |
| Reporter: | Grigori Khmyrov | Email Updates: | |
| Status: | Not a Bug | Impact on me: | |
| Category: | MySQL Server: Locking | Severity: | S3 (Non-critical) |
| Version: | 5.5.15 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
[14 Dec 2011 20:06]
Grigori Khmyrov
[15 Dec 2011 8:41]
Valeriy Kravchuk
Please, send the output of: explain SELECT * FROM s1_tpcc.warehouse WHERE w_id%12=2; I wonder if any index is used.
[15 Dec 2011 16:03]
Grigori Khmyrov
There are results from "locking wrong" and "locking right": mysql> explain SELECT * FROM s1_tpcc.warehouse WHERE w_id%12=2; +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | warehouse | ALL | NULL | NULL | NULL | NULL | 13 | Using where | +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> explain SELECT * FROM s1_tpcc.warehouse WHERE w_id=2; +----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | warehouse | const | PRIMARY | PRIMARY | 4 | const | 1 | | +----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+ 1 row in set (0.00 sec) It sounds roght for me. When expression in where it's OK to use natural order.
[15 Dec 2011 18:13]
Valeriy Kravchuk
Well, "ALL" means that index is not used and every row is locked (as I expected). Please, send the output of: show table status like 'warehouse'\G show indexes from warehouse; But as you compare expression on column with some constant, optimizer can hardly use proper index...
[15 Dec 2011 22:53]
Grigori Khmyrov
mysql> show table status like 'warehouse'\G
*************************** 1. row ***************************
Name: warehouse
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 1197473792
Auto_increment: NULL
Create_time: 2011-11-21 12:51:24
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.05 sec)
mysql> show indexes from warehouse;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| warehouse | 0 | PRIMARY | 1 | w_id | A | 0 | NULL | NULL | | BTREE | | |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
[15 Dec 2011 23:03]
Grigori Khmyrov
Looks like because it is expression in where clause engine will read all records and mark them as locked for update.
[16 Dec 2011 4:52]
Valeriy Kravchuk
Statistics is missing for your table it seems. Please, execute analyze table warehouse; and check EXPLAIN results for the original query again.
[21 Dec 2011 18:10]
Grigori Khmyrov
mysql> analyze table warehouse; +-------------------+---------+----------+----------+ | Table | Op | Msg_type | Msg_text | +-------------------+---------+----------+----------+ | s1_tpcc.warehouse | analyze | status | OK | +-------------------+---------+----------+----------+ 1 row in set (0.30 sec) mysql> explain SELECT * FROM s1_tpcc.warehouse WHERE w_id%12=2; +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | warehouse | ALL | NULL | NULL | NULL | NULL | 7 | Using where | +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.15 sec)
[21 Dec 2011 18:33]
Valeriy Kravchuk
Well, I still do not see any way for optimizer to use index to find 1/4 of all rows in the table (potentially), with large intervals between them (values like 1, 5, 9, 13 etc) in general case. So "ALL" access path is expected and locking is unavoidable.
[21 Dec 2011 20:55]
Grigori Khmyrov
Is it any way to lock only actually selected records instead of all records read by engine? Why do I care how many records and how engine read to select my data? I know "SELECT ... WHERE id IN (3, 7, 9)" will do it if "id" is key field.
