SlideShare a Scribd company logo
How to import 1 million SKUs
in under 10 minutes
1/26
Building an import correctly is hard
2/26
2008
it all started with
DataFlow
3/26
DataFlow
4/26
DataFlow
Stores CSV
records into
database
4/26
DataFlow
Stores CSV
records into
database
Imports product
by product via
AJAX call
4/26
DataFlow
Stores CSV
records into
database
Imports product
by product via
AJAX call
Uses product
model to save
data
4/26
DataFlow
Stores CSV
records into
database
Imports product
by product via
AJAX call
Uses product
model to save
data
Closing the
browser window
stops the whole
process
4/26
Speed
2-3 products per second
5/26
Speed
2-3 products per second
~ 20 minutes for 5k products
5/26
2011
Import/Export saved us all
6/26
ImportExport
7/26
ImportExport
Stored batches of
data into the
database during
validation
7/26
ImportExport
Stored batches of
data into the
database during
validation
Processes stored
data in one HTTP
request
7/26
ImportExport
Stored batches of
data into the
database during
validation
Processes stored
data in one HTTP
request
Validates product
data without using
product model
7/26
ImportExport
Stored batches of
data into the
database during
validation
Processes stored
data in one HTTP
request
Validates product
data without using
product model
Uses multi-row
inserts to
populate tables
7/26
ImportExport
Stored batches of
data into the
database during
validation
Processes stored
data in one HTTP
request
Validates product
data without using
product model
Uses multi-row
inserts to
populate tables
Does not run
indexers
7/26
Speed
41 product per second
8/26
Speed
41 product per second
~ 2 minutes for 5k products
8/26
But there are some
drawbacks
9/26
High memory usage on large datasets
But there are some
drawbacks
9/26
High memory usage on large datasets
Slow in generating primary keys for new products
But there are some
drawbacks
9/26
2015
Magento 2.x
Import Export
10/26
ImportExport M2
11/26
Same base functionality as in M1
ImportExport M2
11/26
Same base functionality as in M1
More complex file format to edit and parse
ImportExport M2
11/26
Same base functionality as in M1
More complex file format to edit and parse
Slower on complex product data
ImportExport M2
11/26
Same base functionality as in M1
More complex file format to edit and parse
Slower on complex product data
Adds additional single statement inserts
ImportExport M2
11/26
2019
I got an idea and a project to implement it on
12/26
Separate Feeds
13/26
Separate Feeds
Main entity (sku, type, set)
13/26
Separate Feeds
Main entity (sku, type, set)
Attributes (sku, attribute, store, value)
13/26
Separate Feeds
Main entity (sku, type, set)
Attributes (sku, attribute, store, value)
Category (sku, category slug, position)
13/26
Separate Feeds
Main entity (sku, type, set)
Attributes (sku, attribute, store, value)
Category (sku, category slug, position)
Configurable Options (sku, attribute, label)
13/26
Separate Feeds
Main entity (sku, type, set)
Attributes (sku, attribute, store, value)
Category (sku, category slug, position)
Configurable Options (sku, attribute, label)
Images (sku, image)
13/26
Separate Feeds
Main entity (sku, type, set)
Attributes (sku, attribute, store, value)
Category (sku, category slug, position)
Configurable Options (sku, attribute, label)
Images (sku, image)
...
13/26
Lazy Entity Resolving
14/26
Lazy Entity Resolving
Reduce memory requirements of the import
14/26
Lazy Entity Resolving
Reduce memory requirements of the import
Cleaner and more readable feed processing
14/26
Lazy Entity Resolving
Reduce memory requirements of the import
Cleaner and more readable feed processing
Possibility of acquiring entity ids in batches
automatically
14/26
Lazy Entity Resolving
$resolver = $this->resolverFactory->createSingleValueResolver(
'catalog_product_entity', 'sku', 'entity_id'
);
 
