Atualmente, estou tentando melhorar alguns módulos em relação ao desempenho.
Alguns de vocês devem saber o uso do walk()
método na coleta, o que é muito útil para evitar a repetição direta dos produtos.
Além disso, e graças ao @Vinai, também é possível usar o delete()
método de coleta .
Mas notei que os arquivos nativos do Magento 1 nem sempre usam qualquer um desses métodos para exclusão.
Um dos piores códigos que eu já vi é o massDelete()
método no app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php
qual os produtos são carregados em um loop antes da exclusão .
foreach ($productIds as $productId) {
$product = Mage::getSingleton('catalog/product')->load($productId);
Mage::dispatchEvent('catalog_controller_product_delete', array('product' => $product));
$product->delete();
}
Então fiz alguns testes de desempenho, adicionei algumas chamadas de log para verificar o tempo gasto e o uso de memória para exclusão de 100 produtos.
Teste 1: walk
método
Substituí o código original colado acima por este código:
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('entity_id')
->addIdFilter($productIds)
->walk('delete');
E meus resultados são os seguintes no meu servidor de desenvolvimento de baixa qualidade (média com base em 10 testes):
- Código original: 19.97 segundos, 15.84MB usado
- Código personalizado: 17.12 segundos, 15.45MB usado
Portanto, para a exclusão de 100 produtos, meu código personalizado é 3 segundos mais rápido e usa 0,4 MB a menos.
Teste 2: Usando o delete()
método de coleta
Substituí o código original por este:
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('entity_id')
->addIdFilter($productIds)
->delete();
E a mente soprada aqui estão os resultados:
- Código original: 19.97 segundos, 15.84MB usado
- Código personalizado: 1,24 segundos, 6,34 MB usados
Portanto, para a exclusão de 100 produtos, meu código personalizado é 18 segundos mais rápido e usa 9 MB a menos.
Conforme declarado nos comentários, parece que esse método não aciona os eventos Magento (após o carregamento, após a exclusão) nem o fluxo de índice / cache.
Questão
Portanto, minha pergunta é: existe uma razão pela qual a equipe principal do Magento não usou walk('delete')
melhor o delete()
método de coleta ou evento , em vez de carregar produtos em um loop (que todos sabemos que é uma prática muito, muito ruim)?
O objetivo principal é estar ciente desses pontos-chave no caso de um desenvolvimento de módulo: existem casos específicos em que não é possível usar o método walk
/ collection delete()
?
EDIT: o motivo definitivamente não é por causa do catalog_controller_product_delete
envio do evento, pois o mesmo código pode ser encontrado em vários locais (verifique os massDelete
métodos) no núcleo do Magento. Usei o exemplo de produtos para destacar o desempenho, pois geralmente são as maiores entidades
fonte
getSingleton()
como medida de desempenho, em vez do uso óbvio da coleção. Ah, e também é possível disparar o evento com uma coleção, mas não com owalk()
atalho.delete()
faz uma consulta DELETE em vez de carregar a coleção e excluir cada produto. Com isso, você realmente perderá os eventos.Respostas:
Nota lateral, mas você deve usar o Varien Profiler para isso!
Embora eu não duvide que sua alteração melhore o desempenho, seria útil fornecer os resultados "anteriores" para comparar as melhorias.
Bem, sabemos de outras perguntas neste fórum o seguinte:
Portanto, sugiro que o exemplo que você encontrou seja provavelmente um dos muitos itens escondidos no código que foram escritos há muito tempo e / ou por um desenvolvedor menos experiente. Como grande parte do código principal (e do código da comunidade!), Ele teria sido testado em um pequeno conjunto de dados e não testado em batalha; portanto, o desempenho pode não ter sido monitorado de perto.
Sua melhoria é benéfica e está mais alinhada às melhores práticas do que o código original? Sim. Você, como desenvolvedor da comunidade Magento [1.x], no entanto, não tem capacidade de contribuir com melhorias sugeridas, como você faz com o Magento 2, então minha sugestão seria implementar isso em um módulo local se você precisar para desempenho em uma de suas lojas. , ou ignore-o se não estiver afetando você, mas você percebeu isso ao fazer alguma pesquisa.
Como uma atualização para a edição da sua pergunta, tenho certeza de que você sabe que o método walk em Varien_Data_Collection aceita um retorno de chamada arbitrário; portanto, você pode usá-lo para qualquer coisa que desejar. Para despachar o evento no exemplo original, você pode fazer isso com a função walk, bem como com a exclusão.
A única razão pela qual eu poderia imaginar que seria útil carregar o produto antes de excluí-lo pode ser que os observadores conectados a esse evento possam precisar de um conjunto de dados completo não disponível sem antes carregar o produto. Se for esse o caso, explicaria por que eles usam um singleton em vez de um modelo para minimizar pelo menos as despesas gerais do objeto.
fonte
Meu pensamento é que eles estão fazendo isso para disparar o
catalog_controller_product_delete
evento que está sendo usado pelo Mage_Tag.catalog_product_delete_before
oucatalog_product_delete_after
significaria que isso era desnecessário, embora eu pensasse. Pergunto-me se esse evento específico também é usado para o log de ações do administrador.fonte
massDelete()
ação doCustomerController.php
Acho que a exclusão em massa deve funcionar como excluir um único produto (totalmente carregado).
Para
$collection->delete()
a resposta já está dada. Se você não acionardeleter_before
,delete_after
eu poderia quebrar algumas extensões e ignorar alguns observadores usados no núcleo.$collection->walk('delete')
possivelmente funcionaria, mas ainda tem a desvantagem de que os dados do produto não estão completos. Isso também pode interromper observadores personalizados se eles confiarem em dados adicionais, por exemplo, objeto de item de estoque.Eu acho que, se você alterar
->addAttributeToSelect('entity_id')
a->addAttributeToSelect('*')
e adicione->setFlag('require_stock_items', true)
(para adicionar dados de estoque para produtos) não terá um desempenho melhor, em seguida, "loop-exclusão".Parece um estilo ruim, mas acho que é certo para ambas as ações de exclusão em massa.
Também uso
walk()
edelete()
para modelos personalizados, mas sei que não há observadores ouentity_id
é suficiente. Apenas para mencionar,walk()
funcionaria com todos os eventos usados no núcleo, porque eles usam apenas$product->getId()
, mas você não conhece observadores de terceiros.fonte