Skip to content

Commit 263c17f

Browse files
kandyadifucan
authored andcommitted
Price Index optimization
1 parent 81340cb commit 263c17f

File tree

11 files changed

+160
-122
lines changed

11 files changed

+160
-122
lines changed

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,8 @@ public function __construct(
7272
*/
7373
public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void
7474
{
75-
foreach ($entityIds as $entityId) {
75+
foreach ($this->getBundleIds($entityIds) as $entityId) {
7676
$entityId = (int) $entityId;
77-
if (!$this->isBundle($entityId)) {
78-
continue;
79-
}
8077
foreach ($this->getWebsiteIdsOfProduct($entityId) as $websiteId) {
8178
$productIdsDisabledRequired = $this->selectionProductsDisabledRequired
8279
->getChildProductIds($entityId, (int)$websiteId);
@@ -138,4 +135,24 @@ private function isBundle(int $entityId): bool
138135
$this->isBundle[$entityId] = $typeId === Type::TYPE_BUNDLE;
139136
return $this->isBundle[$entityId];
140137
}
138+
139+
/**
140+
* @param array $entityIds
141+
* @return \Traversable
142+
*/
143+
protected function getBundleIds(array $entityIds): \Traversable
144+
{
145+
$connection = $this->resourceConnection->getConnection('indexer');
146+
$select = $connection->select();
147+
$select->from(
148+
['cpe' => $this->resourceConnection->getTableName('catalog_product_entity')],
149+
['entity_id']
150+
)->where('cpe.entity_id in ( ? )', $entityIds ?? [0], \Zend_Db::INT_TYPE)
151+
->where('type_id = ?', Type::TYPE_BUNDLE);
152+
153+
$statement = $select->query();
154+
while ($id = $statement->fetchColumn()) {
155+
yield $id;
156+
}
157+
}
141158
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,16 +343,15 @@ protected function _getIndexer($productTypeId)
343343
*/
344344
protected function _insertFromTable($sourceTable, $destTable, $where = null)
345345
{
346-
$sourceColumns = array_keys($this->getConnection()->describeTable($sourceTable));
347-
$targetColumns = array_keys($this->getConnection()->describeTable($destTable));
348-
$select = $this->getConnection()->select()->from($sourceTable, $sourceColumns);
346+
$columns = array_keys($this->getConnection()->describeTable($destTable));
347+
$select = $this->getConnection()->select()->from($sourceTable, $columns);
349348
if ($where) {
350349
$select->where($where);
351350
}
352351
$query = $this->getConnection()->insertFromSelect(
353352
$select,
354353
$destTable,
355-
$targetColumns,
354+
$columns,
356355
AdapterInterface::INSERT_ON_DUPLICATE
357356
);
358357
$this->getConnection()->query($query);

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

Lines changed: 60 additions & 56 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',
130-
[]
131-
)->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',
148113
[]
149114
)->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,7 @@ 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]);
138+
187139

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

@@ -213,8 +165,56 @@ public function getQuery(array $dimensions, string $productType, array $entityId
213165
]
214166
);
215167

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

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

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

235-
// exclude websites that are limited for customer group
236-
$select->where('cgw.website_id IS NULL');
238+
237239

