Skip to content

Commit 5ff6c66

Browse files
author
Oleksii Korshenko
committed
MAGETWO-55589: Wrong algorithm for calculation batch size on category indexing
1 parent 522fad0 commit 5ff6c66

File tree

4 files changed

+331
-43
lines changed

4 files changed

+331
-43
lines changed

lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Magento\Framework\Phrase;
2727
use Magento\Framework\Stdlib\DateTime;
2828
use Magento\Framework\Stdlib\StringUtils;
29+
use Magento\Framework\DB\Query\Generator as QueryGenerator;
2930

3031
/**
3132
* @SuppressWarnings(PHPMD.ExcessivePublicCount)
@@ -199,6 +200,11 @@ class Mysql extends \Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
199200
*/
200201
private $exceptionMap;
201202

203+
/**
204+
* @var QueryGenerator
205+
*/
206+
private $queryGenerator;
207+
202208
/**
203209
* @param StringUtils $string
204210
* @param DateTime $dateTime
@@ -3362,57 +3368,32 @@ public function insertFromSelect(Select $select, $table, array $fields = [], $mo
33623368
* @param int $stepCount
33633369
* @return \Magento\Framework\DB\Select[]
33643370
* @throws LocalizedException
3371+
* @deprecated
33653372
*/
33663373
public function selectsByRange($rangeField, \Magento\Framework\DB\Select $select, $stepCount = 100)
33673374
{
3368-
$fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM);
3369-
if (empty($fromSelect)) {
3370-
throw new LocalizedException(
3371-
new \Magento\Framework\Phrase('Select object must have correct "FROM" part')
3372-
);
3373-
}
3374-
3375-
$tableName = [];
3376-
$correlationName = '';
3377-
foreach ($fromSelect as $correlationName => $formPart) {
3378-
if ($formPart['joinType'] == \Magento\Framework\DB\Select::FROM) {
3379-
$tableName = $formPart['tableName'];
3380-
break;
3381-
}
3382-
}
3383-
3384-
$selectRange = $this->select()
3385-
->from(
3386-
$tableName,
3387-
[
3388-
new \Zend_Db_Expr('MIN(' . $this->quoteIdentifier($rangeField) . ') AS min'),
3389-
new \Zend_Db_Expr('MAX(' . $this->quoteIdentifier($rangeField) . ') AS max'),
3390-
]
3391-
);
3392-
3393-
$rangeResult = $this->fetchRow($selectRange);
3394-
$min = $rangeResult['min'];
3395-
$max = $rangeResult['max'];
3396-
3375+
$iterator = $this->getQueryGenerator()->generate($rangeField, $select, $stepCount);
33973376
$queries = [];
3398-
while ($min <= $max) {
3399-
$partialSelect = clone $select;
3400-
$partialSelect->where(
3401-
$this->quoteIdentifier($correlationName) . '.'
3402-
. $this->quoteIdentifier($rangeField) . ' >= ?',
3403-
$min
3404-
)
3405-
->where(
3406-
$this->quoteIdentifier($correlationName) . '.'
3407-
. $this->quoteIdentifier($rangeField) . ' < ?',
3408-
$min + $stepCount
3409-
);
3410-
$queries[] = $partialSelect;
3411-
$min += $stepCount;
3377+
foreach ($iterator as $query) {
3378+
$queries[] = $query;
34123379
}
34133380
return $queries;
34143381
}
34153382