$insert = InsertOnDuplicate::create(
'catalog_product_entity_varchar',
['entity_id', 'attribute_id', 'store_id', 'value']
)->withResolver($resolver);
 
$insert
->withRow($resolver->unresolved('sku1'), 1, 0, 'some value')
->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1')
->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2');
15/26
Configure table lookup information
Lazy Entity Resolving
$resolver = $this->resolverFactory->createSingleValueResolver(
'catalog_product_entity', 'sku', 'entity_id'
);
 
$insert = InsertOnDuplicate::create(
'catalog_product_entity_varchar',
['entity_id', 'attribute_id', 'store_id', 'value']
)->withResolver($resolver);
 
$insert
->withRow($resolver->unresolved('sku1'), 1, 0, 'some value')
->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1')
->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2');
15/26
Pass resolver into insert builder
Lazy Entity Resolving
$insert = InsertOnDuplicate::create(
'catalog_product_entity_varchar',
['entity_id', 'attribute_id', 'store_id', 'value']
)->withResolver($resolver);
$resolver = $this->resolverFactory->createSingleValueResolver(
'catalog_product_entity', 'sku', 'entity_id'
);
 
 
$insert
->withRow($resolver->unresolved('sku1'), 1, 0, 'some value')
->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1')
->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2');
15/26
Use resolver to create identifier containers
Lazy Entity Resolving
->withRow($resolver->unresolved('sku1'), 1, 0, 'some value')
->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1')
->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2');
$resolver = $this->resolverFactory->createSingleValueResolver(
'catalog_product_entity', 'sku', 'entity_id'
);
 
$insert = InsertOnDuplicate::create(
'catalog_product_entity_varchar',
['entity_id', 'attribute_id', 'store_id', 'value']
)->withResolver($resolver);
 
$insert
15/26
Insert on duplicate will skip any unresolved entries
Lazy Entity Resolving
$resolver = $this->resolverFactory->createSingleValueResolver(
'catalog_product_entity', 'sku', 'entity_id'
);
 
$insert = InsertOnDuplicate::create(
'catalog_product_entity_varchar',
['entity_id', 'attribute_id', 'store_id', 'value']
)->withResolver($resolver);
 
$insert
->withRow($resolver->unresolved('sku1'), 1, 0, 'some value')
->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1')
->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2');
15/26
16/26
Batch auto-increment generation
START TRANSACTION;
 
INSERT INTO catalog_product_entity (sku)
VALUES
('sku1'),
('sku2'),
('sku3'),
('sku4');
 
SELECT entity_id, sku
FROM catalog_product_entity
WHERE
sku IN ('sku1', 'sku2', 'sku3', 'sku4');
 
ROLLBACK;
17/26
Start a transaction
Batch auto-increment generation
START TRANSACTION;
 
INSERT INTO catalog_product_entity (sku)
VALUES
('sku1'),
('sku2'),
('sku3'),
('sku4');
 
SELECT entity_id, sku
FROM catalog_product_entity
WHERE
sku IN ('sku1', 'sku2', 'sku3', 'sku4');
 
ROLLBACK;
17/26
Populate table with un-resolved keys
Batch auto-increment generation
 
INSERT INTO catalog_product_entity (sku)
VALUES
('sku1'),
('sku2'),
('sku3'),
('sku4');
 
START TRANSACTION;
SELECT entity_id, sku
FROM catalog_product_entity
WHERE
sku IN ('sku1', 'sku2', 'sku3', 'sku4');
 
ROLLBACK;
17/26
Retrieve new identifiers
Batch auto-increment generation
SELECT entity_id, sku
FROM catalog_product_entity
WHERE
sku IN ('sku1', 'sku2', 'sku3', 'sku4');
 
START TRANSACTION;
 
INSERT INTO catalog_product_entity (sku)
VALUES
('sku1'),
('sku2'),
('sku3'),
('sku4');
 
ROLLBACK;
17/26
Rollback transaction
Batch auto-increment generation
ROLLBACK;
START TRANSACTION;
 
