Skip to content

Commit 53de67e

Browse files
committed
MC-23215: Slow catalog_product_price indexer for Bundle products
1 parent d0c8f05 commit 53de67e

File tree

1 file changed

+154
-83
lines changed
  • app/code/Magento/Bundle/Model/ResourceModel/Indexer

1 file changed

+154
-83
lines changed

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

Lines changed: 154 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use Magento\Catalog\Api\Data\ProductInterface;
99
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier;
10+
use Magento\Framework\DB\Select;
1011
use Magento\Framework\Indexer\DimensionalIndexerInterface;
1112
use Magento\Framework\EntityManager\MetadataPool;
1213
use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
@@ -394,8 +395,8 @@ private function calculateBundleOptionPrice($priceTable, $dimensions)
394395
$connection = $this->getConnection();
395396

396397
$this->prepareBundleSelectionTable();
397-
$this->calculateBundleSelectionPrice($dimensions, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED);
398-
$this->calculateBundleSelectionPrice($dimensions, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC);
398+
$this->calculateFixedBundleSelectionPrice();
399+
$this->calculateDynamicBundleSelectionPrice($dimensions);
399400

400401
$this->prepareBundleOptionTable();
401402

@@ -426,84 +427,17 @@ private function calculateBundleOptionPrice($priceTable, $dimensions)
426427
}
427428

