我们最近将Magento应用程序从私有主机迁移到AWS Web服务。我们注意到Magento的一些内部功能在迁移后执行的时间过长,因此开始调查。
其中一个查询是一个简单的客户选择查询,对属性表有大约9-10个常规联接以获取属性。
我们对查询进行了一些测试,发现旧主机和AWS之间的区别在于旧主机上,MySQL优化器似乎使用正确的索引,而在AWS中,它使用filesort,忽略了索引。
Using FORCE INDEX(index_name)
使得查询在AWS中正确执行,但是我们不想走这条路,宁愿在数据库配置中修复问题而不是make manual hacks throughout our Magento application。要清楚this is not an issue with our indexes,它们设置正确。
背景:
FORCE INDEX()
强制RDS的行为方式与旧主机相同时旧的MySQL服务器运行的版本为 5.1.61 ,我们运行的AWS RDS实例位于 5.6.19 。一个咨询小组向我们建议我们将我们的RDS实例降级到5.1.61,但是我们再也不想这样做,因为它不是一个可持续的解决方案。
有问题的查询如下(为了空间而从select中删除字段缩短了):
SELECT
`e`.*
-- various field names here, removed
FROM `customer_entity` AS `e`
LEFT JOIN `customer_entity_int` AS `at_default_billing` ON (`at_default_billing`.`entity_id` = `e`.`entity_id`) AND (`at_default_billing`.`attribute_id` = '13')
LEFT JOIN `customer_address_entity_varchar` AS `at_billing_postcode` ON (`at_billing_postcode`.`entity_id` = `at_default_billing`.`value`) AND (`at_billing_postcode`.`attribute_id` = '30')
LEFT JOIN `customer_address_entity_varchar` AS `at_billing_city` ON (`at_billing_city`.`entity_id` = `at_default_billing`.`value`) AND (`at_billing_city`.`attribute_id` = '26')
LEFT JOIN `customer_address_entity_varchar` AS `at_billing_telephone` ON (`at_billing_telephone`.`entity_id` = `at_default_billing`.`value`) AND (`at_billing_telephone`.`attribute_id` = '31')
LEFT JOIN `customer_address_entity_varchar` AS `at_billing_regione` ON (`at_billing_regione`.`entity_id` = `at_default_billing`.`value`) AND (`at_billing_regione`.`attribute_id` = '28')
LEFT JOIN `customer_address_entity_varchar` AS `at_billing_country_id` ON (`at_billing_country_id`.`entity_id` = `at_default_billing`.`value`) AND (`at_billing_country_id`.`attribute_id` = '27')
LEFT JOIN `core_store` AS `at_store_name` ON (at_store_name.`store_id`=e.store_id)
LEFT JOIN `customer_entity_varchar` AS `firstname` ON e.entity_id = firstname.entity_id AND firstname.attribute_id = 5
LEFT JOIN `customer_entity_varchar` AS `lastname` ON e.entity_id = lastname.entity_id AND lastname.attribute_id = 7
WHERE (`e`.`entity_type_id` = '1')
ORDER BY `e`.`entity_id`
DESC LIMIT 20;
以下EXPLAIN
此查询时服务器之间差异的摘要:
RDS - MySQL v5.6.19:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: e
type: ref
possible_keys: IDX_CUSTOMER_ENTITY_ENTITY_TYPE_ID
key: IDX_CUSTOMER_ENTITY_ENTITY_TYPE_ID
key_len: 2
ref: const
rows: 653990
Extra: Using temporary; Using filesort
旧主机 - MySQL v5.1.61,或者在RDS上使用FORCE INDEX
时:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: e
type: ref
possible_keys: IDX_CUSTOMER_ENTITY_ENTITY_TYPE_ID
key: IDX_CUSTOMER_ENTITY_ENTITY_TYPE_ID
key_len: 2
ref: const
rows: 644775
Extra: Using where
我意识到这些数据库版本的差异很可能改变了查询优化器的工作方式,而且我不知道这些版本的差异是什么,但是我正在寻找能够帮助我们解决这些差异的解决方案。
编辑:这里是RDS的比较列表,其中列出了从旧主机复制的参数与此MySQL版本的默认参数。这些参数都没有影响上面的结果是否存在或者我是否在RDS中使用了标准参数:
答案 0 :(得分:1)
我的赌注是关于MySQL conf:
答案 1 :(得分:1)
查看您提供的查询,看起来可能被Bug #74030阻止。修补程序是为更高版本(5.6.20和5.7.4)提供的,但尚未应用,查看release notes。登录并为该错误投票可能会很好。
就目前而言,尽管我很痛苦,但您的顾问小组可能是正确的(可能是偶然的)..直到补丁被应用为止。
答案 2 :(得分:0)
这看起来像文档中提到的关于优化器无法找出正确索引的情况,因为用于选择数据的密钥与用于对数据进行排序的密钥不同。
我无法对版本之间的任何变化发表意见,但以下是与此案例相关的模糊内容:
在某些情况下,MySQL无法使用索引来解析ORDER BY,尽管它仍然使用索引来查找与WHERE子句匹配的行。这些案例包括以下内容:
用于获取行的键与ORDER BY中使用的键不同:
SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
以下是documentation的问题,它提供了一些纠正措施的建议。我不确定你已尝试过什么。