我有一个简单的新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)上运行答案 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)
您可能需要寻找以下内容,以了解索引性能差的原因。
答案 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?