428429
/**
429-
* Calculate bundle product selections price by product type
430+
* Get base select for bundle selection price
430431
*
431-
* @param array $dimensions
432-
* @param int $priceType
433-
* @return void
432+
* @return Select
434433
* @throws \Exception
435-
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
436434
*/
437-
private function calculateBundleSelectionPrice($dimensions, $priceType)
435+
private function getBaseBundleSelectionPriceSelect(): Select
438436
{
439-
$connection = $this->getConnection();
440-
441-
if ($priceType == \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED) {
442-
$selectionPriceValue = $connection->getCheckSql(
443-
'bsp.selection_price_value IS NULL',
444-
'bs.selection_price_value',
445-
'bsp.selection_price_value'
446-
);
447-
$selectionPriceType = $connection->getCheckSql(
448-
'bsp.selection_price_type IS NULL',
449-
'bs.selection_price_type',
450-
'bsp.selection_price_type'
451-
);
452-
$priceExpr = new \Zend_Db_Expr(
453-
$connection->getCheckSql(
454-
$selectionPriceType . ' = 1',
455-
'ROUND(i.price * (' . $selectionPriceValue . ' / 100),4)',
456-
$connection->getCheckSql(
457-
'i.special_price > 0 AND i.special_price < 100',
458-
'ROUND(' . $selectionPriceValue . ' * (i.special_price / 100),4)',
459-
$selectionPriceValue
460-
)
461-
) . '* bs.selection_qty'
462-
);
463-
464-
$tierExpr = $connection->getCheckSql(
465-
'i.base_tier IS NOT NULL',
466-
$connection->getCheckSql(
467-
$selectionPriceType . ' = 1',
468-
'ROUND(i.base_tier - (i.base_tier * (' . $selectionPriceValue . ' / 100)),4)',
469-
$connection->getCheckSql(
470-
'i.tier_percent > 0',
471-
'ROUND((1 - i.tier_percent / 100) * ' . $selectionPriceValue . ',4)',
472-
$selectionPriceValue
473-
)
474-
) . ' * bs.selection_qty',
475-
'NULL'
476-
);
477-
478-
$priceExpr = $connection->getLeastSql(
479-
[
480-
$priceExpr,
481-
$connection->getIfNullSql($tierExpr, $priceExpr),
482-
]
483-
);
484-
} else {
485-
$price = 'idx.min_price * bs.selection_qty';
486-
$specialExpr = $connection->getCheckSql(
487-
'i.special_price > 0 AND i.special_price < 100',
488-
'ROUND(' . $price . ' * (i.special_price / 100), 4)',
489-
$price
490-
);
491-
$tierExpr = $connection->getCheckSql(
492-
'i.tier_percent IS NOT NULL',
493-
'ROUND((1 - i.tier_percent / 100) * ' . $price . ', 4)',
494-
'NULL'
495-
);
496-
$priceExpr = $connection->getLeastSql(
497-
[
498-
$specialExpr,
499-
$connection->getIfNullSql($tierExpr, $price),
500-
]
501-
);
502-
}
503-
504437
$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
505438
$linkField = $metadata->getLinkField();
506-
$select = $connection->select()->from(
439+
440+
$select = $this->getConnection()->select()->from(
507441
['i' => $this->getBundlePriceTable()],
508442
['entity_id', 'customer_group_id', 'website_id']
509443
)->join(
@@ -518,22 +452,160 @@ private function calculateBundleSelectionPrice($dimensions, $priceType)
518452
['bs' => $this->getTable('catalog_product_bundle_selection')],
519453
'bs.option_id = bo.option_id',
520454
['selection_id']
521-
)->joinLeft(
455+
);
456+
457+
return $select;
458+
}
459+
460+
/**
461+
* Calculate product selections price for fixed bundles
462+
*
463+
* @return void
464+
* @throws \Exception
465+
*/
466+
private function calculateFixedBundleSelectionPrice()
467+
{
468+
$connection = $this->getConnection();
469+
470+
$selectionPriceValue = 'bs.selection_price_value';
471+
$selectionPriceType = 'bs.selection_price_type';
472+
$priceExpr = new \Zend_Db_Expr(
473+
$connection->getCheckSql(
474+
$selectionPriceType . ' = 1',
475+
'ROUND(i.price * (' . $selectionPriceValue . ' / 100),4)',
476+
$connection->getCheckSql(
477+
'i.special_price > 0 AND i.special_price < 100',
478+
'ROUND(' . $selectionPriceValue . ' * (i.special_price / 100),4)',
479+
$selectionPriceValue
480+
)
481+
) . '* bs.selection_qty'
482+
);
483+
$tierExpr = $connection->getCheckSql(
484+
'i.base_tier IS NOT NULL',
485+
$connection->getCheckSql(
486+
$selectionPriceType . ' = 1',
487+
'ROUND(i.base_tier - (i.base_tier * (' . $selectionPriceValue . ' / 100)),4)',
488+
$connection->getCheckSql(
489+
'i.tier_percent > 0',
490+
'ROUND((1 - i.tier_percent / 100) * ' . $selectionPriceValue . ',4)',
491+
$selectionPriceValue
492+
)
493+
) . ' * bs.selection_qty',
494+
'NULL'
495+
);
496+
$priceExpr = $connection->getLeastSql(
497+
[
498+
$priceExpr,
499+
$connection->getIfNullSql($tierExpr, $priceExpr),
500+
]
501+
);
502+
503+
$select = $this->getBaseBundleSelectionPriceSelect();
504+
$select->where(
505+
'i.price_type=?',
506+
\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED
507+
)->columns(
508+
[
509+
'group_type' => $connection->getCheckSql("bo.type = 'select' OR bo.type = 'radio'", '0', '1'),
510+
'is_required' => 'bo.required',
511+
'price' => $priceExpr,
512+
'tier_price' => $tierExpr,
513+
]
514+
);
515+
$query = $select->insertFromSelect($this->getBundleSelectionTable());
516+
$connection->query($query);
517+
518+
$selectionPriceValue = 'bsp.selection_price_value';
519+
$selectionPriceType = 'bsp.selection_price_type';
520+
$priceExpr = new \Zend_Db_Expr(
521+
$connection->getCheckSql(
522+
$selectionPriceType . ' = 1',
523+
'ROUND(i.price * (' . $selectionPriceValue . ' / 100),4)',
524+
$connection->getCheckSql(
525+
'i.special_price > 0 AND i.special_price < 100',
526+
'ROUND(' . $selectionPriceValue . ' * (i.special_price / 100),4)',
527+
$selectionPriceValue
528+
)
529+
) . '* bs.selection_qty'
530+
);
531+
$tierExpr = $connection->getCheckSql(
532+
'i.base_tier IS NOT NULL',
533+
$connection->getCheckSql(
534+
$selectionPriceType . ' = 1',
535+
'ROUND(i.base_tier - (i.base_tier * (' . $selectionPriceValue . ' / 100)),4)',
536+
$connection->getCheckSql(
537+
'i.tier_percent > 0',
538+
'ROUND((1 - i.tier_percent / 100) * ' . $selectionPriceValue . ',4)',
539+
$selectionPriceValue
540+
)
541+
) . ' * bs.selection_qty',
542+
'NULL'
543+
);
544+
$priceExpr = $connection->getLeastSql(
545+
[
546+
$priceExpr,
547+
$connection->getIfNullSql($tierExpr, $priceExpr),
548+
]
549+
);
550+
551+
$select = $this->getBaseBundleSelectionPriceSelect();
552+
$select->joinInner(
522553
['bsp' => $this->getTable('catalog_product_bundle_selection_price')],
523554
'bs.selection_id = bsp.selection_id AND bsp.website_id = i.website_id',
524-
['']
525-
)->join(
555+
[]
556+
)->where(
557+
'i.price_type=?',
558+
\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED
559+
)->columns(
560+
[
561+
'group_type' => $connection->getCheckSql("bo.type = 'select' OR bo.type = 'radio'", '0', '1'),
562+
'is_required' => 'bo.required',
563+
'price' => $priceExpr,
564+
'tier_price' => $tierExpr,
565+
]
566+
);
567+
$query = $select->crossUpdateFromSelect($this->getBundleSelectionTable());
568+
$connection->query($query);
569+
}
570+
571+
/**
572+
* Calculate product selections price for dynamic bundles
573+
*
574+
* @param array $dimensions
575+
* @return void
576+
* @throws \Exception
577+
*/
578+
private function calculateDynamicBundleSelectionPrice($dimensions)
579+
{
580+
$connection = $this->getConnection();
581+
582+
$price = 'idx.min_price * bs.selection_qty';
583+
$specialExpr = $connection->getCheckSql(
584+
'i.special_price > 0 AND i.special_price < 100',
585+
'ROUND(' . $price . ' * (i.special_price / 100), 4)',
586+
$price
587+
);
588+
$tierExpr = $connection->getCheckSql(
589+
'i.tier_percent IS NOT NULL',
590+
'ROUND((1 - i.tier_percent / 100) * ' . $price . ', 4)',
591+
'NULL'
592+
);
593+
$priceExpr = $connection->getLeastSql(
594+
[
595+
$specialExpr,
596+
$connection->getIfNullSql($tierExpr, $price),
597+
]
598+
);
599+
600+
$select = $this->getBaseBundleSelectionPriceSelect();
601+
$select->join(
526602
['idx' => $this->getMainTable($dimensions)],
527603
'bs.product_id = idx.entity_id AND i.customer_group_id = idx.customer_group_id' .
528604
' AND i.website_id = idx.website_id',
529605
[]
530-
)->join(
531-
['e' => $this->getTable('catalog_product_entity')],
532-
'bs.product_id = e.entity_id AND e.required_options=0',
533-
[]
534606
)->where(
535607
'i.price_type=?',
536-
$priceType
608+
\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC
537609
)->columns(
538610
[
539611
'group_type' => $connection->getCheckSql("bo.type = 'select' OR bo.type = 'radio'", '0', '1'),
@@ -542,7 +614,6 @@ private function calculateBundleSelectionPrice($dimensions, $priceType)
542614
'tier_price' => $tierExpr,
543615
]
544616
);
545-
546617
$query = $select->insertFromSelect($this->getBundleSelectionTable());
547618
$connection->query($query);
548619
}

0 commit comments

Comments
 (0)