首页 > 解决方案 > mysql索引在rails中行为不端

问题描述

我有一个使用 Mysql 托管的 Rails 应用程序,在rescheduled_reservation_id列(可为空)中有一个带有索引设置的预订表。

在我的 Rails 应用程序中,有两个部分通过 rescheduled_reservation_id 字段查询预订,如下所示:

Transit::Reservation.find_by(rescheduled_reservation_id: 25805)

并产生以下日志输出:

Transit::Reservation Load (60.3ms)  SELECT  `transit_reservations`.* FROM `transit_reservations` WHERE `transit_reservations`.`deleted_at` IS NULL AND `transit_reservations`.`rescheduled_reservation_id` = 25805 LIMIT 1

但是应用程序的另一部分:

Transit::Reservation.where(rescheduled_reservation_id: 25805).last

日志输出如下

Transit::Reservation Load (2.3ms)  SELECT  `transit_reservations`.* FROM `transit_reservations` WHERE `transit_reservations`.`deleted_at` IS NULL AND `transit_reservations`.`rescheduled_reservation_id` = 25805  ORDER BY `transit_reservations`.`id` DESC LIMIT 1

清楚地看到第一个查询

Transit::Reservation Load (60.3ms)  SELECT  `transit_reservations`.* FROM `transit_reservations` WHERE `transit_reservations`.`deleted_at` IS NULL AND `transit_reservations`.`rescheduled_reservation_id` = 25805 LIMIT 1

占用了 60 毫秒,与本文档中的 2 毫秒相比,索引可能没有被正确使用

Transit::Reservation Load (2.3ms)  SELECT  `transit_reservations`.* FROM `transit_reservations` WHERE `transit_reservations`.`deleted_at` IS NULL AND `transit_reservations`.`rescheduled_reservation_id` = 25805  ORDER BY `transit_reservations`.`id` DESC LIMIT 1

在此处输入图像描述

我还尝试通过对两个查询运行解释来进一步调试,我得到了相同的结果,即正在使用的索引 rescheduled_reservation_id

在此处输入图像描述

有没有人遇到过这个问题?我想知道 rails mysql 连接(我正在使用 mysql2 gem)是否可能导致 MySQL 服务器没有选择正确的索引

标签: mysqlruby-on-railsindexingmysql-workbenchmysql2

解决方案


这很罕见,但很正常。

可能的答案是第一次出现没有找到它需要缓存在 buffer_pool 中的块。因此,它必须从磁盘中获取它们。在普通的 ole HDD 上,经验法则是每次磁盘命中 10 毫秒。因此,可能需要 6 个块来获取,导致 60.3 毫秒。

另一种可能性是其他活动正在干扰,从而减慢了此操作。

2.3ms 对于像这样的简单查询是合理的,可以完全使用 RAM 中的缓存块执行。

服务器最近是否重新启动?重新启动后,缓存中没有任何内容。桌子比 大innodb_buffer_pool_size吗?如果是这样,那将导致 60ms 偶尔发生——块会被撞出。(警告:buffer_pool 不应该变得太大以至于发生“交换”。)

一个块是16KB;它包含 BTree 的一些数据行或索引行或节点。根据表的大小,即使是“点查询”也可能需要查看 6 个或更多块。

如果你大部分时间都没有得到 2.3ms ,我们应该更深入地挖掘。(我已经暗示要调查的尺寸。)


推荐阅读