我有一个简单的新 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)上运行
最佳答案
这是应该发生的事情:
优化器将决定使用唯一键。这意味着将有零行或一行具有该值。
- 向下钻取 BTree(3-4 层深)以查找 [inventory_product_id, id] 的索引行
- (假设找到一行),使用
id
向下钻取数据 BTree(可能深 4 层)。 - 提取该行的所有列(因为您说过
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/