238240
/**
239241
* throw event for backward compatibility
@@ -248,6 +250,8 @@ public function getQuery(array $dimensions, string $productType, array $entityId
248250
]
249251
);
250252

253+
// static $p; if (!$p) { echo $select; $p =1; }
254+
// var_dump(__METHOD__, $connection->query($connection->select()->from((clone $select)->having('customer_group_id = 0'), "COUNT(*)"))->fetchColumn());
251255
return $select;
252256
}
253257

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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Fulltext implements
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

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

Lines changed: 33 additions & 40 deletions
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,
@@ -357,10 +357,11 @@ public function getProductAttributes($storeId, array $productIds, array $attribu
357357
$selects = [];
358358
$ifStoreValue = $this->connection->getCheckSql('t_store.value_id > 0', 't_store.value', 't_default.value');
359359
$linkField = $this->metadata->getLinkField();
360-
$productLinkFieldsToEntityIdMap = $this->connection->fetchPairs(
360+
$tmpTableName = 'index_fulltext_tmp_' . time();
361+
$this->connection->query('CREATE TEMPORARY TABLE ' . $tmpTableName . ' ' .
361362
$this->connection->select()->from(
362363
['cpe' => $this->getTable('catalog_product_entity')],
363-
[$linkField, 'entity_id']
364+
$linkField != 'entity_id' ? [$linkField, 'entity_id'] : ['entity_id']
364365
)->where(
365366
'cpe.entity_id IN (?)',
366367
$productIds,
@@ -369,53 +370,45 @@ public function getProductAttributes($storeId, array $productIds, array $attribu
369370
);
370371
foreach ($attributeTypes as $backendType => $attributeIds) {
371372
if ($attributeIds) {
372-
$tableName = $this->getTable('catalog_product_entity_' . $backendType);
373-
374-
$select = $this->connection->select()->from(
375-
['t' => $tableName],
376-
[
377-
$linkField => 't.' . $linkField,
378-
'attribute_id' => 't.attribute_id',
379-
'value' => $this->unifyField($ifStoreValue, $backendType),
380-
]
381-
)->joinLeft(
382-
['t_store' => $tableName],
383-
$this->connection->quoteInto(
384-
't.' . $linkField . '=t_store.' . $linkField .
385-
' AND t.attribute_id=t_store.attribute_id' .
386-
' AND t_store.store_id = ?',
387-
$storeId
388-
),
389-
[]
390-
)->joinLeft(
391-
['t_default' => $tableName],
392-
$this->connection->quoteInto(
393-
't.' . $linkField . '=t_default.' . $linkField .
394-
' AND t.attribute_id=t_default.attribute_id' .
395-
' AND t_default.store_id = ?',
396-
0
397-
),
398-
[]
399-
)->where(
400-
't.attribute_id IN (?)',
401-
$attributeIds
402-
)->where(
403-
't.' . $linkField . ' IN (?)',
404-
array_keys($productLinkFieldsToEntityIdMap)
405-
)->distinct();
406-
$selects[] = $select;
373+
foreach ($attributeIds as $attributeId) {
374+
$tableName = $this->getTable('catalog_product_entity_' . $backendType);
375+
376+
$select = $this->connection->select()->from(
377+
['t' => $tmpTableName],
378+
[
379+
'entity_id' => 't.entity_id',
380+
$linkField => 't.' . $linkField,
381+
'value' => $this->unifyField($ifStoreValue, $backendType),
382+
]
383+
)->joinLeft(
384+
['t_default' => $tableName],
385+
't.' . $linkField . ' = t_default.' . $linkField
386+
. ' AND t_default.attribute_id = ' . (int) $attributeId
387+
. ' AND t_default.store_id = 0',
388+
['attribute_id' => 't_default.attribute_id']
389+
)->joinLeft(
390+
['t_store' => $tableName],
391+
't.' . $linkField . ' = t_store.' . $linkField
392+
. ' AND t_store.attribute_id = ' . (int) $attributeId
393+
. ' AND t_store.store_id = ' . (int) $storeId,
394+
395+
[]
396+
);
397+
$selects[] = $select;
398+
}
399+
407400
}
408401
}
409402

410403
if ($selects) {
411404
$select = $this->connection->select()->union($selects, Select::SQL_UNION_ALL);
412405
$query = $this->connection->query($select);
413406
while ($row = $query->fetch()) {
414-
$entityId = $productLinkFieldsToEntityIdMap[$row[$linkField]];
407+
$entityId = $row['entity_id'];
415408
$result[$entityId][$row['attribute_id']] = $row['value'];
416409
}
417410
}
418-
411+
$this->connection->dropTemporaryTable($tmpTableName);
419412
return $result;
420413
}
421414

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ public function __construct(
260260
$indexIteratorFactory = null,
261261
\Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
262262
DataProvider $dataProvider = null,
263-
$batchSize = 500,
263+
$batchSize = 1000,
264264
?DeploymentConfig $deploymentConfig = null
265265
) {
266266
$this->resource = $resource;

0 commit comments

Comments
 (0)