mysql - 事件记录查找 - 尽管添加了索引,find_by_inventory_product_id 仍间歇性缓慢

标签 mysql ruby-on-rails-3 indexing rails-activerecord unique-key

我有一个简单的新 API 端点,其中涉及查询我新设置和填充的表 - inventory_products。

inventory_products 表的架构是:

CREATE TABLE `inventory_products` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `inventory_product_id` binary(16) DEFAULT NULL,
  `product_id` binary(16) DEFAULT NULL,
  `status` enum('ACTIVE','INACTIVE','DELETED') DEFAULT 'ACTIVE',
  `priority` int(11) DEFAULT '0',
  `inventory_service_id` tinyint(3) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uc_inventory_product_id` (`inventory_product_id`),
  KEY `idx_product_status` (`product_id`,`status`)
) ENGINE=InnoDB AUTO_INCREMENT=76312817 DEFAULT CHARSET=utf8;

API端点主要执行以下操作:

def lookup_inventory_service_id
    return render_error_response(AUTH_ERROR, {status: 403}) unless client.name == PERMITTED_NAME

    ip_fetch_start = Time.now
    inventory_product = InventoryProducts.find_by_inventory_product_id(resource_attributes[:inventory_product_id])
    Rails.logger.info({inventory_product_id: resource_attributes[:inventory_product_id], inventory_product_fetch_time_ms: (Time.now - ip_fetch_start)*1000}.as_json)
    return head :not_found unless inventory_product
....

问题:inventory_product查找(find_by_inventory_product_id)是Rails的ActiveRecord提供的标准函数(我没有在我的模型中覆盖它)。此函数需要 10 毫秒到有时甚至 650 毫秒(从我添加的日志中找到)。尽管查找中使用的列上存在 Mysql 索引,为什么在某些情况下会花费如此多的时间,而在其他情况下却花费更少的时间?

我已经提到 inventory_product_id 作为我的架构中的唯一键,并且由上述函数触发的 MySQL 查询使用 inventory_product_id 作为下面 explain 语句中的索引。

解释 SELECT inventory_products.* FROM inventory_products WHERE inventory_products.inventory_product_id = 0x3a288cdce78d44618eadd72e240f26a4 LIMIT 1

id select_type 表类型 possible_keys key key_len ref rows Extra 1 SIMPLE inventory_products const uc_inventory_product_id uc_inventory_product_id 17 const 1 NULL

我的架构有问题吗?我是否明确需要在架构中提及 inventory_product_id 作为 mysql 索引?类似于:

KEY `idx_product_status` (`product_id`,`status`)

提前谢谢!!

我使用Mysql 5.6和rails - 3.2.8。另外,我的 Rails 应用程序在 jruby (1.7.0)/内的 tomcat 服务器(版本 - Apache Tomcat/7.0.16)上运行

最佳答案

这是应该发生的事情:

优化器将决定使用唯一键。这意味着将有零行或一行具有该值。

  1. 向下钻取 BTree(3-4 层深)以查找 [inventory_product_id, id] 的索引行
  2. (假设找到一行),使用 id 向下钻取数据 BTree(可能深 4 层)。
  3. 提取该行的所有列(因为您说过SELECT *)。

即使在非常冷的系统上,我也不认为需要读取超过 8 个 block 。如果驱动器是 HDD,那么我估计最多需要 80 毫秒来执行查询。同时,我认为 10-20 毫秒是典型的。

所以... 630ms 意味着还有其他事情正在发生。尤其值得怀疑的是任何涉及该表的查询。

(product_id, status) 索引与此查询无关。

UUID 对性能来说非常糟糕,尤其是当索引无法放入 RAM 时。您有多少可用 RAM? innodb_buffer_pool_size 的值是多少?

关于mysql - 事件记录查找 - 尽管添加了索引,find_by_inventory_product_id 仍间歇性缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58155225/

相关文章:

mysql select查询不返回任何内容

mysql - 搜索多个字段mysql的最快方法

ruby-on-rails - 尝试验证日期

java - Hibernate:无法在进程之间查看 MYSQL 中的持久数据

ruby - 如何使用 Ruby 将列标题写入 csv 文件?

ruby-on-rails - 迁移文件名以奇怪的数字开头

mysql - 为什么 MySQL 会选择错误的索引?

C# 在 List<T> 索引处添加值的方法

javascript - 在 Javascript 中获取关联数组的索引

mysql - Windows 7 MySQL 错误 1067 服务无法启动