INSERT INTO catalog_product_entity (sku)
VALUES
('sku1'),
('sku2'),
('sku3'),
('sku4');
 
SELECT entity_id, sku
FROM catalog_product_entity
WHERE
sku IN ('sku1', 'sku2', 'sku3', 'sku4');
 
17/26
Prepared Statements
18/26
Compile query for constant batch size
Prepared Statements
18/26
Compile query for constant batch size
Send only data instead of generating new queries
Prepared Statements
18/26
Compile query for constant batch size
Send only data instead of generating new queries
Reduces query processing on MySQL side by half
Prepared Statements
18/26
Speed
450 products per second
19/26
Speed
450 products per second
~ 11 seconds for 5k products
19/26
But it was still not good enough
20/26
But it was still not good enough
45 minutes to import 1 million SKUs
20/26
Sure, because it's a sequential process...
21/26
So I made it asynchronous as PoC
22/26
Under the hood
23/26
Under the hood
Each target tabletarget table receives a separate connection
to MySQL
23/26
Under the hood
Each target tabletarget table receives a separate connection
to MySQL
Identity resolver is attached to the source table
connection
23/26
Under the hood
Each target tabletarget table receives a separate connection
to MySQL
Identity resolver is attached to the source table
connection
Each feed is processed concurrently by using
round robinround robin strategy
23/26
Under the hood
Each target tabletarget table receives a separate connection
to MySQL
Identity resolver is attached to the source table
connection
Each feed is processed concurrently by using
round robinround robin strategy
During MySQL query execution PHP prepares the
next batch
23/26
Speed
1,850 products per second
24/26
Speed
1,850 products per second
~ 9 minutes for 1m products
24/26
It is coming this fall as an open source tool for
everyone!
25/26
Questions
ivan@ecomdev.org
IvanChepurnyi.GitHub.io
26/26

More Related Content

What's hot

CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...
CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...
CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...
Giorgio Carbone
 
quadrotor
quadrotor quadrotor
quadrotor
doukhioualid
 
Dssg talk CNN intro
Dssg talk CNN introDssg talk CNN intro
Dssg talk CNN intro
Vincent Tatan
 
Ener1 - CM4 - Distribution électrique
Ener1 - CM4 - Distribution électriqueEner1 - CM4 - Distribution électrique
Ener1 - CM4 - Distribution électrique
Pierre Maréchal
 
Mopcon 2021 Scrum 是新的死亡行軍嗎?
Mopcon 2021   Scrum 是新的死亡行軍嗎?Mopcon 2021   Scrum 是新的死亡行軍嗎?
Mopcon 2021 Scrum 是新的死亡行軍嗎?
Jen-Chieh Ko
 
Abnormal activity detection in surveillance video scenes
Abnormal activity detection in surveillance video scenesAbnormal activity detection in surveillance video scenes
Abnormal activity detection in surveillance video scenes
TELKOMNIKA JOURNAL
 
Deep Learning Hardware: Past, Present, & Future
Deep Learning Hardware: Past, Present, & FutureDeep Learning Hardware: Past, Present, & Future
Deep Learning Hardware: Past, Present, & Future
Rouyun Pan
 
生產與作業管理
生產與作業管理生產與作業管理
生產與作業管理5045033
 
28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si
28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si
28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si
Aleš Vidmar
 
Le portrait de ma grand mere
Le portrait de ma grand mereLe portrait de ma grand mere
Le portrait de ma grand mereAndrey Kuznetsov
 
Probability Concepts
Probability ConceptsProbability Concepts
Probability Concepts
ConflagratioNal Jahid
 
MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...
MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...
MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...
Stephen Aylward
 
Ch1 circuits logiques_p3_combinatoire-v1
Ch1 circuits logiques_p3_combinatoire-v1Ch1 circuits logiques_p3_combinatoire-v1
Ch1 circuits logiques_p3_combinatoire-v1linuxscout
 

What's hot (13)

CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...
CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...
CXR-ACGAN: Auxiliary Classifier GAN for Conditional Generation of Chest X-Ray...
 
quadrotor
quadrotor quadrotor
quadrotor
 
Dssg talk CNN intro
Dssg talk CNN introDssg talk CNN intro
Dssg talk CNN intro
 
Ener1 - CM4 - Distribution électrique
Ener1 - CM4 - Distribution électriqueEner1 - CM4 - Distribution électrique
Ener1 - CM4 - Distribution électrique
 
Mopcon 2021 Scrum 是新的死亡行軍嗎?
Mopcon 2021   Scrum 是新的死亡行軍嗎?Mopcon 2021   Scrum 是新的死亡行軍嗎?
Mopcon 2021 Scrum 是新的死亡行軍嗎?
 
Abnormal activity detection in surveillance video scenes
Abnormal activity detection in surveillance video scenesAbnormal activity detection in surveillance video scenes
Abnormal activity detection in surveillance video scenes
 
Deep Learning Hardware: Past, Present, & Future
Deep Learning Hardware: Past, Present, & FutureDeep Learning Hardware: Past, Present, & Future
Deep Learning Hardware: Past, Present, & Future
 
生產與作業管理
生產與作業管理生產與作業管理
生產與作業管理
 
28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si
28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si
28 let uspešnega delovanja Yaskawe v Sloveniji, dr. Hubert Kosler Lovedigital.si
 
Le portrait de ma grand mere
Le portrait de ma grand mereLe portrait de ma grand mere
Le portrait de ma grand mere
 
Probability Concepts
Probability ConceptsProbability Concepts
Probability Concepts
 
MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...
MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...
MONAI: Medical imaging AI for data scientists and developers @ 3D Slicer Proj...
 
Ch1 circuits logiques_p3_combinatoire-v1
Ch1 circuits logiques_p3_combinatoire-v1Ch1 circuits logiques_p3_combinatoire-v1
Ch1 circuits logiques_p3_combinatoire-v1
 

Similar to How to import 1 million SKUs in under 10 minutes

SQL Server - Full text search
SQL Server - Full text searchSQL Server - Full text search
SQL Server - Full text search
Peter Gfader
 
Scale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App FabricScale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App Fabric
Chris Dufour
 
MET CS 669 Database Design and Implementation for BusinessLab .docx
MET CS 669 Database Design and Implementation for BusinessLab .docxMET CS 669 Database Design and Implementation for BusinessLab .docx
MET CS 669 Database Design and Implementation for BusinessLab .docx
buffydtesurina
 
KSQL - Stream Processing simplified!
KSQL - Stream Processing simplified!KSQL - Stream Processing simplified!
KSQL - Stream Processing simplified!
Guido Schmutz
 
Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)
GOG.com dev team
 
Xml4js pentaho
Xml4js pentahoXml4js pentaho
Xml4js pentaho
Roland Bouman
 
Microsoft Windows Server AppFabric
Microsoft Windows Server AppFabricMicrosoft Windows Server AppFabric
Microsoft Windows Server AppFabric
Mark Ginnebaugh
 
Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...
Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...
Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...
Codemotion
 
Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016
Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016
Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016
Luigi Dell'Aquila
 
MySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELKMySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELK
YoungHeon (Roy) Kim
 
Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...
Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...
Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...
Trivadis
 
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should KnowDBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
Alex Zaballa
 
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should KnowDBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
Alex Zaballa
 
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should KnowDBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
Alex Zaballa
 
Oracle 10g Performance: chapter 00 sampling
Oracle 10g Performance: chapter 00 samplingOracle 10g Performance: chapter 00 sampling
Oracle 10g Performance: chapter 00 sampling
Kyle Hailey
 
Pieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React NativePieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React Native
tlv-ios-dev
 
What's new in Cassandra 2.0
What's new in Cassandra 2.0What's new in Cassandra 2.0
What's new in Cassandra 2.0
iamaleksey
 
