什么可能导致InnoDB表的单个UPDATE的性能非常慢?

时间:2014-07-18 10:47:31

标签: mysql sql performance innodb

我的网络应用程序中有一个用于存储会话数据的表。它的表现很糟糕,我无法弄清楚原因。慢查询日志显示更新行需要6到60秒。

CREATE TABLE `sessions` (
    `id` char(40) COLLATE utf8_unicode_ci NOT NULL,
    `payload` text COLLATE utf8_unicode_ci NOT NULL,
    `last_activity` int(11) unsigned NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `session_id_unique` (`id`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

PK是char(40),它存储由该项目使用的框架(Laravel)生成的唯一会话哈希。

(我已经意识到PK和唯一索引的冗余,但我已经尝试了所有组合,但它对我的测试中的性能没有任何影响。这是当前状态它。)

表格很小 - 少于200行

慢查询日志中的典型查询如下所示:

INSERT INTO sessions (id, payload, last_activity) 
VALUES ('d195825ddefbc606e9087546d1254e9be97147eb', 
        'YTo1OntzOjY6Il90b2tlbiI7czo0MDoi...around 700 chars...oiMCI7fX0=', 
        1405679480) 
ON DUPLICATE KEY UPDATE 
    payload=VALUES(payload), last_activity=VALUES(last_activity);

我做了很明显的事情,比如查看表格是否有损坏。我已经尝试添加专用的PK列作为自动增量int,我已经尝试过没有PK,没有唯一索引,将text列换成非常大的{ {1}},你的名字。

我已经尝试将表格切换为使用MyISAM,但它仍然很慢。

我所做的一切似乎没有任何区别 - 桌子的表现非常缓慢。

我的下一个想法是查询。这是由框架生成的,但是如果失败的话,我已经测试了将其标记为varchar UPDATEINSERT声明继续缓慢。

我已经阅读了很多关于慢UPDATEINSERT语句的问题,但这些问题通常与批量交易相关。这只是每个请求每个用户一次插入/更新。该网站并不是很忙,而且它拥有足够的资源在自己的VPS上。

什么可能导致缓慢?

2 个答案:

答案 0 :(得分:2)

这不是答案,但SE评论的长度太短了。如此。

如果直接在命令行上运行相同的INSERT ... ON DUPLICATE KEY UPDATE ...语句会发生什么?请尝试使用和不使用应用程序的实际使用。该应用程序可能会人为地减慢此更新速度(例如,在INNODB中,事务可能会被打开,但是在消耗了大量时间之后就会提交。您也使用MyISAM进行测试,这也不支持事务。也许在这种情况下,显式LOCK可以如果框架使用这个技巧,我不确定,我不知道laravel)尝试进行基准测试以确定是否存在并发效应。

另一个问题:这是一台服务器吗?或者它是一个复制到一个或多个奴隶的主人?

除了这个问题,还有一些意见:

  • id的值是十六进制字符串。该列是unicode。这意味着保留了3 * 40个字节,而只使用了40个字节。这是浪费,一般会使事情效率低下。使用BINARY或ASCII作为字符编码会好得多。更好的是,将id列更改为BINARY数据类型并存储(未映射的)二进制值
  • innodb PK表的哈希将跨页面分散数据。使用auto_incrment pk或者根本没有明确声明pk的想法(这将导致innodb在内部创建自己的自动增量pk)是一个好主意。
  • 看起来有效负载是base64编码的。同样,字符编码被指定为unicode。 Ascii或Binary(字符编码,而不是数据类型)更合适。
  • ID上唯一索引中的HASH关键字没有意义。 InnoDB没有实现HASH索引。不幸的是,MySQL对此完全保持沉默(见http://bugs.mysql.com/bug.php?id=73326

(虽然这个列表确实提供了改进的角度,但似乎不太可能通过这种方式来解决极端缓慢问题。必须有其他事情发生)

答案 1 :(得分:0)

令人沮丧的是,答案是这个案子是一个糟糕的磁盘。存储阵列中的一个磁盘变坏了,因此写入工作将永远完成。就是这样。