where('id', '>', $lastId) ->where('createtime', '>=', $startTime) ->where('createtime', '<', $endTime) ->order('id', 'asc') ->limit($batchSize) ->select(); if (empty($records)) { $hasMore = false; break; } // 转换数据格式,生成雪花ID $dataToInsert = []; foreach ($records as $record) { $newRecord = [ 'id' => Snowflake::generate(), 'user_id' => $record['user_id'] ?? 0, 'gift_id' => $record['gift_id'] ?? 0, 'gift_type' => $record['gift_type'] ?? 1, 'number' => $record['number'] ?? 0, 'gift_user' => $record['gift_user'] ?? 0, 'from_id' => $record['from_id'] ?? 0, 'pit_number' => $record['pit_number'] ?? 0, 'total_price' => $record['total_price'] ?? 0, 'type' => $record['type'] ?? 1, 'from' => $record['from'] ?? 1, 'createtime' => $record['createtime'] ?? time(), 'updatetime' => $record['updatetime'] ?? time(), ]; $dataToInsert[] = $newRecord; $lastId = $record['id']; // 使用原始表的ID } // 批量插入到分表 if (!empty($dataToInsert)) { Db::table($targetTable)->insertAll($dataToInsert); $totalMigrated += count($dataToInsert); Log::info("迁移批次成功: {$yearMonth}, 本批: " . count($dataToInsert) . " 条,总计: {$totalMigrated} 条"); } // 防止内存占用过高 unset($records, $dataToInsert); // 小睡一下,防止CPU占用过高 usleep(10000); } catch (\Exception $e) { Log::error("迁移 {$yearMonth} 数据失败: " . $e->getMessage()); return [ 'success' => false, 'message' => $e->getMessage(), 'total' => $totalMigrated, 'last_id' => $lastId ]; } } Log::info("完成迁移 {$yearMonth} 数据,总计: {$totalMigrated} 条"); return [ 'success' => true, 'message' => '迁移完成', 'total' => $totalMigrated, 'last_id' => $lastId ]; } /** * 迁移所有历史数据 * @param int $batchSize 每批数量 * @return array */ public static function migrateAllData($batchSize = 1000) { // 获取所有需要迁移的月份 $firstRecord = Db::name('vs_give_gift') ->where('createtime', '>', 0) ->order('createtime', 'asc') ->find(); $lastRecord = Db::name('vs_give_gift') ->where('createtime', '>', 0) ->order('createtime', 'desc') ->find(); if (!$firstRecord || !$lastRecord) { return ['success' => true, 'message' => '没有数据需要迁移']; } $startMonth = date('Ym', $firstRecord['createtime']); $endMonth = date('Ym', $lastRecord['createtime']); // 生成月份列表 $months = self::generateMonthRange($startMonth, $endMonth); Log::info("开始迁移数据,月份范围: {$startMonth} 到 {$endMonth},共 " . count($months) . " 个月"); $results = []; foreach ($months as $month) { Log::info("开始迁移 {$month} 数据"); $result = self::migrateMonthData($month, $batchSize); $results[$month] = $result; if (!$result['success']) { Log::error("迁移 {$month} 数据失败,停止迁移"); break; } Log::info("完成迁移 {$month} 数据,共 {$result['total']} 条"); } return [ 'success' => true, 'message' => '所有数据迁移完成', 'results' => $results ]; } /** * 生成月份范围 * @param string $startMonth 202401 * @param string $endMonth 202412 * @return array */ private static function generateMonthRange($startMonth, $endMonth) { $start = new \DateTime($startMonth . '01'); $end = new \DateTime($endMonth . '01'); $months = []; while ($start <= $end) { $months[] = $start->format('Ym'); $start->modify('+1 month'); } return $months; } /** * 获取迁移进度 * @return array */ public static function getMigrationProgress() { // 查询原始表数据量 $totalCount = Db::name('vs_give_gift')->count(); // 查询已迁移的数据量 $migratedCount = 0; $tables = GiftTableManager::getAllTables(); foreach ($tables as $tableInfo) { try { $count = Db::table($tableInfo['table_name'])->count(); $migratedCount += $count; } catch (\Exception $e) { // 表可能不存在,跳过 } } $progress = $totalCount > 0 ? round($migratedCount / $totalCount * 100, 2) : 0; return [ 'total' => $totalCount, 'migrated' => $migratedCount, 'progress' => $progress, 'remaining' => $totalCount - $migratedCount ]; } /** * 验证迁移数据一致性 * @param string $yearMonth 年月 * @return array */ public static function verifyMigration($yearMonth) { $startTime = strtotime($yearMonth . '01 00:00:00'); $endTime = strtotime(date('Y-m-01', strtotime('+1 month', $startTime))); // 原始表数据量 $sourceCount = Db::name('vs_give_gift') ->where('createtime', '>=', $startTime) ->where('createtime', '<', $endTime) ->count(); // 目标表数据量 $targetTable = 'fa_vs_give_gift_' . $yearMonth; $targetCount = 0; try { $targetCount = Db::table($targetTable)->count(); } catch (\Exception $e) { Log::error("验证迁移数据失败,目标表不存在: " . $targetTable); } // 比较总价值 $sourceTotalPrice = Db::name('vs_give_gift') ->where('createtime', '>=', $startTime) ->where('createtime', '<', $endTime) ->sum('total_price'); $targetTotalPrice = 0; try { $targetTotalPrice = Db::table($targetTable)->sum('total_price'); } catch (\Exception $e) { // 表可能不存在 } return [ 'source_count' => $sourceCount, 'target_count' => $targetCount, 'count_match' => $sourceCount == $targetCount, 'source_total_price' => $sourceTotalPrice, 'target_total_price' => $targetTotalPrice, 'price_match' => abs(floatval($sourceTotalPrice) - floatval($targetTotalPrice)) < 0.01 ]; } }