Skip to content

Commit 9dd7c72

Browse files
authored
Merge pull request #1065 from magento-performance/MAGETWO-64766-64954
[performance] MAGETWO-64766: [Performance] Investigate and optimize price layered navigation
2 parents 2991a00 + 560b0e9 commit 9dd7c72

File tree

23 files changed

+568
-69
lines changed

23 files changed

+568
-69
lines changed

app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2289,7 +2289,7 @@ public function addMediaGalleryData()
22892289
return $this;
22902290
}
22912291

2292-
if (!$this->count()) {
2292+
if (!$this->getSize()) {
22932293
return $this;
22942294
}
22952295

app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ public function testAddMediaGalleryData()
258258
$this->metadataPoolMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock);
259259
$metadataMock->expects($this->once())->method('getLinkField')->willReturn($linkField);
260260

261+
$this->connectionMock->expects($this->once())->method('fetchOne')->with($selectMock)->willReturn(42);
261262
$this->connectionMock->expects($this->once())->method('fetchAll')->with($selectMock)->willReturn(
262263
[['row_id' => $rowId]]
263264
);

app/code/Magento/CatalogInventory/Setup/InstallSchema.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,10 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con
344344
$installer->getIdxName('cataloginventory_stock_status', ['website_id']),
345345
['website_id']
346346
)
347+
->addIndex(
348+
$installer->getIdxName('cataloginventory_stock_status', ['stock_status']),
349+
['stock_status']
350+
)
347351
->setComment('Cataloginventory Stock Status');
348352
$installer->getConnection()
349353
->createTable($table);

app/code/Magento/CatalogInventory/Setup/UpgradeSchema.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con
3030
}
3131

3232
if (version_compare($context->getVersion(), '2.3.0', '<')) {
33+
$this->addCatalogInventoryStockStatusIndexOnStockStatus($setup);
3334
$this->addReplicaTable($setup, 'cataloginventory_stock_status', 'cataloginventory_stock_status_replica');
3435
}
36+
3537
$setup->endSetup();
3638
}
3739

@@ -124,6 +126,27 @@ private function getForeignKeys(SchemaSetupInterface $setup, array $compositeKey
124126
return $foreignKeys;
125127
}
126128

129+
/**
130+
* Creates index for `stock_status` field in `cataloginventory_stock_status` table
131+
*
132+
* @param SchemaSetupInterface $setup
133+
* @return void
134+
*/
135+
private function addCatalogInventoryStockStatusIndexOnStockStatus(SchemaSetupInterface $setup)
136+
{
137+
$table = $setup->getTable('cataloginventory_stock_status');
138+
$indexesList = $setup->getConnection()->getIndexList($table);
139+
$indexName = $setup->getIdxName($table, ['stock_status']);
140+
141+
if (!array_key_exists(strtoupper($indexName), $indexesList)) {
142+
$setup->getConnection()->addIndex(
143+
$table,
144+
$indexName,
145+
['stock_status']
146+
);
147+
}
148+
}
149+
127150
/**
128151
* Add replica table for existing one.
129152
*

app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,16 @@ public function getDataSet(
139139
);
140140
$table .= $tableSufix;
141141
$subSelect = $select;
142-
$subSelect->from(['main_table' => $table], ['main_table.value'])
142+
$subSelect->from(['main_table' => $table], ['main_table.entity_id', 'main_table.value'])
143+
->distinct()
143144
->joinLeft(
144145
['stock_index' => $this->indexerStockFrontendResource->getMainTable()],
145146
'main_table.source_id = stock_index.product_id',
146147
[]
147148
)
148149
->where('main_table.attribute_id = ?', $attribute->getAttributeId())
149150
->where('main_table.store_id = ? ', $currentScopeId)
150-
->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK)
151-
->group(['main_table.entity_id', 'main_table.value']);
151+
->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK);
152152
$parentSelect = $this->getSelect();
153153
$parentSelect->from(['main_table' => $subSelect], ['main_table.value']);
154154
$select = $parentSelect;

app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Magento\Framework\Search\Request\BucketInterface;
1818
use Magento\Framework\App\ObjectManager;
1919
use Magento\Indexer\Model\ResourceModel\FrontendResource;
20+
use Magento\Store\Model\StoreManager;
2021

2122
/**
2223
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -58,21 +59,28 @@ class DataProvider implements DataProviderInterface
5859
*/
5960
private $indexerFrontendResource;
6061

