Skip to content

Commit 0763e06

Browse files
authored
Merge pull request #7496 from magento-performance/MCP-946
[Performance] MCP-946: Price Index optimization
2 parents bbaa528 + 6fa1080 commit 0763e06

File tree

14 files changed

+175
-117
lines changed

14 files changed

+175
-117
lines changed

app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,17 @@ private function applyBundlePrice($priceTable): void
822822
]
823823
);
824824

825-
$this->tableMaintainer->insertFromSelect($select, $priceTable->getTableName(), []);
825+
$this->tableMaintainer->insertFromSelect($select, $priceTable->getTableName(), [
826+
"entity_id",
827+
"customer_group_id",
828+
"website_id",
829+
"tax_class_id",
830+
"price",
831+
"final_price",
832+
"min_price",
833+
"max_price",
834+
"tier_price",
835+
]);
826836
}
827837

828838
/**

app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price/DisabledProductOptionPriceModifier.php

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,22 @@ class DisabledProductOptionPriceModifier implements PriceModifierInterface
3434
/**
3535
* @var array
3636
*/
37-
private $isBundle = [];
37+
private $websiteIdsOfProduct = [];
3838

3939
/**
40-
* @var array
40+
* @var BundleSelection
4141
*/
42-
private $websiteIdsOfProduct = [];
42+
private BundleSelection $bundleSelection;
43+
44+
/**
45+
* @var Config
46+
*/
47+
private Config $config;
48+
49+
/**
50+
* @var MetadataPool
51+
*/
52+
private MetadataPool $metadataPool;
4353

4454
/**
4555
* @param ResourceConnection $resourceConnection
@@ -72,11 +82,8 @@ public function __construct(
7282
*/
7383
public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void
7484
{
75-
foreach ($entityIds as $entityId) {
85+
foreach ($this->getBundleIds($entityIds) as $entityId) {
7686
$entityId = (int) $entityId;
77-
if (!$this->isBundle($entityId)) {
78-
continue;
79-
}
8087
foreach ($this->getWebsiteIdsOfProduct($entityId) as $websiteId) {
8188
$productIdsDisabledRequired = $this->selectionProductsDisabledRequired
8289
->getChildProductIds($entityId, (int)$websiteId);
@@ -118,24 +125,24 @@ private function getWebsiteIdsOfProduct(int $entityId): array
118125
}
119126

120127
/**
121-
* Is product bundle
128+
* Get Bundle Ids
122129
*
123-
* @param int $entityId
124-
* @return bool
130+
* @param array $entityIds
131+
* @return \Traversable
125132
*/
126-
private function isBundle(int $entityId): bool
133+
private function getBundleIds(array $entityIds): \Traversable
127134
{
128-
if (isset($this->isBundle[$entityId])) {
129-
return $this->isBundle[$entityId];
130-
}
131135
$connection = $this->resourceConnection->getConnection('indexer');
132136
$select = $connection->select();
133137
$select->from(
134138
['cpe' => $this->resourceConnection->getTableName('catalog_product_entity')],
135-
['type_id']
136-
)->where('cpe.entity_id = ?', $entityId);
137-
$typeId = $connection->fetchOne($select);
138-
$this->isBundle[$entityId] = $typeId === Type::TYPE_BUNDLE;
139-
return $this->isBundle[$entityId];
139+
['entity_id']
140+
)->where('cpe.entity_id in ( ? )', !empty($entityIds) ? $entityIds : [0], \Zend_Db::INT_TYPE)
141+
->where('type_id = ?', Type::TYPE_BUNDLE);
142+
143+
$statement = $select->query();
144+
while ($id = $statement->fetchColumn()) {
145+
yield $id;
146+
}
140147
}
141148
}

app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ abstract class AbstractAction
6161
protected $_storeManager;
6262

6363
/**
64-
* Currency factory
6564
*
6665
* @var CurrencyFactory
6766
*/
@@ -83,7 +82,6 @@ abstract class AbstractAction
8382
protected $_catalogProductType;
8483

8584
/**
86-
* Indexer price factory
8785
*
8886
* @var Factory
8987
*/
@@ -343,16 +341,15 @@ protected function _getIndexer($productTypeId)
343341
*/
344342
protected function _insertFromTable($sourceTable, $destTable, $where = null)
345343
{
346-
$sourceColumns = array_keys($this->getConnection()->describeTable($sourceTable));
347-
$targetColumns = array_keys($this->getConnection()->describeTable($destTable));
348-
$select = $this->getConnection()->select()->from($sourceTable, $sourceColumns);
344+
$columns = array_keys($this->getConnection()->describeTable($destTable));
345+
$select = $this->getConnection()->select()->from($sourceTable, $columns);
349346
if ($where) {
350347
$select->where($where);
351348
}
352349
$query = $this->getConnection()->insertFromSelect(
353350
$select,
354351
$destTable,
355-
$targetColumns,
352+
$columns,
356353
AdapterInterface::INSERT_ON_DUPLICATE
357354
);
358355
$this->getConnection()->query($query);

app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/BaseFinalPrice.php

Lines changed: 56 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -110,62 +110,14 @@ public function getQuery(array $dimensions, string $productType, array $entityId
110110

111111
$select = $connection->select()->from(
112112
['e' => $this->getTable('catalog_product_entity')],
113-
['entity_id']
114-
)->joinInner(
115-
['cg' => $this->getTable('customer_group')],
116-
array_key_exists(CustomerGroupDimensionProvider::DIMENSION_NAME, $dimensions)
117-
? sprintf(
118-
'%s = %s',
119-
$this->dimensionToFieldMapper[CustomerGroupDimensionProvider::DIMENSION_NAME],
120-
$dimensions[CustomerGroupDimensionProvider::DIMENSION_NAME]->getValue()
121-
) : '',
122-
['customer_group_id']
123-
)->joinInner(
124-
['pw' => $this->getTable('catalog_product_website')],
125-
'pw.product_id = e.entity_id',
126-
['pw.website_id']
127-
)->joinInner(
128-
['cwd' => $this->getTable('catalog_product_index_website')],
129-
'pw.website_id = cwd.website_id',
130113
[]
131114
)->joinLeft(
132-
// customer group website limitations
133-
['cgw' => $this->getTable('customer_group_excluded_website')],
134-
'cg.customer_group_id = cgw.customer_group_id AND pw.website_id = cgw.website_id',
135-
[]
136-
)->joinLeft(
137-
// we need this only for BCC in case someone expects table `tp` to be present in query
138-
['tp' => $this->getTable('catalog_product_index_tier_price')],
139-
'tp.entity_id = e.entity_id AND' .
140-
' tp.customer_group_id = cg.customer_group_id AND tp.website_id = pw.website_id',
141-
[]
142-
)->joinLeft(
143-
// calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group`
144-
['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')],
145-
'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' .
146-
' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' .
147-
' AND tier_price_1.website_id = 0',
148-
[]
149-
)->joinLeft(
150-
// calculate tier price specified as Website = `Specific Website`
151-
//and Customer Group = `Specific Customer Group`
152-
['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')],
153-
'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0 ' .
154-
'AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' .
155-
' AND tier_price_2.website_id = pw.website_id',
156-
[]
157-
)->joinLeft(
158-
// calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS`
159-
['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')],
160-
'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1 ' .
161-
'AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0',
115+
['pw' => $this->getTable('catalog_product_website')],
116+
'pw.product_id = e.entity_id',
162117
[]
163118
)->joinLeft(
164-
// calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS`
165-
['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')],
166-
'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' .
167-
' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' .
168-
' AND tier_price_4.website_id = pw.website_id',
119+
['cwd' => $this->getTable('catalog_product_index_website')],
120+
'pw.website_id = cwd.website_id',
169121
[]
170122
);
171123

