防止查询等待表级锁的方法

32b*_*oat 10 mysql myisam performance mysql-5.5 locking

将客户的数据库移动到额外的服务器后,我们遇到了问题。这应该会对站点的性能产生积极的影响,但是 MyISAM 中的表锁定存在问题。(我听说过使用 InnoDB 代替 MyISAM,但我们不能在不久的将来更改引擎)。
我们可以发现它是一个更新查询,当主持人在文章站点上激活评论时执行该查询。这是过程:

  • 处理更新查询 SET status = 1 WHERE id = 5(设置索引)
  • 页面缓存文件被删除

此时整个页面变得缓慢。数据库本身忙了几分钟。我取了几次进程列表,看到大约 60 个不同选择查询的条目,它们都处于等待表级锁定的状态。

1.我不明白为什么表上的这个更新article_comments会影响表的选择语句article以等待表级锁。在 processlist 中,几乎所有等待的查询都来自该表。我已经读过更新/插入比选择更受欢迎的事实,这可能会导致此类问题,但是当评论被激活时,文章表本身不会更新,因此选择不应该等待。我误解了吗?
2. 除了更改为 InnoDB 之外,还有什么可以防止这种行为或至少是为了获得更好的平衡吗?我对在将数据库移动到新服务器之前没有出现这个问题感到非常恼火。我想有一些配置错误,但我不知道如何识别。

Rol*_*DBA 8

MyISAM 存储引擎因对任何 DML(插入、更新、删除)执行全表锁定而臭名昭著。从长远来看,InnoDB 肯定会解决这个问题。

我写了使用 MyISAM 与 InnoDB 的优缺点

关于您当前的问题,这是一种可能的情况:

  • article并且article_comments都是 MyISAM 表
  • article_comments有一个或多个索引status作为一列
  • 索引页更新article_comments缓存在 MyISAM 密钥缓冲区中(大小由key_buffer_size 决定),导致旧的索引页超出 MyISAM 密钥缓冲区
  • 您有 SELECT 查询在article和之间执行 JOINarticle_comments

在我建议的场景中,对article表的SELECT可以阻止允许写入,因为必须等待article_comments从任何 DML 中释放(在这种情况下,一个UPDATE


Ric*_*mes 7

此时整个页面变得缓慢。数据库本身忙了几分钟。

闻起来像你有一个很大的 Query_cache?

mysql> SHOW VARIABLES LIKE 'query_cache%';
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 16777216 | -- Not over 50M
| query_cache_type             | DEMAND   | -- Only if using SQL_CACHE
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+
Run Code Online (Sandbox Code Playgroud)

对于有大量写入的生产系统,您也可以关闭 query_cache。

当对该表进行任何写入时,将清除给定表的 query_cache 中的所有条目。QC 越大,此任务越慢。

MyISAM 使用“表级”锁。读取和写入不能同时发生(在同一个表上)。粗鲁,但有效。