62+
/**
63+
* @var StoreManager
64+
*/
65+
private $storeManager;
66+
6167
/**
6268
* @param ResourceConnection $resource
6369
* @param Range $range
6470
* @param Session $customerSession
6571
* @param MysqlDataProviderInterface $dataProvider
6672
* @param IntervalFactory $intervalFactory
6773
* @param FrontendResource $indexerFrontendResource
74+
* @param StoreManager $storeManager
6875
*/
6976
public function __construct(
7077
ResourceConnection $resource,
7178
Range $range,
7279
Session $customerSession,
7380
MysqlDataProviderInterface $dataProvider,
7481
IntervalFactory $intervalFactory,
75-
FrontendResource $indexerFrontendResource = null
82+
FrontendResource $indexerFrontendResource = null,
83+
StoreManager $storeManager = null
7684
) {
7785
$this->resource = $resource;
7886
$this->connection = $resource->getConnection();
@@ -83,6 +91,7 @@ public function __construct(
8391
$this->indexerFrontendResource = $indexerFrontendResource ?: ObjectManager::getInstance()->get(
8492
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\FrontendResource::class
8593
);
94+
$this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManager::class);
8695
}
8796

8897
/**
@@ -99,7 +108,7 @@ public function getRange()
99108
public function getAggregations(\Magento\Framework\Search\Dynamic\EntityStorage $entityStorage)
100109
{
101110
$aggregation = [
102-
'count' => 'count(DISTINCT main_table.entity_id)',
111+
'count' => 'count(main_table.entity_id)',
103112
'max' => 'MAX(min_price)',
104113
'min' => 'MIN(min_price)',
105114
'std' => 'STDDEV_SAMP(min_price)',
@@ -111,14 +120,13 @@ public function getAggregations(\Magento\Framework\Search\Dynamic\EntityStorage
111120
/** @var Table $table */
112121
$table = $entityStorage->getSource();
113122
$select->from(['main_table' => $tableName], [])
114-
->joinInner(['entities' => $table->getName()], 'main_table.entity_id = entities.entity_id', [])
123+
->where('main_table.entity_id in (select entity_id from ' . $table->getName() . ')')
115124
->columns($aggregation);
116125

117126
$select = $this->setCustomerGroupId($select);
127+
$select->where('main_table.website_id = ?', $this->storeManager->getStore()->getWebsiteId());
118128

119-
$result = $this->connection->fetchRow($select);
120-
121-
return $result;
129+
return $this->connection->fetchRow($select);
122130
}
123131

124132
/**

app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Magento\Framework\Search\Request\FilterInterface;
2323
use Magento\Store\Model\ScopeInterface;
2424
use Magento\Store\Model\Store;
25+
use Magento\Customer\Model\Session;
2526

2627
/**
2728
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -73,6 +74,11 @@ class Preprocessor implements PreprocessorInterface
7374
*/
7475
private $aliasResolver;
7576