@@ -183,7 +135,6 @@ public function getQuery(array $dimensions, string $productType, array $entityId
183135
} else {
184136
$taxClassId = new \Zend_Db_Expr(0);
185137
}
186-
$select->columns(['tax_class_id' => $taxClassId]);
187138

188139
$this->joinAttributeProcessor->process($select, 'status', Status::STATUS_ENABLED);
189140

@@ -213,8 +164,56 @@ public function getQuery(array $dimensions, string $productType, array $entityId
213164
]
214165
);
215166

167+
$select->join(
168+
['cg' => $this->getTable('customer_group')],
169+
array_key_exists(CustomerGroupDimensionProvider::DIMENSION_NAME, $dimensions)
170+
? sprintf(
171+
'%s = %s',
172+
$this->dimensionToFieldMapper[CustomerGroupDimensionProvider::DIMENSION_NAME],
173+
$dimensions[CustomerGroupDimensionProvider::DIMENSION_NAME]->getValue()
174+
) : '',
175+
[]
176+
)->joinLeft(
177+
// customer group website limitations
178+
['cgw' => $this->getTable('customer_group_excluded_website')],
179+
'cg.customer_group_id = cgw.customer_group_id AND pw.website_id = cgw.website_id',
180+
[]
181+
)->joinLeft(
182+
// calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group`
183+
['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')],
184+
'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' .
185+
' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' .
186+
' AND tier_price_1.website_id = 0',
187+
[]
188+
)->joinLeft(
189+
// calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS`
190+
['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')],
191+
'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1 ' .
192+
'AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0',
193+
[]
194+
)->joinLeft(
195+
// calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS`
196+
['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')],
197+
'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' .
198+
' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' .
199+
' AND tier_price_4.website_id = pw.website_id',
200+
[]
201+
)->joinLeft(
202+
// calculate tier price specified as Website = `Specific Website`
203+
//and Customer Group = `Specific Customer Group`
204+
['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')],
205+
'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0 ' .
206+
'AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' .
207+
' AND tier_price_2.website_id = pw.website_id',
208+
[]
209+
);
210+
// the order of fields is important!
216211
$select->columns(
217212
[
213+
'entity_id',
214+
'cg.customer_group_id',
215+
'pw.website_id',
216+
'tax_class_id' => $taxClassId,
218217
//orig_price in catalog_product_index_price_final_tmp
219218
'price' => $connection->getIfNullSql($price, 0),
220219
//price in catalog_product_index_price_final_tmp
@@ -227,14 +226,14 @@ public function getQuery(array $dimensions, string $productType, array $entityId
227226

228227
$select->where("e.type_id = ?", $productType);
229228

229+
// exclude websites that are limited for customer group
230+
$select->where('cgw.website_id IS NULL');
231+
230232
if ($entityIds !== null) {
231233
$select->where(sprintf('e.entity_id BETWEEN %s AND %s', min($entityIds), max($entityIds)));
232-
$select->where('e.entity_id IN(?)', $entityIds);
234+
$select->where('e.entity_id IN(?)', $entityIds, \Zend_Db::INT_TYPE);
233235
}
234236

235-
// exclude websites that are limited for customer group
236-
$select->where('cgw.website_id IS NULL');
237-
238237
/**
239238
* throw event for backward compatibility
240239
*/

app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/SimpleProductPrice.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,21 @@ public function executeByDimensions(array $dimensions, \Traversable $entityIds)
8181
'tierPriceField' => 'tier_price',
8282
]);
8383
$select = $this->baseFinalPrice->getQuery($dimensions, $this->productType, iterator_to_array($entityIds));
84-
$this->tableMaintainer->insertFromSelect($select, $temporaryPriceTable->getTableName(), []);
84+
$this->tableMaintainer->insertFromSelect(
85+
$select,
86+
$temporaryPriceTable->getTableName(),
87+
[
88+
"entity_id",
89+
"customer_group_id",
90+
"website_id",
91+
"tax_class_id",
92+
"price",
93+
"final_price",
94+
"min_price",
95+
"max_price",
96+
"tier_price",
97+
]
98+
);
8599

86100
$this->basePriceModifier->modifyPrice($temporaryPriceTable, iterator_to_array($entityIds));
87101
}

