SlideShare ist ein Scribd-Unternehmen logo
1 von 28
Optimizing Magento
By Preloading Data
Disclaimer
This talk is not about cache optimization or pre-warming
Cache Pitfalls
● Combination of variables that invalidate it
● Slow updates in the backend
● Cache memory usage grows with the catalog size
● Caching onion nightmares
But do we need caching?
How many page parts are cached?
How many page parts are cached?
What’s problem that cache solve?
Top Menu
On each menu item Magento does a call to obtain url of category
Product List
On each configurable product all assigned simple
products are loaded to its calculate price
Load in the Loop (N+1 problem)
Why does it exist in Magento core?
- Introduction of excessive abstractions
- Promotion of singular service access
- System is designed from the bottom up
Can we fix it without modifying core?
- Observe load events on collections of interest
- Load data for related items in the collection
- Create a plugin around a service that triggers
N+1
There is a module for that!
https://github.com/EcomDev/magento2-product-preloader
1. Implement DataLoader interface on your custom service with:
○ isApplicable(string $type) method for deciding if loaded
○ load(ScopeFilter $filter, ProductWrapper[] $products) for loading
related data for a list of product at once
2. Register custom loader as a dependency in di.xml for
LoaderService
3. Use LoadService for accessing data in your plugin with:
○ get(int $productId, string $type) method for accessing data
○ has(int $productId, string $type) method for checking when preload was
done for this product
How to use
Example with configurable products
Target Goal
● Remove load in the loop for the price
retrieval
● Remove load in the loop for the inventory
check
● Achieve below 90 queries on category page with
configurables
● Simple product status is ignored in the
example for simplicity
Loader For Simple Product Prices in Configurable
class ConfigurablePrice implements DataLoader
{
public const DATA_KEY = 'configurable_price';
private ResourceConnection $resourceConnection;
public function __construct(ResourceConnection $resourceConnection)
{
$this->resourceConnection = $resourceConnection;
}
public function load(ScopeFilter $filter, array $products): array
{
/*...*/
}
public function isApplicable(string $type): bool
{
return $type === self::TYPE_LIST;
}
}
Loader For Simple Product Prices in Configurable
public function load(ScopeFilter $filter, array $products): array
{
$configurableProductIds = [];
foreach ($products as $product) {
if ($product->isType(Configurable::TYPE_CODE)) {
$configurableProductIds[] = $product->getId();
}
}
if (!$configurableProductIds) {
return [];
}
$connection = $this->resourceConnection->getConnection('catalog');
$priceIndexTable = $this->resourceConnection->getTableName('catalog_product_index_price','catalog');
$relationTable = $this->resourceConnection->getTableName('catalog_product_super_link','catalog');
/*...*/
}
Loader For Simple Product Prices in Configurable
public function load(ScopeFilter $filter, array $products): array
{
/*...*/
$select = $connection->select()
->from(['index' => $priceIndexTable], [])
->join(['relation' => $relationTable], 'relation.product_id = index.entity_id', [])
->columns([
'entity_id' => 'relation.parent_id',
'price' => 'MIN(index.price)',
'final_price' => 'MIN(index.final_price)',
])
->group('relation.parent_id')
->where('relation.parent_id IN(?)', $configurableProductIds)
->where('index.customer_group_id = ?', $filter->getCustomerGroupId())
->where('index.website_id = ?', $filter->getWebsiteId())
;
return $connection->fetchAssoc($select);
}
Plugin on Price Resolver
class ConfigurablePriceResolverPlugin
{
private LoadService $loadService;
public function __construct(LoadService $loadService)
{
$this->loadService = $loadService;
}
public function aroundResolvePrice(ConfigurablePriceResolver $subject, callable $proceed, SaleableInterface $product)
{
$productId = (int)$product->getId();
if ($this->loadService->has($productId, ConfigurablePrice::DATA_KEY)) {
return (float)($this->loadService->get($productId, ConfigurablePrice::DATA_KEY)['final_price'] ?? 0);
}
return $proceed($product);
}
}
DI configuration
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="EcomDevProductDataPreLoaderDataServiceLoadService">
<arguments>
<argument name="loaders" xsi:type="array">
<item name="configurable_price" xsi:type="object">EcomDevConfigurableProductPreloaderLoaderConfigurablePrice</item>
</argument>
</arguments>
</type>
<type name="MagentoConfigurableProductPricingPriceConfigurablePriceResolver">
<plugin
name="use_preloaded_final_price_of_the_product"
type="EcomDevConfigurableProductPreloaderPluginConfigurablePriceResolverPlugin"
/>
</type>
</config>
See rest of the loaders in the link at the end
So what’s the result?
https://blackfire.io/profiles/compare/6285d4fd-f239-4845-a72a-f596e9d035dc/graph
How about under load?
Key takeaways
- Avoid using cache for data within cached page
- Use single query per set of data
- Disable block_html cache
- Use profiler to find bottlenecks
Future plans
- Make it a plug-and-play module
- Create common preloaders of product data
- MSI qty retrieval for shopping cart and checkout
- FPC identities retrieval for composite products
- Create preloader module for categories
- Rewrite setup:di:compile with higher performance
solution
QA & Links
Example in the slides:
https://github.com/EcomDev/example-preloading-configurable-product
Preloader Library:
https://github.com/EcomDev/magento2-product-preloader
Contacts:
https://ivanchepurnyi.github.io/

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Flask – Python
Flask – PythonFlask – Python
Flask – Python
 
