InnoDB
表使用行级锁,以便多个会话和应用程序可以同时读取和写入同一表,而不会相互等待或产生不一致的结果。对于此存储引擎,请避免使用 LOCK TABLES
语句,因为它不提供任何额外的保护,反而会降低并发性。自动的行级锁使这些表适用于最繁忙的数据库,这些数据库包含您最重要的数据,同时也简化了应用程序逻辑,因为您不需要锁定和解锁表。因此,InnoDB
存储引擎是 MySQL 的默认存储引擎。
MySQL 对除 InnoDB
之外的所有存储引擎使用表级锁(而不是页面级、行级或列级锁)。锁定操作本身不会产生太多开销。但由于一次只有一个会话可以写入表,因此为了获得这些其他存储引擎的最佳性能,请主要将它们用于经常被查询且很少插入或更新的表。
在选择使用 InnoDB
还是其他存储引擎创建表时,请记住表级锁的以下缺点
表级锁允许许多会话同时从表中读取,但如果一个会话想要写入表,它必须首先获得独占访问权限,这意味着它可能需要等待其他会话先完成对表的访问。在更新期间,所有其他想要访问该特定表的会话都必须等待更新完成。
当一个会话在等待时,由于磁盘已满,并且需要释放一些空间才能让会话继续执行,这会导致表级锁出现问题。在这种情况下,所有想要访问问题表的会话也会被置于等待状态,直到释放更多磁盘空间。
一个
SELECT
语句如果运行时间过长,会阻止其他会话在此期间更新该表,从而使其他会话看起来很慢或无响应。当一个会话在等待获得对表进行更新的独占访问权限时,发出SELECT
语句的其他会话会在其后面排队,即使对于只读会话也是如此,这会降低并发性。
以下项目描述了一些避免或减少由表级锁引起的争用问题的方法
考虑将表切换到
InnoDB
存储引擎,可以使用CREATE TABLE ... ENGINE=INNODB
在设置过程中完成,或者使用ALTER TABLE ... ENGINE=INNODB
对现有表完成。有关此存储引擎的更多详细信息,请参见 第 17 章,InnoDB 存储引擎。优化
SELECT
语句以更快地运行,这样它们锁定的时间就会更短。您可能需要创建一些摘要表来完成此操作。使用 mysqld 启动,并使用
--low-priority-updates
。对于仅使用表级锁的存储引擎(如MyISAM
、MEMORY
和MERGE
),这将使所有更新(修改)表的语句的优先级低于SELECT
语句。在这种情况下,前面场景中的第二个SELECT
语句将在UPDATE
语句之前执行,并且不会等待第一个SELECT
完成。要指定在特定连接中发出的所有更新都应以低优先级执行,请将
low_priority_updates
服务器系统变量设置为 1。为了提高特定
SELECT
语句的优先级,请使用HIGH_PRIORITY
属性。请参见 第 15.2.13 节“SELECT 语句”。使用较低的值启动 mysqld 的
max_write_lock_count
系统变量,以强制 MySQL 在对表进行特定数量的写锁(例如插入操作)后,暂时提高所有等待表的SELECT
语句的优先级。这允许在特定数量的写锁之后进行读锁。如果您在混合
SELECT
和DELETE
语句方面遇到问题,DELETE
的LIMIT
选项可能会有所帮助。请参见 第 15.2.2 节“DELETE 语句”。对
SELECT
语句使用SQL_BUFFER_RESULT
有助于缩短表锁的持续时间。请参见 第 15.2.13 节“SELECT 语句”。将表内容拆分为单独的表可能会有所帮助,因为这样可以允许查询针对一个表的列运行,而更新则限制在另一个表的列中。
您可以修改
mysys/thr_lock.c
中的锁定代码以使用单个队列。在这种情况下,写锁和读锁将具有相同的优先级,这可能有助于某些应用程序。