فهرست منبع

Merge branch 'master' into dev

shish 2 ماه پیش
والد
کامیت
534ac7bab8
1فایلهای تغییر یافته به همراه112 افزوده شده و 44 حذف شده
  1. 112 44
      console/controllers/SaltController.php

+ 112 - 44
console/controllers/SaltController.php

@@ -97,73 +97,141 @@ class SaltController extends Controller
 
     /**
      * 补充 xhClear 结账单历史数据的 salt 字段
-     * 职责:查询全部 xhClear 记录,循环重新生成并设置 salt
+     * 职责:利用主键游标进行分页查询,分批重新生成并设置 salt,确保线上大表安全
      */
     public function actionFillClear()
     {
         $db = Yii::$app->db;
-        // 查询全部结账单 ID
-        $ids = $db->createCommand("SELECT id FROM xhClear ORDER BY id DESC")->queryColumn();
-        $count = 0;
-        foreach ($ids as $id) {
-            // 支持 limit 参数限制更新数量
-            if ($this->limit > 0 && $count >= $this->limit) {
+        $this->stdout("开始分页重新设置 xhClear 表的 salt 字段...\n");
+
+        $processed = 0;
+        $lastId = null;
+        $batchSize = $this->batchSize > 0 ? $this->batchSize : 1000;
+
+        while (true) {
+            // 如果设置了 limit 且已达到上限,则退出
+            if ($this->limit > 0 && $processed >= $this->limit) {
                 break;
             }
-            if ($this->dryRun) {
-                $this->stdout("[dry-run] xhClear id={$id}\n");
-                $count++;
-                continue;
+
+            // 计算当前批次需要查询的数量
+            $currentBatchSize = $batchSize;
+            if ($this->limit > 0) {
+                $currentBatchSize = min($batchSize, $this->limit - $processed);
             }
-            // 重新生成 10 位随机 salt 并更新
-            $salt = stringUtil::charsShuffleLowerCase(10);
-            $db->createCommand("UPDATE xhClear SET salt = :salt WHERE id = :id")
-                ->bindValues([':salt' => $salt, ':id' => $id])
-                ->execute();
-            $count++;
-
-            // 支持 sleepMs 降低数据库压力
-            if ($this->sleepMs > 0) {
-                usleep($this->sleepMs * 1000);
+
+            // 使用主键游标分页查询 ID(利用主键索引,性能极高,避免大表全表扫描)
+            if ($lastId === null) {
+                $ids = $db->createCommand("SELECT id FROM xhClear ORDER BY id DESC LIMIT :limit")
+                    ->bindValue(':limit', $currentBatchSize)
+                    ->queryColumn();
+            } else {
+                $ids = $db->createCommand("SELECT id FROM xhClear WHERE id < :lastId ORDER BY id DESC LIMIT :limit")
+                    ->bindValues([':lastId' => $lastId, ':limit' => $currentBatchSize])
+                    ->queryColumn();
             }
+
+            if (empty($ids)) {
+                break;
+            }
+
+            // 循环更新当前批次的记录
+            foreach ($ids as $id) {
+                if ($this->dryRun) {
+                    $this->stdout("[dry-run] xhClear id={$id}\n");
+                    $processed++;
+                    continue;
+                }
+
+                // 重新生成 10 位随机 salt 并更新
+                $salt = stringUtil::charsShuffleLowerCase(10);
+                $db->createCommand("UPDATE xhClear SET salt = :salt WHERE id = :id")
+                    ->bindValues([':salt' => $salt, ':id' => $id])
+                    ->execute();
+                $processed++;
+
+                // 每次更新后休眠,降低数据库写入压力
+                if ($this->sleepMs > 0) {
+                    usleep($this->sleepMs * 1000);
+                }
+            }
+
+            // 更新游标为当前批次中最小的 ID
+            $lastId = min($ids);
+            $this->stdout("xhClear 已处理 {$processed} 条记录,当前 ID 游标: {$lastId}\n");
         }
-        $this->stdout("xhClear salt 全部重新设置完成,共处理 {$count} 条记录\n");
+
+        $this->stdout("xhClear salt 全部重新设置完成,共处理 {$processed} 条记录\n");
         return ExitCode::OK;
     }
 
     /**
      * 补充 xhSettle 结算单历史数据的 salt 字段
-     * 职责:查询全部 xhSettle 记录,循环重新生成并设置 salt
+     * 职责:利用主键游标进行分页查询,分批重新生成并设置 salt,确保线上大表安全
      */
     public function actionFillSettle()
     {
         $db = Yii::$app->db;
-        // 查询全部结算单 ID
-        $ids = $db->createCommand("SELECT id FROM xhSettle ORDER BY id DESC")->queryColumn();
-        $count = 0;
-        foreach ($ids as $id) {
-            // 支持 limit 参数限制更新数量
-            if ($this->limit > 0 && $count >= $this->limit) {
+        $this->stdout("开始分页重新设置 xhSettle 表的 salt 字段...\n");
+
+        $processed = 0;
+        $lastId = null;
+        $batchSize = $this->batchSize > 0 ? $this->batchSize : 1000;
+
+        while (true) {
+            // 如果设置了 limit 且已达到上限,则退出
+            if ($this->limit > 0 && $processed >= $this->limit) {
                 break;
             }
-            if ($this->dryRun) {
-                $this->stdout("[dry-run] xhSettle id={$id}\n");
-                $count++;
-                continue;
+
+            // 计算当前批次需要查询的数量
+            $currentBatchSize = $batchSize;
+            if ($this->limit > 0) {
+                $currentBatchSize = min($batchSize, $this->limit - $processed);
             }
-            // 重新生成 10 位随机 salt 并更新
-            $salt = stringUtil::charsShuffleLowerCase(10);
-            $db->createCommand("UPDATE xhSettle SET salt = :salt WHERE id = :id")
-                ->bindValues([':salt' => $salt, ':id' => $id])
-                ->execute();
-            $count++;
-
-            // 支持 sleepMs 降低数据库压力
-            if ($this->sleepMs > 0) {
-                usleep($this->sleepMs * 1000);
+
+            // 使用主键游标分页查询 ID(利用主键索引,性能极高,避免大表全表扫描)
+            if ($lastId === null) {
+                $ids = $db->createCommand("SELECT id FROM xhSettle ORDER BY id DESC LIMIT :limit")
+                    ->bindValue(':limit', $currentBatchSize)
+                    ->queryColumn();
+            } else {
+                $ids = $db->createCommand("SELECT id FROM xhSettle WHERE id < :lastId ORDER BY id DESC LIMIT :limit")
+                    ->bindValues([':lastId' => $lastId, ':limit' => $currentBatchSize])
+                    ->queryColumn();
             }
+
+            if (empty($ids)) {
+                break;
+            }
+
+            // 循环更新当前批次的记录
+            foreach ($ids as $id) {
+                if ($this->dryRun) {
+                    $this->stdout("[dry-run] xhSettle id={$id}\n");
+                    $processed++;
+                    continue;
+                }
+
+                // 重新生成 10 位随机 salt 并更新
+                $salt = stringUtil::charsShuffleLowerCase(10);
+                $db->createCommand("UPDATE xhSettle SET salt = :salt WHERE id = :id")
+                    ->bindValues([':salt' => $salt, ':id' => $id])
+                    ->execute();
+                $processed++;
+
+                // 每次更新后休眠,降低数据库写入压力
+                if ($this->sleepMs > 0) {
+                    usleep($this->sleepMs * 1000);
+                }
+            }
+
+            // 更新游标为当前批次中最小的 ID
+            $lastId = min($ids);
+            $this->stdout("xhSettle 已处理 {$processed} 条记录,当前 ID 游标: {$lastId}\n");
         }
-        $this->stdout("xhSettle salt 全部重新设置完成,共处理 {$count} 条记录\n");
+
+        $this->stdout("xhSettle salt 全部重新设置完成,共处理 {$processed} 条记录\n");
         return ExitCode::OK;
     }