Specificity and CSS Selectors
Specificity and CSS SelectorsSpecificity and CSS Selectors
Specificity and CSS Selectors
 
Front end microservices: architectures and solution
Front end microservices: architectures and solutionFront end microservices: architectures and solution
Front end microservices: architectures and solution
 
Python/Flask Presentation
Python/Flask PresentationPython/Flask Presentation
Python/Flask Presentation
 
Angular Libraries & NPM
 Angular Libraries & NPM Angular Libraries & NPM
Angular Libraries & NPM
 
Python tools to deploy your machine learning models faster
Python tools to deploy your machine learning models fasterPython tools to deploy your machine learning models faster
Python tools to deploy your machine learning models faster
 
JQuery UI
JQuery UIJQuery UI
JQuery UI
 
Broadleaf Presents Thymeleaf
Broadleaf Presents ThymeleafBroadleaf Presents Thymeleaf
Broadleaf Presents Thymeleaf
 
SOLID Design Principles
SOLID Design PrinciplesSOLID Design Principles
SOLID Design Principles
 
What Is Virtual DOM In React JS.pptx
What Is Virtual DOM In React JS.pptxWhat Is Virtual DOM In React JS.pptx
What Is Virtual DOM In React JS.pptx
 
Gradle Introduction
Gradle IntroductionGradle Introduction
Gradle Introduction
 
Javascript
JavascriptJavascript
Javascript
 
angular fundamentals.pdf
angular fundamentals.pdfangular fundamentals.pdf
angular fundamentals.pdf
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 
Django for Beginners
Django for BeginnersDjango for Beginners
Django for Beginners
 
A Deeper look into Javascript Basics
A Deeper look into Javascript BasicsA Deeper look into Javascript Basics
A Deeper look into Javascript Basics
 
React for Beginners
React for BeginnersReact for Beginners
React for Beginners
 
An Intro into webpack
An Intro into webpackAn Intro into webpack
An Intro into webpack
 
javascript objects
javascript objectsjavascript objects
javascript objects
 

Ähnlich wie Optimizing Magento by Preloading Data

Magento Attributes - Fresh View
Magento Attributes - Fresh ViewMagento Attributes - Fresh View
Magento Attributes - Fresh View
Alex Gotgelf
 
Web applications with Catalyst
Web applications with CatalystWeb applications with Catalyst
Web applications with Catalyst
svilen.ivanov
 