3383+
/**
3384+
* Get query generator
3385+
*
3386+
* @return QueryGenerator
3387+
* @deprecated
3388+
*/
3389+
private function getQueryGenerator()
3390+
{
3391+
if ($this->queryGenerator === null) {
3392+
$this->queryGenerator = \Magento\Framework\App\ObjectManager::getInstance()->create(QueryGenerator::class);
3393+
}
3394+
return $this->queryGenerator;
3395+
}
3396+
34163397
/**
34173398
* Get update table query using select object for join and update
34183399
*
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Framework\DB\Query;
7+
8+
use Magento\Framework\DB\Adapter\AdapterInterface;
9+
use Magento\Framework\DB\Select;
10+
11+
/**
12+
* Query batch iterator
13+
*/
14+
class BatchIterator implements \Iterator
15+
{
16+
/**
17+
* @var int
18+
*/
19+
private $batchSize;
20+
21+
/**
22+
* @var Select
23+
*/
24+
private $select;
25+
26+
/**
27+
* @var int
28+
*/
29+
private $minValue = 0;
30+
31+
/**
32+
* @var string
33+
*/
34+
private $correlationName;
35+
36+
/**
37+
* @var string
38+
*/
39+
private $rangeField;
40+
41+
/**
42+
* @var Select
43+
*/
44+
private $currentSelect;
45+
46+
/**
47+
* @var AdapterInterface
48+
*/
49+
private $connection;
50+
51+
/**
52+
* @var int
53+
*/
54+
private $iteration = 0;
55+
56+
/**
57+
* @var string
58+
*/
59+
private $rangeFieldAlias;
60+
61+
/**
62+
* Initialize dependencies.
63+
*
64+
* @param Select $select
65+
* @param int $batchSize
66+
* @param string $correlationName
67+
* @param string $rangeField
68+
*/
69+
public function __construct(
70+
Select $select,
71+
$batchSize,
72+
$correlationName,
73+
$rangeField,
74+
$rangeFieldAlias
75+
) {
76+
$this->batchSize = $batchSize;
77+
$this->select = $select;
78+
$this->correlationName = $correlationName;
79+
$this->rangeField = $rangeField;
80+
$this->rangeFieldAlias = $rangeFieldAlias;
81+
$this->connection = $select->getConnection();
82+
}
83+
84+
/**
85+
* @return Select
86+
*/
87+
public function current()
88+
{
89+
return $this->currentSelect;
90+
}
91+
92+
/**
93+
* @return Select
94+
*/
95+
public function next()
96+
{
97+
$this->iteration++;
98+
return $this->currentSelect;
99+
}
100+
101+
/**
102+
* @return int
103+
*/
104+
public function key()
105+
{
106+
return $this->iteration;
107+
}
108+
109+
/**
110+
* @return bool
111+
*/
112+
public function valid()
113+
{
114+
$this->currentSelect = $this->initSelectObject();
115+
$batchSize = $this->calculateBatchSize($this->currentSelect);
116+
return $batchSize > 0;
117+
}
118+
119+
/**
120+
* @return void
121+
*/
122+
public function rewind()
123+
{
124+
$this->minValue = 0;
125+
$this->iteration = 0;
126+
}
127+
128+
/**
129+
* Calculate batch size for select.
130+
*
131+
* @param Select $select
132+
* @return int
133+
*/
134+
private function calculateBatchSize(Select $select)
135+
{
136+
$wrapperSelect = $this->connection->select();
137+
$wrapperSelect->from(
138+
$select,
139+
[
140+
new \Zend_Db_Expr('MAX(' . $this->rangeFieldAlias . ') as max'),
141+
new \Zend_Db_Expr('COUNT(*) as cnt')
142+
]
143+
);
144+
$row = $this->connection->fetchRow($wrapperSelect);
145+
$this->minValue = $row['max'];
146+
return intval($row['cnt']);
147+
}
148+
149+
/**
150+
* Initialize select object.
151+
*
152+
* @return \Magento\Framework\DB\Select
153+
*/
154+
private function initSelectObject()
155+
{
156+
$object = clone $this->select;
157+
$object->where(
158+
$this->connection->quoteIdentifier($this->correlationName)
159+
. '.' . $this->connection->quoteIdentifier($this->rangeField)
160+
. ' > ?',
161+
$this->minValue
162+
);
163+
$object->limit($this->batchSize);
164+
/**
165+
* Reset sort order section from origin select object
166+
*/
167+
$object->order($this->correlationName . '.' . $this->rangeField . ' asc');
168+
return $object;
169+
}
170+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
namespace Magento\Framework\DB\Query;
3+
4+
/**
5+
* Factory class for @see \Magento\Framework\DB\Query\BatchIterator
6+
*/
7+
class BatchIteratorFactory
8+
{
9+
/**
10+
* Object Manager instance
11+
*
12+
* @var \Magento\Framework\ObjectManagerInterface
13+
*/
14+
private $objectManager = null;
15+
16+
/**
17+
* Instance name to create
18+
*
19+
* @var string
20+
*/
21+
private $instanceName = null;
22+
23+
/**
24+
* Factory constructor
25+
*
26+
* @param \Magento\Framework\ObjectManagerInterface $objectManager
27+
* @param string $instanceName
28+
*/
29+
public function __construct(
30+
\Magento\Framework\ObjectManagerInterface $objectManager,
31+
$instanceName = \Magento\Framework\DB\Query\BatchIterator::class
32+
) {
33+
$this->objectManager = $objectManager;
34+
$this->instanceName = $instanceName;
35+
}
36+
37+
/**
38+
* Create class instance with specified parameters
39+
*
40+
* @param array $data
41+
* @return \Magento\Framework\DB\Query\BatchIterator
42+
*/
43+
public function create(array $data = array())
44+
{
45+
return $this->objectManager->create($this->instanceName, $data);
46+
}
47+
}

0 commit comments

Comments
 (0)