|
|
@@ -21,18 +21,18 @@ use yii\console\ExitCode;
|
|
|
* 用法:
|
|
|
* php yii salt/fill
|
|
|
* php yii salt/fill --dryRun=1
|
|
|
- * php yii salt/fill --batchSize=50 --sleepMs=200
|
|
|
- * php yii salt/fill --mode=pk --scanSize=2000
|
|
|
+ * php yii salt/fill --batchSize=1000 --sleepMs=200
|
|
|
+ * php yii salt/fill --mode=pk --scanSize=1000
|
|
|
* php yii salt/fill-ghs-order
|
|
|
* php yii salt/fill-cg
|
|
|
*/
|
|
|
class SaltController extends Controller
|
|
|
{
|
|
|
/** @var int 每批处理条数 */
|
|
|
- public $batchSize = 5000;
|
|
|
+ public $batchSize = 1000;
|
|
|
|
|
|
/** @var int pk 模式下每次主键游标扫描行数 */
|
|
|
- public $scanSize = 5000;
|
|
|
+ public $scanSize = 1000;
|
|
|
|
|
|
/**
|
|
|
* 扫描模式:
|
|
|
@@ -139,13 +139,13 @@ class SaltController extends Controller
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 只查 salt='' 的记录,补完即停,不会扫描已有 salt 的上千万数据
|
|
|
+ * 只查 salt='' 的记录,从最大 id 向小 id 分批处理
|
|
|
*/
|
|
|
private function fillByEmptySalt($label, $tableName)
|
|
|
{
|
|
|
$db = Yii::$app->db;
|
|
|
$processed = 0;
|
|
|
- $lastId = 0;
|
|
|
+ $lastId = null;
|
|
|
|
|
|
while (true) {
|
|
|
if ($this->limit > 0 && $processed >= $this->limit) {
|
|
|
@@ -153,18 +153,24 @@ class SaltController extends Controller
|
|
|
}
|
|
|
|
|
|
$batchLimit = $this->limit > 0 ? min($this->batchSize, $this->limit - $processed) : $this->batchSize;
|
|
|
- $rows = $db->createCommand(
|
|
|
- "SELECT id FROM {$tableName} WHERE salt = '' AND id > :lastId ORDER BY id ASC LIMIT {$batchLimit}"
|
|
|
- )->bindValue(':lastId', $lastId)->queryColumn();
|
|
|
+ if ($lastId === null) {
|
|
|
+ $rows = $db->createCommand(
|
|
|
+ "SELECT id FROM {$tableName} WHERE salt = '' ORDER BY id DESC LIMIT {$batchLimit}"
|
|
|
+ )->queryColumn();
|
|
|
+ } else {
|
|
|
+ $rows = $db->createCommand(
|
|
|
+ "SELECT id FROM {$tableName} WHERE salt = '' AND id < :lastId ORDER BY id DESC LIMIT {$batchLimit}"
|
|
|
+ )->bindValue(':lastId', $lastId)->queryColumn();
|
|
|
+ }
|
|
|
|
|
|
if (empty($rows)) {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
$processed += $this->updateIds($label, $tableName, $rows);
|
|
|
- $lastId = (int)end($rows);
|
|
|
+ $lastId = (int)min($rows);
|
|
|
|
|
|
- $this->stdout("{$label} 已处理 {$processed} 条,当前 id <= {$lastId}\n");
|
|
|
+ $this->stdout("{$label} 已处理 {$processed} 条,当前 id >= {$lastId}\n");
|
|
|
$this->sleepBetweenBatch();
|
|
|
}
|
|
|
|
|
|
@@ -172,33 +178,39 @@ class SaltController extends Controller
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 按主键游标分段扫描,查询只走主键索引;适合 empty 模式执行计划不佳时使用
|
|
|
+ * 按主键从最大 id 向小 id 分段扫描;适合 empty 模式执行计划不佳时使用
|
|
|
*/
|
|
|
private function fillByPrimaryKeyScan($label, $tableName)
|
|
|
{
|
|
|
$db = Yii::$app->db;
|
|
|
$processed = 0;
|
|
|
- $lastId = 0;
|
|
|
+ $lastId = null;
|
|
|
|
|
|
while (true) {
|
|
|
if ($this->limit > 0 && $processed >= $this->limit) {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- $ids = $db->createCommand(
|
|
|
- "SELECT id FROM {$tableName} WHERE id > :lastId ORDER BY id ASC LIMIT {$this->scanSize}"
|
|
|
- )->bindValue(':lastId', $lastId)->queryColumn();
|
|
|
+ if ($lastId === null) {
|
|
|
+ $ids = $db->createCommand(
|
|
|
+ "SELECT id FROM {$tableName} ORDER BY id DESC LIMIT {$this->scanSize}"
|
|
|
+ )->queryColumn();
|
|
|
+ } else {
|
|
|
+ $ids = $db->createCommand(
|
|
|
+ "SELECT id FROM {$tableName} WHERE id < :lastId ORDER BY id DESC LIMIT {$this->scanSize}"
|
|
|
+ )->bindValue(':lastId', $lastId)->queryColumn();
|
|
|
+ }
|
|
|
|
|
|
if (empty($ids)) {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- $lastId = (int)end($ids);
|
|
|
- $minId = (int)$ids[0];
|
|
|
- $maxId = $lastId;
|
|
|
+ $lastId = (int)min($ids);
|
|
|
+ $minId = (int)min($ids);
|
|
|
+ $maxId = (int)max($ids);
|
|
|
|
|
|
$emptyIds = $db->createCommand(
|
|
|
- "SELECT id FROM {$tableName} WHERE id >= :minId AND id <= :maxId AND salt = '' ORDER BY id ASC"
|
|
|
+ "SELECT id FROM {$tableName} WHERE id >= :minId AND id <= :maxId AND salt = '' ORDER BY id DESC"
|
|
|
)->bindValues([
|
|
|
':minId' => $minId,
|
|
|
':maxId' => $maxId,
|
|
|
@@ -211,7 +223,7 @@ class SaltController extends Controller
|
|
|
$processed += $this->updateIds($label, $tableName, $emptyIds);
|
|
|
}
|
|
|
|
|
|
- $this->stdout("{$label} 已处理 {$processed} 条,已扫描到 id={$lastId}\n");
|
|
|
+ $this->stdout("{$label} 已处理 {$processed} 条,已扫描到 id >= {$lastId}\n");
|
|
|
$this->sleepBetweenBatch();
|
|
|
}
|
|
|
|