Relentless Refactoring
Relentless RefactoringRelentless Refactoring
Relentless Refactoring
Mark Rickerby
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
arcware
 
food,banana,5,200.0food,bread,10,120.0household,toaster,5.docx
food,banana,5,200.0food,bread,10,120.0household,toaster,5.docxfood,banana,5,200.0food,bread,10,120.0household,toaster,5.docx
food,banana,5,200.0food,bread,10,120.0household,toaster,5.docx
budbarber38650
 
Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)
Ivan Chepurnyi
 
Abstracting functionality with centralised content
Abstracting functionality with centralised contentAbstracting functionality with centralised content
Abstracting functionality with centralised content
Michael Peacock
 

Ähnlich wie Optimizing Magento by Preloading Data (20)

Magento Performance Toolkit
Magento Performance ToolkitMagento Performance Toolkit
Magento Performance Toolkit
 
Magento Indexes
Magento IndexesMagento Indexes
Magento Indexes
 
Utilization of zend an ultimate alternate for intense data processing
Utilization of zend  an ultimate alternate for intense data processingUtilization of zend  an ultimate alternate for intense data processing
Utilization of zend an ultimate alternate for intense data processing
 
Magento Attributes - Fresh View
Magento Attributes - Fresh ViewMagento Attributes - Fresh View
Magento Attributes - Fresh View
 
Web applications with Catalyst
Web applications with CatalystWeb applications with Catalyst
Web applications with Catalyst
 
Relentless Refactoring
Relentless RefactoringRelentless Refactoring
Relentless Refactoring
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for Magento
 
Grails EE
Grails EEGrails EE
Grails EE
 
Angular JS2 Training Session #2
Angular JS2 Training Session #2Angular JS2 Training Session #2
Angular JS2 Training Session #2
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin development
 
food,banana,5,200.0food,bread,10,120.0household,toaster,5.docx
food,banana,5,200.0food,bread,10,120.0household,toaster,5.docxfood,banana,5,200.0food,bread,10,120.0household,toaster,5.docx
food,banana,5,200.0food,bread,10,120.0household,toaster,5.docx
 
Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)
 
MeteorJS Meetup
MeteorJS MeetupMeteorJS Meetup
MeteorJS Meetup
 
Abstracting functionality with centralised content
Abstracting functionality with centralised contentAbstracting functionality with centralised content
Abstracting functionality with centralised content
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 

Kürzlich hochgeladen

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Kürzlich hochgeladen (20)

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 

