活动记录查找-尽管添加了索引,但find_by_inventory_product_id间歇性地缓慢

时间:2019-09-29 12:29:43

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

我有一个简单的新API端点,该端点涉及查询我的新设置和填充的表-库存产品。

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
....

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

我已经在自己的模式中提到了stock_product_id作为唯一键,并且上述功能触发的MySQL查询使用的是stock_product_id作为以下 explain 语句中的索引。

解释选择inventory_products。*从inventory_productsinventory_productsinventory_product_id = 0x3a288cdce78d44618eadd72e240f26a4限制1

id select_type表的类型可能的键关键字key_len参考行Extra 1个简单的stock_products const uc_inventory_product_id uc_inventory_product_id 17 const 1 NULL

我的模式有问题吗?我是否需要在架构中明确提及stocking_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 个答案:

答案 0 :(得分:0)

这是应该发生的

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

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

即使在非常寒冷的系统上,我也不希望读取超过8个块。如果驱动器是HDD,则我将最长等待80ms来执行查询。同时,我会说典型的时间是10到20毫秒。

所以... 630毫秒表示还有其他事情正在进行。尤其值得怀疑的是,任何查询都会触及该表。

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

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