app/code/Magento/Catalog/etc/db_schema.xml

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,7 +1623,7 @@
16231623
<table name="catalog_product_index_price_tmp" resource="default" engine="innodb"
16241624
comment="Catalog Product Price Indexer Temp Table">
16251625
<column xsi:type="int" name="entity_id" unsigned="true" nullable="false" identity="false"
1626-
comment="Entity ID"/>
1626+
comment="Product ID"/>
16271627
<column xsi:type="int" name="customer_group_id" unsigned="true" nullable="false" identity="false"
16281628
default="0" comment="Customer Group ID"/>
16291629
<column xsi:type="smallint" name="website_id" unsigned="true" nullable="false" identity="false"
@@ -1640,20 +1640,11 @@
16401640
comment="Max Price"/>
16411641
<column xsi:type="decimal" name="tier_price" scale="6" precision="20" unsigned="false" nullable="true"
16421642
comment="Tier Price"/>
1643+
<column xsi:type="int" name="id" unsigned="true" nullable="false" identity="true"
1644+
comment="ID"/>
16431645
<constraint xsi:type="primary" referenceId="PRIMARY">
1644-
<column name="entity_id"/>
1645-
<column name="customer_group_id"/>
1646-
<column name="website_id"/>
1646+
<column name="id"/>
16471647
</constraint>
1648-
<index referenceId="CATALOG_PRODUCT_INDEX_PRICE_TMP_CUSTOMER_GROUP_ID" indexType="btree">
1649-
<column name="customer_group_id"/>
1650-
</index>
1651-
<index referenceId="CATALOG_PRODUCT_INDEX_PRICE_TMP_WEBSITE_ID" indexType="btree">
1652-
<column name="website_id"/>
1653-
</index>
1654-
<index referenceId="CATALOG_PRODUCT_INDEX_PRICE_TMP_MIN_PRICE" indexType="btree">
1655-
<column name="min_price"/>
1656-
</index>
16571648
</table>
16581649
<table name="catalog_category_product_index_tmp" resource="default" engine="innodb"
16591650
comment="Catalog Category Product Indexer temporary table">

app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ class Fulltext implements
3333
/**
3434
* Indexer ID in configuration
3535
*/
36-
const INDEXER_ID = 'catalogsearch_fulltext';
36+
public const INDEXER_ID = 'catalogsearch_fulltext';
3737

3838
/**
3939
* Default batch size
4040
*/
41-
private const BATCH_SIZE = 100;
41+
private const BATCH_SIZE = 1000;
4242

4343
/**
4444
* @var array index structure
@@ -113,6 +113,7 @@ class Fulltext implements
113113
* @param int|null $batchSize
114114
* @param DeploymentConfig|null $deploymentConfig
115115
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
116+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
116117
*/
117118
public function __construct(
118119
FullFactory $fullActionFactory,

app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public function getSearchableProducts(
204204
array $staticFields,
205205
$productIds = null,
206206
$lastProductId = 0,
207-
$batch = 100
207+
$batch = 1000
208208
) {
209209
$select = $this->selectSearchableProducts->execute(
210210
(int) $storeId,

0 commit comments

Comments
 (0)