Optimizing Magento by Preloading Data

  • 2. Disclaimer This talk is not about cache optimization or pre-warming
  • 3. Cache Pitfalls ● Combination of variables that invalidate it ● Slow updates in the backend ● Cache memory usage grows with the catalog size ● Caching onion nightmares
  • 4. But do we need caching?
  • 5. How many page parts are cached?
  • 6. How many page parts are cached?
  • 7. What’s problem that cache solve?
  • 8. Top Menu On each menu item Magento does a call to obtain url of category
  • 9. Product List On each configurable product all assigned simple products are loaded to its calculate price
  • 10. Load in the Loop (N+1 problem)
  • 11. Why does it exist in Magento core? - Introduction of excessive abstractions - Promotion of singular service access - System is designed from the bottom up
  • 12. Can we fix it without modifying core? - Observe load events on collections of interest - Load data for related items in the collection - Create a plugin around a service that triggers N+1
  • 13. There is a module for that!
  • 15. 1. Implement DataLoader interface on your custom service with: ○ isApplicable(string $type) method for deciding if loaded ○ load(ScopeFilter $filter, ProductWrapper[] $products) for loading related data for a list of product at once 2. Register custom loader as a dependency in di.xml for LoaderService 3. Use LoadService for accessing data in your plugin with: ○ get(int $productId, string $type) method for accessing data ○ has(int $productId, string $type) method for checking when preload was done for this product How to use
  • 17. Target Goal ● Remove load in the loop for the price retrieval ● Remove load in the loop for the inventory check ● Achieve below 90 queries on category page with configurables ● Simple product status is ignored in the example for simplicity
  • 18. Loader For Simple Product Prices in Configurable class ConfigurablePrice implements DataLoader { public const DATA_KEY = 'configurable_price'; private ResourceConnection $resourceConnection; public function __construct(ResourceConnection $resourceConnection) { $this->resourceConnection = $resourceConnection; } public function load(ScopeFilter $filter, array $products): array { /*...*/ } public function isApplicable(string $type): bool { return $type === self::TYPE_LIST; } }
  • 19. Loader For Simple Product Prices in Configurable public function load(ScopeFilter $filter, array $products): array { $configurableProductIds = []; foreach ($products as $product) { if ($product->isType(Configurable::TYPE_CODE)) { $configurableProductIds[] = $product->getId(); } } if (!$configurableProductIds) { return []; } $connection = $this->resourceConnection->getConnection('catalog'); $priceIndexTable = $this->resourceConnection->getTableName('catalog_product_index_price','catalog'); $relationTable = $this->resourceConnection->getTableName('catalog_product_super_link','catalog'); /*...*/ }
  • 20. Loader For Simple Product Prices in Configurable public function load(ScopeFilter $filter, array $products): array { /*...*/ $select = $connection->select() ->from(['index' => $priceIndexTable], []) ->join(['relation' => $relationTable], 'relation.product_id = index.entity_id', []) ->columns([ 'entity_id' => 'relation.parent_id', 'price' => 'MIN(index.price)', 'final_price' => 'MIN(index.final_price)', ]) ->group('relation.parent_id') ->where('relation.parent_id IN(?)', $configurableProductIds) ->where('index.customer_group_id = ?', $filter->getCustomerGroupId()) ->where('index.website_id = ?', $filter->getWebsiteId()) ; return $connection->fetchAssoc($select); }
  • 21. Plugin on Price Resolver class ConfigurablePriceResolverPlugin { private LoadService $loadService; public function __construct(LoadService $loadService) { $this->loadService = $loadService; } public function aroundResolvePrice(ConfigurablePriceResolver $subject, callable $proceed, SaleableInterface $product) { $productId = (int)$product->getId(); if ($this->loadService->has($productId, ConfigurablePrice::DATA_KEY)) { return (float)($this->loadService->get($productId, ConfigurablePrice::DATA_KEY)['final_price'] ?? 0); } return $proceed($product); } }
  • 22. DI configuration <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="EcomDevProductDataPreLoaderDataServiceLoadService"> <arguments> <argument name="loaders" xsi:type="array"> <item name="configurable_price" xsi:type="object">EcomDevConfigurableProductPreloaderLoaderConfigurablePrice</item> </argument> </arguments> </type> <type name="MagentoConfigurableProductPricingPriceConfigurablePriceResolver"> <plugin name="use_preloaded_final_price_of_the_product" type="EcomDevConfigurableProductPreloaderPluginConfigurablePriceResolverPlugin" /> </type> </config>
  • 23. See rest of the loaders in the link at the end
  • 24. So what’s the result? https://blackfire.io/profiles/compare/6285d4fd-f239-4845-a72a-f596e9d035dc/graph
  • 26. Key takeaways - Avoid using cache for data within cached page - Use single query per set of data - Disable block_html cache - Use profiler to find bottlenecks
  • 27. Future plans - Make it a plug-and-play module - Create common preloaders of product data - MSI qty retrieval for shopping cart and checkout - FPC identities retrieval for composite products - Create preloader module for categories - Rewrite setup:di:compile with higher performance solution
  • 28. QA & Links Example in the slides: https://github.com/EcomDev/example-preloading-configurable-product Preloader Library: https://github.com/EcomDev/magento2-product-preloader Contacts: https://ivanchepurnyi.github.io/