如何让 Magento 更快地保存产品?
Posted
技术标签:
【中文标题】如何让 Magento 更快地保存产品?【英文标题】:How to make Magento saving product faster? 【发布时间】:2012-09-26 06:55:32 【问题描述】:此行以下的所有内容都已过时。 Magento 很慢,仅此而已。
如https://***.com/questions/12580828/magento-saving-product-is-extremly-slow-but-profiler-shows-it-only-takes-1sec/12583078#12583078中所说,Magento 非常慢
由于缺乏对 HostGator 的 root 权限而苦苦挣扎后,我最终分析了 Magento 调用自己。
这是其中一个结果:
Blue: timing 1982878436 Mage_Sales_Model_mysql4_Quote begin
Mage_Sales_Model_Mysql4_Quote 的save
方法时记录的。
Blue: timing 1982878436 Mage_Sales_Model_Mysql4_Quote 46
数字1982878436
是一个随机数,作为调用的ID 生成。而数字46
是以秒为单位的时间。
2012-09-26T06:36:16+00:00 DEBUG (7): Blue: timing 1982878436 Mage_Sales_Model_Mysql4_Quote begin
2012-09-26T06:36:18+00:00 DEBUG (7): Blue: timing 645597828 Mage_Log_Model_Mysql4_Visitor begin
2012-09-26T06:36:18+00:00 DEBUG (7): Blue: 645597828 Varien_Db_Adapter_Pdo_Mysql
2012-09-26T06:36:18+00:00 DEBUG (7): Blue: timing 645597828 Mage_Log_Model_Mysql4_Visitor 0
2012-09-26T06:36:18+00:00 DEBUG (7): Blue: timing 1712949075 Mage_Sales_Model_Mysql4_Quote begin
2012-09-26T06:36:24+00:00 DEBUG (7): Blue: timing 2103820838 Mage_Sales_Model_Mysql4_Quote begin
2012-09-26T06:36:56+00:00 DEBUG (7): Blue: timing 1999314779 Mage_Log_Model_Mysql4_Visitor begin
2012-09-26T06:36:56+00:00 DEBUG (7): Blue: 1999314779 Varien_Db_Adapter_Pdo_Mysql
2012-09-26T06:36:56+00:00 DEBUG (7): Blue: timing 1999314779 Mage_Log_Model_Mysql4_Visitor 0
2012-09-26T06:36:56+00:00 DEBUG (7): Blue: timing 504509596 Mage_Sales_Model_Mysql4_Quote begin
2012-09-26T06:36:56+00:00 DEBUG (7): Blue: timing 1887845167 Mage_Log_Model_Mysql4_Visitor begin
2012-09-26T06:36:56+00:00 DEBUG (7): Blue: timing 1887845167 Mage_Log_Model_Mysql4_Visitor 0
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: timing 1887308594 Mage_GoogleOptimizer_Model_Mysql4_Code begin
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: timing 1887308594 Mage_GoogleOptimizer_Model_Mysql4_Code 0
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: 504509596 Varien_Db_Adapter_Pdo_Mysql
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: timing 504509596 Mage_Sales_Model_Mysql4_Quote 6
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: 1982878436 Varien_Db_Adapter_Pdo_Mysql
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: timing 1982878436 Mage_Sales_Model_Mysql4_Quote 46
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: 1712949075 Varien_Db_Adapter_Pdo_Mysql
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: timing 1712949075 Mage_Sales_Model_Mysql4_Quote 44
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: 2103820838 Varien_Db_Adapter_Pdo_Mysql
2012-09-26T06:37:02+00:00 DEBUG (7): Blue: timing 2103820838 Mage_Sales_Model_Mysql4_Quote 38
我们可以看到1982878436
、1712949075
、2103820838
是并行调用的,每个都需要几十秒才能完成。我怀疑这三个调用之间存在一些锁定问题,使它们相互等待。有时当我保存产品时,Magento 甚至会报告操作失败,因为 MySQL 由于死锁而失败。
有人对此有任何想法吗?
【问题讨论】:
Magento 的版本是多少? +1 for “Magento 就是慢” ;-) 【参考方案1】:在运行涉及IN
的查询时,MySQL
总是使最外层表领先。
这意味着这个查询:
UPDATE $this->getTable('sales/quote') SET trigger_recollect = 1
WHERE entity_id IN (
SELECT DISTINCT quote_id
FROM $this->getTable('sales/quote_item')
WHERE product_id IN (SELECT DISTINCT product_id FROM $this->getTable('catalogrule/rule_product_price'))
必须扫描sales/quote
中的每条记录,并对照sales/quote_item
进行检查,而sales/quote_item
又必须对照catalogrule/rule_product_price
检查每条匹配的记录。
如果sales/quote
中的记录比子查询返回的记录多得多,这会很慢。
您可能希望将其重写为连接:
UPDATE $this->getTable('catalogrule/rule_product_price') crpp
JOIN $this->getTable('sales/quote_item') sqi
ON sqi.product_id = crpp.product_id
JOIN $this->getTable('sales/quote') sq
ON sq.entity_id = sqi.quote_id
SET sq.trigger_recollect = 1
这样,优化器可以选择哪个表作为前导(当每个连接字段都被索引时,它应该是最小的表)。
【讨论】:
【参考方案2】:最终只是其他查询阻止了这些查询。这个问题有两个主要的放缓。
一个在Mage/Sales/Model/Mysql4/Quote.php,有两个嵌套查询。我既不知道 MySQL 的缓存是如何工作的,也不知道如何在 HostGator 上配置 MySQL,所以我最终自己缓存了查询结果:
public function markQuotesRecollectOnCatalogRules()
/*
$this->_getWriteAdapter()->query("
UPDATE $this->getTable('sales/quote') SET trigger_recollect = 1
WHERE entity_id IN (
SELECT DISTINCT quote_id
FROM $this->getTable('sales/quote_item')
WHERE product_id IN (SELECT DISTINCT product_id FROM $this->getTable('catalogrule/rule_product_price'))
)"
);
*/
$products = $this->_getReadAdapter()->fetchCol("SELECT DISTINCT product_id FROM $this->getTable('catalogrule/rule_product_price')");
$ids = $this->_getReadAdapter()->fetchCol("
SELECT DISTINCT quote_id
FROM $this->getTable('sales/quote_item')
WHERE product_id IN (?)", implode(',', $products)
);
if (count($ids) > 0)
$this->_getWriteAdapter()->query("
UPDATE $this->getTable('sales/quote') SET trigger_recollect = 1
WHERE entity_id IN (?)", implode(',', $ids)
);
和
public function markQuotesRecollect($productIds)
/*
$this->_getWriteAdapter()->query("
UPDATE `$this->getTable('sales/quote')` SET `trigger_recollect` = 1
WHERE `entity_id` IN (
SELECT DISTINCT `quote_id`
FROM `$this->getTable('sales/quote_item')`
WHERE `product_id` IN (?)
)", $productIds
);
*/
$ids = $this->_getReadAdapter()->fetchCol("
SELECT DISTINCT quote_id
FROM $this->getTable('sales/quote_item')
WHERE product_id IN (?)", $productIds
);
if (count($ids) > 0)
$this->_getWriteAdapter()->query("
UPDATE $this->getTable('sales/quote') SET trigger_recollect = 1
WHERE entity_id IN (?)", implode(',', $ids)
);
return $this;
还有 Mage/CatalogRule/Model/Rule.php。在内部,这似乎是一个众所周知的重新索引问题。
public function applyAllRulesToProduct($product)
$this->_getResource()->applyAllRulesForDateRange(NULL, NULL, $product);
$this->_invalidateCache();
/*
$indexProcess = Mage::getSingleton('index/indexer')->getProcessByCode('catalog_product_price');
if ($indexProcess)
$indexProcess->reindexAll();
*/
if ($product instanceof Mage_Catalog_Model_Product)
$id = $product->getId();
else
$id = $product;
if ($id)
$indexer = Mage::getResourceSingleton('catalog/product_indexer_price');
if ($indexer)
$indexer->reindexProductIds(array($id));
我认为让它响应全局设置应该是更好的方法。但是我没有时间,所以我复制了这个解决方案。
【讨论】:
以上是关于如何让 Magento 更快地保存产品?的主要内容,如果未能解决你的问题,请参考以下文章
Magento 2 - 如何让 2 个单独的 phtml 来处理产品列表和产品网格?
Supabase: 一个开源的后端服务,可以让你更快地构建产品