77+
/**
78+
* @var Session
79+
*/
80+
private $customerSession;
81+
7682
/**
7783
* @var \Magento\Indexer\Model\Indexer\StateFactory
7884
*/
@@ -88,6 +94,9 @@ class Preprocessor implements PreprocessorInterface
8894
* @param ScopeConfigInterface|null $scopeConfig
8995
* @param AliasResolver|null $aliasResolver
9096
* @param \Magento\Indexer\Model\Indexer\StateFactory|null $stateFactory
97+
* @param Session $customerSession
98+
*
99+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
91100
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
92101
*/
93102
public function __construct(
@@ -99,7 +108,8 @@ public function __construct(
99108
$attributePrefix,
100109
ScopeConfigInterface $scopeConfig = null,
101110
AliasResolver $aliasResolver = null,
102-
\Magento\Indexer\Model\Indexer\StateFactory $stateFactory = null
111+
\Magento\Indexer\Model\Indexer\StateFactory $stateFactory = null,
112+
Session $customerSession = null
103113
) {
104114
$this->conditionManager = $conditionManager;
105115
$this->scopeResolver = $scopeResolver;
@@ -114,11 +124,15 @@ public function __construct(
114124
if (null === $aliasResolver) {
115125
$aliasResolver = ObjectManager::getInstance()->get(AliasResolver::class);
116126
}
117-
$this->indexerStateFactory = $stateFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
118-
->get(\Magento\Indexer\Model\Indexer\StateFactory::class);
127+
if (null === $customerSession) {
128+
$customerSession = ObjectManager::getInstance()->get(Session::class);
129+
}
130+
119131
$this->scopeConfig = $scopeConfig;
120132
$this->aliasResolver = $aliasResolver;
121-
133+
$this->customerSession = $customerSession;
134+
$this->indexerStateFactory = $stateFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
135+
->get(\Magento\Indexer\Model\Indexer\StateFactory::class);
122136
}
123137

124138
/**
@@ -146,6 +160,12 @@ private function processQueryWithField(FilterInterface $filter, $isNegation, $qu
146160
$this->connection->quoteIdentifier('price_index.min_price'),
147161
$query
148162
);
163+
164+
$resultQuery .= sprintf(
165+
' AND %s = %s',
166+
$this->connection->quoteIdentifier('price_index.customer_group_id'),
167+
$this->customerSession->getCustomerGroupId()
168+
);
149169
} elseif ($filter->getField() === 'category_ids') {
150170
return 'category_ids_index.category_id = ' . (int) $filter->getValue();
151171
} elseif ($attribute->isStatic()) {

app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Magento\CatalogInventory\Model\Stock;
2121
use Magento\Framework\App\ScopeResolverInterface;
2222
use Magento\Framework\App\ObjectManager;
23+
use Magento\CatalogSearch\Model\Search\QueryChecker\FullTextSearchCheck;
2324

2425
/**
2526
* Build base Query for Index
@@ -73,6 +74,11 @@ class IndexBuilder implements IndexBuilderInterface
7374
*/
7475
private $indexerStockFrontendResource;
7576

77+
/**
78+
* @var FullTextSearchCheck
79+
*/
80+
private $fullTextSearchCheck;
81+
7682
/**
7783
* @param \Magento\Framework\App\ResourceConnection $resource
7884
* @param ScopeConfigInterface $config
@@ -82,6 +88,7 @@ class IndexBuilder implements IndexBuilderInterface
8288
* @param TableMapper $tableMapper
8389
* @param ScopeResolverInterface $dimensionScopeResolver
8490
* @param null|\Magento\Indexer\Model\ResourceModel\FrontendResource $indexerStockFrontendResource
91+
* @param FullTextSearchCheck $fullTextSearchCheck
8592
*/
8693
public function __construct(
8794
ResourceConnection $resource,
@@ -91,7 +98,8 @@ public function __construct(
9198
IndexScopeResolver $scopeResolver,
9299
TableMapper $tableMapper,
93100
ScopeResolverInterface $dimensionScopeResolver,
94-
\Magento\Indexer\Model\ResourceModel\FrontendResource $indexerStockFrontendResource = null
101+
\Magento\Indexer\Model\ResourceModel\FrontendResource $indexerStockFrontendResource = null,
102+
FullTextSearchCheck $fullTextSearchCheck = null
95103
) {
96104
$this->resource = $resource;
97105
$this->config = $config;
@@ -102,6 +110,8 @@ public function __construct(
102110
$this->dimensionScopeResolver = $dimensionScopeResolver;
103111
$this->indexerStockFrontendResource = $indexerStockFrontendResource ?: ObjectManager::getInstance()
104112
->get(\Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\FrontendResource::class);
113+
$this->fullTextSearchCheck = $fullTextSearchCheck ?: ObjectManager::getInstance()
114+
->get(FullTextSearchCheck::class);
105115
}
106116

107117
/**
@@ -110,6 +120,8 @@ public function __construct(
110120
* @param RequestInterface $request
111121
* @return Select
112122
* @throws \LogicException
123+
* @throws \DomainException
124+
* @throws \InvalidArgumentException
113125
*/
114126
public function build(RequestInterface $request)
115127
{
@@ -118,12 +130,15 @@ public function build(RequestInterface $request)
118130
->from(
119131
['search_index' => $searchIndexTable],
120132
['entity_id' => 'entity_id']
121-
)
122-
->joinLeft(
133+
);
134+
135+
if ($this->fullTextSearchCheck->isRequiredForQuery($request->getQuery())) {
136+
$select->joinLeft(
123137
['cea' => $this->resource->getTableName('catalog_eav_attribute')],
124138
'search_index.attribute_id = cea.attribute_id',
125139
[]
126140
);
141+
}
127142

128143
$select = $this->tableMapper->addTables($select, $request);
129144

0 commit comments

Comments
 (0)