尽管在where子句

时间:2019-10-09 16:29:32

标签: mysql ruby-on-rails indexing rails-activerecord unique-constraint

我有一个简单的新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 语句中的索引。

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

 id select_type      table       type  key                key_len ref rows Extra
 1     SIMPLE inventory_products const 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)上运行

3 个答案:

答案 0 :(得分:0)

我没有看到架构文件中的索引(我认为这是一个架构文件?),只是一个唯一的键引用

再次检查很容易,只需运行rails g migration addIndexToInventoryProductIds。这将使您可以填充一个迁移文件:

class addIndexToInventoryProductIds < ActiveRecord::Migration[5.2]

  def up
    add_index :inventory_products, :inventory_product_id
  end

  def down
    remove_index :inventory_products, :inventory_product_id
  end
end

运行rake db:migrate之后-如果没有错误,则索引不存在。

答案 1 :(得分:0)

您可能需要寻找以下内容,以了解索引性能差的原因。

  • 高交换使用率和较少的可用内存。如果您使用的是RDS,则可以在AWS控制台中轻松获取此数据。由于内存不足,索引表可能会不断从主内存中清除。增加实例RAM或重新考虑应用程序中使用的索引将解决此问题-ref
  • 增加队列深度。您的实例可能在IOPS上达到极限,查询可能受到限制,因此增加了队列深度-在RDS控制台中检查突发平衡以获取更多信息-增加实例的大小或选择提供IOPS可以解决此问题
  • 对表的写操作的规模-如果表正在接受高速率的写操作,则由于索引表需要在插入或更新时进行更新(还要考虑为确保具有唯一索引的列的唯一性而需要进行的锁定),因此需要检查对该表进行写操作的规模。如果这是问题所在,则水平缩放可以是一种解决方案,其中您可以从多个只读副本中读取内容,但只能写入主副本中。

答案 2 :(得分:0)

您有UNIQUE(inventory_product_id),这是查询的最佳索引。

即使在冷的系统上,也不会超过10个磁盘命中次数来获取所需的行。 HDD可能需要100毫秒;在SSD上速度更快。在运行平稳的系统中,大多数块都将缓存在buffer_pool中,因此100ms很少。

如果桌上有其他事情在发生,可能会干扰锁,CPU,I / O等。但是,看到630ms还是很麻烦的。什么是平均值

binary(16)表示您正在使用某种哈希或UUID?这意味着缓存不是很有用,因此您的最小时间为10ms。

innodb_buffer_pool_size的值是什么?你有多少RAM?什么版本的MySQL?