Tony jambu (obscure) tools of the trade for tuning oracle sq ls
Tony jambu   (obscure) tools of the trade for tuning oracle sq lsTony jambu   (obscure) tools of the trade for tuning oracle sq ls
Tony jambu (obscure) tools of the trade for tuning oracle sq ls
InSync Conference
 
Overview of Oracle database12c for developers
Overview of Oracle database12c for developersOverview of Oracle database12c for developers
Overview of Oracle database12c for developers
Getting value from IoT, Integration and Data Analytics
 
Introduction to Oracle Database.pptx
Introduction to Oracle Database.pptxIntroduction to Oracle Database.pptx
Introduction to Oracle Database.pptx
SiddhantBhardwaj26
 

Similar to How to import 1 million SKUs in under 10 minutes (20)

SQL Server - Full text search
SQL Server - Full text searchSQL Server - Full text search
SQL Server - Full text search
 
Scale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App FabricScale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App Fabric
 
MET CS 669 Database Design and Implementation for BusinessLab .docx
MET CS 669 Database Design and Implementation for BusinessLab .docxMET CS 669 Database Design and Implementation for BusinessLab .docx
MET CS 669 Database Design and Implementation for BusinessLab .docx
 
KSQL - Stream Processing simplified!
KSQL - Stream Processing simplified!KSQL - Stream Processing simplified!
KSQL - Stream Processing simplified!
 
Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)
 
Xml4js pentaho
Xml4js pentahoXml4js pentaho
Xml4js pentaho
 
Microsoft Windows Server AppFabric
Microsoft Windows Server AppFabricMicrosoft Windows Server AppFabric
Microsoft Windows Server AppFabric
 
Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...
Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...
Geospatial Graphs made easy with OrientDB - Luigi Dell'Aquila - Codemotion Mi...
 
Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016
Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016
Geospatial Graphs made easy with OrientDB - Codemotion Milan 2016
 
MySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELKMySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELK
 
Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...
Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...
Trivadis TechEvent 2016 Useful Oracle 12c Features for Data Warehousing by Da...
 
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should KnowDBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
 
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should KnowDBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
 
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should KnowDBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
DBA Brasil 1.0 - DBA Commands and Concepts That Every Developer Should Know
 
Oracle 10g Performance: chapter 00 sampling
Oracle 10g Performance: chapter 00 samplingOracle 10g Performance: chapter 00 sampling
Oracle 10g Performance: chapter 00 sampling
 
Pieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React NativePieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React Native
 
What's new in Cassandra 2.0
What's new in Cassandra 2.0What's new in Cassandra 2.0
What's new in Cassandra 2.0
 
Tony jambu (obscure) tools of the trade for tuning oracle sq ls
Tony jambu   (obscure) tools of the trade for tuning oracle sq lsTony jambu   (obscure) tools of the trade for tuning oracle sq ls
Tony jambu (obscure) tools of the trade for tuning oracle sq ls
 
Overview of Oracle database12c for developers
Overview of Oracle database12c for developersOverview of Oracle database12c for developers
Overview of Oracle database12c for developers
 
Introduction to Oracle Database.pptx
Introduction to Oracle Database.pptxIntroduction to Oracle Database.pptx
Introduction to Oracle Database.pptx
 

More from Ivan Chepurnyi

Optimizing Magento by Preloading Data
Optimizing Magento by Preloading DataOptimizing Magento by Preloading Data
Optimizing Magento by Preloading Data
Ivan Chepurnyi
 
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Ivan Chepurnyi
 
Varnish Cache and its usage in the real world!
Varnish Cache and its usage in the real world!Varnish Cache and its usage in the real world!
Varnish Cache and its usage in the real world!
Ivan Chepurnyi
 
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
 
Hidden Secrets of Magento Price Rules
Hidden Secrets of Magento Price RulesHidden Secrets of Magento Price Rules
Hidden Secrets of Magento Price Rules
Ivan Chepurnyi
 
