MariaDB MyISAM表执行handler open是否应添加表元数据读锁?
问题背景
我正在将应用从MariaDB 5.5迁移至10.3版本。该应用使用HANDLER OPEN、HANDLER READ命令直接访问MyISAM表,另有一个应用通过不同连接使用标准SELECT/INSERT/UPDATE等语句操作同一批表。
在5.5版本中,HANDLER OPEN不会对表添加任何锁,但10.3版本中会添加元数据锁,测试步骤及结果如下:
MariaDB [test]> create table t1 (a int) engine=MyISAM ; Query OK, 0 rows affected (0.003 sec) MariaDB [test]> handler t1 open ; Query OK, 0 rows affected (0.001 sec) MariaDB [test]> select * from information_schema.metadata_lock_info ; +-----------+-----------------+---------------+---------------------+--------------+------------+ | THREAD_ID | LOCK_MODE | LOCK_DURATION | LOCK_TYPE | TABLE_SCHEMA | TABLE_NAME | +-----------+-----------------+---------------+---------------------+--------------+------------+ | 17821 | MDL_SHARED_READ | NULL | Table metadata lock | test | t1 | +-----------+-----------------+---------------+---------------------+--------------+------------+ 1 row in set (0.001 sec)
当另一个连接尝试执行LOCK TABLES t1 WRITE;时会无限阻塞,进程列表中该连接状态显示为“Waiting for table metadata lock”。
官方文档对比
MySQL手册中明确说明:
HANDLER是一种相对底层的语句。例如,它不保证一致性。也就是说,HANDLER ... OPEN不会创建表快照,也不会锁定表。这意味着在执行HANDLER ... OPEN语句后,表数据可能会被修改(当前会话或其他会话),这些修改可能仅部分对HANDLER ... NEXT或HANDLER ... PREV扫描可见。
这与MariaDB 5.5的原有行为完全一致。
MariaDB手册的相关说明则暗示不会添加元数据锁:
限制 由于这是直接与存储引擎交互的接口,当表发生变化时,可能会存在一些操作限制和异常情况。
(显然如果表被锁定,就无法发生变化。)
结论:HANDLER OPEN不应添加该元数据锁
从功能设计、向后兼容性及文档一致性角度判断,MariaDB 10.3中给HANDLER OPEN添加MDL_SHARED_READ锁的行为不合理:
- 违背HANDLER的底层设计初衷:HANDLER作为直接对接存储引擎的低层级接口,核心特性就是支持无锁并发访问、允许其他会话随时修改表数据,添加元数据锁直接颠覆了这一设计逻辑。
- 破坏向后兼容性:原有依赖MariaDB 5.5版本无锁特性的多应用并发场景,迁移至10.3后会出现写操作阻塞的问题,违背了数据库版本升级应尽量兼容旧行为的原则。
- 与官方文档描述矛盾:MariaDB手册明确说明HANDLER接口允许表发生变化,但实际添加的元数据锁会阻塞
LOCK TABLES ... WRITE这类写锁操作,形成文档与实际行为的不一致。
如果需要保证HANDLER访问过程中的数据一致性,应该由业务侧主动通过锁机制控制,而非数据库强制添加元数据锁限制并发。
内容的提问来源于stack exchange,提问作者user23440221