Magento 2.0: Prepare yourself for a new way of module development
Magento 2.0: Prepare yourself for a new way of module developmentMagento 2.0: Prepare yourself for a new way of module development
Magento 2.0: Prepare yourself for a new way of module development
Ivan Chepurnyi
 
Magento Indexes
Magento IndexesMagento Indexes
Magento Indexes
Ivan Chepurnyi
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for Magento
Ivan Chepurnyi
 

More from Ivan Chepurnyi (8)

Optimizing Magento by Preloading Data
Optimizing Magento by Preloading DataOptimizing Magento by Preloading Data
Optimizing Magento by Preloading Data
 
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
 
Varnish Cache and its usage in the real world!
Varnish Cache and its usage in the real world!Varnish Cache and its usage in the real world!
Varnish Cache and its usage in the real world!
 
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)
 
Hidden Secrets of Magento Price Rules
Hidden Secrets of Magento Price RulesHidden Secrets of Magento Price Rules
Hidden Secrets of Magento Price Rules
 
Magento 2.0: Prepare yourself for a new way of module development
Magento 2.0: Prepare yourself for a new way of module developmentMagento 2.0: Prepare yourself for a new way of module development
Magento 2.0: Prepare yourself for a new way of module development
 
Magento Indexes
Magento IndexesMagento Indexes
Magento Indexes
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for Magento
 

Recently uploaded

National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
Building RAG with self-deployed Milvus vector database and Snowpark Container...
Building RAG with self-deployed Milvus vector database and Snowpark Container...Building RAG with self-deployed Milvus vector database and Snowpark Container...
Building RAG with self-deployed Milvus vector database and Snowpark Container...
Zilliz
 
“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”
Claudio Di Ciccio
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
Rohit Gautam
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
Neo4j
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
SOFTTECHHUB
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
Kumud Singh
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
James Anderson
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
DianaGray10
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
SOFTTECHHUB
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 

Recently uploaded (20)

National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
Building RAG with self-deployed Milvus vector database and Snowpark Container...
Building RAG with self-deployed Milvus vector database and Snowpark Container...Building RAG with self-deployed Milvus vector database and Snowpark Container...
Building RAG with self-deployed Milvus vector database and Snowpark Container...
 
“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 

How to import 1 million SKUs in under 10 minutes

  • 1. How to import 1 million SKUs in under 10 minutes 1/26
  • 2. Building an import correctly is hard 2/26
  • 3. 2008 it all started with DataFlow 3/26
  • 6. DataFlow Stores CSV records into database Imports product by product via AJAX call 4/26
  • 7. DataFlow Stores CSV records into database Imports product by product via AJAX call Uses product model to save data 4/26
  • 8. DataFlow Stores CSV records into database Imports product by product via AJAX call Uses product model to save data Closing the browser window stops the whole process 4/26
  • 10. Speed 2-3 products per second ~ 20 minutes for 5k products 5/26
  • 13. ImportExport Stored batches of data into the database during validation 7/26
  • 14. ImportExport Stored batches of data into the database during validation Processes stored data in one HTTP request 7/26
  • 15. ImportExport Stored batches of data into the database during validation Processes stored data in one HTTP request Validates product data without using product model 7/26
  • 16. ImportExport Stored batches of data into the database during validation Processes stored data in one HTTP request Validates product data without using product model Uses multi-row inserts to populate tables 7/26
  • 17. ImportExport Stored batches of data into the database during validation Processes stored data in one HTTP request Validates product data without using product model Uses multi-row inserts to populate tables Does not run indexers 7/26
  • 18. Speed 41 product per second 8/26
  • 19. Speed 41 product per second ~ 2 minutes for 5k products 8/26
  • 20. But there are some drawbacks 9/26
  • 21. High memory usage on large datasets But there are some drawbacks 9/26
  • 22. High memory usage on large datasets Slow in generating primary keys for new products But there are some drawbacks 9/26
  • 25. Same base functionality as in M1 ImportExport M2 11/26
  • 26. Same base functionality as in M1 More complex file format to edit and parse ImportExport M2 11/26
  • 27. Same base functionality as in M1 More complex file format to edit and parse Slower on complex product data ImportExport M2 11/26
  • 28. Same base functionality as in M1 More complex file format to edit and parse Slower on complex product data Adds additional single statement inserts ImportExport M2 11/26
  • 29. 2019 I got an idea and a project to implement it on 12/26
  • 31. Separate Feeds Main entity (sku, type, set) 13/26
  • 32. Separate Feeds Main entity (sku, type, set) Attributes (sku, attribute, store, value) 13/26
  • 33. Separate Feeds Main entity (sku, type, set) Attributes (sku, attribute, store, value) Category (sku, category slug, position) 13/26
  • 34. Separate Feeds Main entity (sku, type, set) Attributes (sku, attribute, store, value) Category (sku, category slug, position) Configurable Options (sku, attribute, label) 13/26
  • 35. Separate Feeds Main entity (sku, type, set) Attributes (sku, attribute, store, value) Category (sku, category slug, position) Configurable Options (sku, attribute, label) Images (sku, image) 13/26
  • 36. Separate Feeds Main entity (sku, type, set) Attributes (sku, attribute, store, value) Category (sku, category slug, position) Configurable Options (sku, attribute, label) Images (sku, image) ... 13/26
  • 38. Lazy Entity Resolving Reduce memory requirements of the import 14/26
  • 39. Lazy Entity Resolving Reduce memory requirements of the import Cleaner and more readable feed processing 14/26
  • 40. Lazy Entity Resolving Reduce memory requirements of the import Cleaner and more readable feed processing Possibility of acquiring entity ids in batches automatically 14/26
  • 41. Lazy Entity Resolving $resolver = $this->resolverFactory->createSingleValueResolver( 'catalog_product_entity', 'sku', 'entity_id' );   $insert = InsertOnDuplicate::create( 'catalog_product_entity_varchar', ['entity_id', 'attribute_id', 'store_id', 'value'] )->withResolver($resolver);   $insert ->withRow($resolver->unresolved('sku1'), 1, 0, 'some value') ->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1') ->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2'); 15/26
  • 42. Configure table lookup information Lazy Entity Resolving $resolver = $this->resolverFactory->createSingleValueResolver( 'catalog_product_entity', 'sku', 'entity_id' );   $insert = InsertOnDuplicate::create( 'catalog_product_entity_varchar', ['entity_id', 'attribute_id', 'store_id', 'value'] )->withResolver($resolver);   $insert ->withRow($resolver->unresolved('sku1'), 1, 0, 'some value') ->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1') ->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2'); 15/26
  • 43. Pass resolver into insert builder Lazy Entity Resolving $insert = InsertOnDuplicate::create( 'catalog_product_entity_varchar', ['entity_id', 'attribute_id', 'store_id', 'value'] )->withResolver($resolver); $resolver = $this->resolverFactory->createSingleValueResolver( 'catalog_product_entity', 'sku', 'entity_id' );     $insert ->withRow($resolver->unresolved('sku1'), 1, 0, 'some value') ->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1') ->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2'); 15/26
  • 44. Use resolver to create identifier containers Lazy Entity Resolving ->withRow($resolver->unresolved('sku1'), 1, 0, 'some value') ->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1') ->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2'); $resolver = $this->resolverFactory->createSingleValueResolver( 'catalog_product_entity', 'sku', 'entity_id' );   $insert = InsertOnDuplicate::create( 'catalog_product_entity_varchar', ['entity_id', 'attribute_id', 'store_id', 'value'] )->withResolver($resolver);   $insert 15/26
  • 45. Insert on duplicate will skip any unresolved entries Lazy Entity Resolving $resolver = $this->resolverFactory->createSingleValueResolver( 'catalog_product_entity', 'sku', 'entity_id' );   $insert = InsertOnDuplicate::create( 'catalog_product_entity_varchar', ['entity_id', 'attribute_id', 'store_id', 'value'] )->withResolver($resolver);   $insert ->withRow($resolver->unresolved('sku1'), 1, 0, 'some value') ->withRow($resolver->unresolved('sku2'), 1, 0, 'some value1') ->withRow($resolver->unresolved('sku3'), 1, 0, 'some value2'); 15/26
  • 46. 16/26
  • 47. Batch auto-increment generation START TRANSACTION;   INSERT INTO catalog_product_entity (sku) VALUES ('sku1'), ('sku2'), ('sku3'), ('sku4');   SELECT entity_id, sku FROM catalog_product_entity WHERE sku IN ('sku1', 'sku2', 'sku3', 'sku4');   ROLLBACK; 17/26
  • 48. Start a transaction Batch auto-increment generation START TRANSACTION;   INSERT INTO catalog_product_entity (sku) VALUES ('sku1'), ('sku2'), ('sku3'), ('sku4');   SELECT entity_id, sku FROM catalog_product_entity WHERE sku IN ('sku1', 'sku2', 'sku3', 'sku4');   ROLLBACK; 17/26
  • 49. Populate table with un-resolved keys Batch auto-increment generation   INSERT INTO catalog_product_entity (sku) VALUES ('sku1'), ('sku2'), ('sku3'), ('sku4');   START TRANSACTION; SELECT entity_id, sku FROM catalog_product_entity WHERE sku IN ('sku1', 'sku2', 'sku3', 'sku4');   ROLLBACK; 17/26
  • 50. Retrieve new identifiers Batch auto-increment generation SELECT entity_id, sku FROM catalog_product_entity WHERE sku IN ('sku1', 'sku2', 'sku3', 'sku4');   START TRANSACTION;   INSERT INTO catalog_product_entity (sku) VALUES ('sku1'), ('sku2'), ('sku3'), ('sku4');   ROLLBACK; 17/26
  • 51. Rollback transaction Batch auto-increment generation ROLLBACK; START TRANSACTION;   INSERT INTO catalog_product_entity (sku) VALUES ('sku1'), ('sku2'), ('sku3'), ('sku4');   SELECT entity_id, sku FROM catalog_product_entity WHERE sku IN ('sku1', 'sku2', 'sku3', 'sku4');   17/26
  • 53. Compile query for constant batch size Prepared Statements 18/26
  • 54. Compile query for constant batch size Send only data instead of generating new queries Prepared Statements 18/26
  • 55. Compile query for constant batch size Send only data instead of generating new queries Reduces query processing on MySQL side by half Prepared Statements 18/26
  • 56. Speed 450 products per second 19/26
  • 57. Speed 450 products per second ~ 11 seconds for 5k products 19/26
  • 58. But it was still not good enough 20/26
  • 59. But it was still not good enough 45 minutes to import 1 million SKUs 20/26
  • 60. Sure, because it's a sequential process... 21/26
  • 61. So I made it asynchronous as PoC 22/26
  • 63. Under the hood Each target tabletarget table receives a separate connection to MySQL 23/26
  • 64. Under the hood Each target tabletarget table receives a separate connection to MySQL Identity resolver is attached to the source table connection 23/26
  • 65. Under the hood Each target tabletarget table receives a separate connection to MySQL Identity resolver is attached to the source table connection Each feed is processed concurrently by using round robinround robin strategy 23/26
  • 66. Under the hood Each target tabletarget table receives a separate connection to MySQL Identity resolver is attached to the source table connection Each feed is processed concurrently by using round robinround robin strategy During MySQL query execution PHP prepares the next batch 23/26
  • 67. Speed 1,850 products per second 24/26
  • 68. Speed 1,850 products per second ~ 9 minutes for 1m products 24/26
  • 69. It is coming this fall as an open source tool for everyone! 25/26