diff --git a/app/Console/Commands/TransferSqliteToMysql.php b/app/Console/Commands/TransferSqliteToMysql.php index 87b6aa0..8e34924 100644 --- a/app/Console/Commands/TransferSqliteToMysql.php +++ b/app/Console/Commands/TransferSqliteToMysql.php @@ -48,23 +48,28 @@ class TransferSqliteToMysql extends Command $this->info("📦 Transferring table: {$table}"); try { - // 從 SQLite 資料庫讀取資料 - $records = DB::connection('sqlite')->table($table)->get(); + // 用 cursor 來避免一次性佔用過多記憶體 + $rows = DB::connection('sqlite')->table($table)->cursor(); - if ($records->isEmpty()) { - $this->warn("⚠️ Table {$table} has no data."); - continue; + $buffer = []; + $count = 0; + + foreach ($rows as $row) { + $buffer[] = (array) $row; + $count++; + + if ($count % 500 === 0) { + DB::connection($mysqlConnection)->table($table)->insert($buffer); + $buffer = []; // 清空 buffer + } } - // 資料分批處理,避免一次插入過多資料造成效能問題 - $chunks = $records->chunk(500); - foreach ($chunks as $chunk) { - DB::connection($mysqlConnection)->table($table)->insert( - $chunk->map(fn ($row) => (array) $row)->toArray() - ); + // 插入剩下的資料 + if (!empty($buffer)) { + DB::connection($mysqlConnection)->table($table)->insert($buffer); } - $this->info("✅ Done: {$table}"); + $this->info("✅ Done: {$table} ({$count} records)"); } catch (\Exception $e) { $this->error("❌ Failed to transfer {$table}: " . $e->getMessage()); } diff --git a/app/Jobs/ImportArtistChunkJob.php b/app/Jobs/ImportArtistChunkJob.php index 422d084..3bb0188 100644 --- a/app/Jobs/ImportArtistChunkJob.php +++ b/app/Jobs/ImportArtistChunkJob.php @@ -36,7 +36,7 @@ class ImportArtistChunkJob implements ShouldQueue $now = now(); foreach ($this->rows as $index => $row) { try { - $name = trim($row['歌手姓名'] ?? ''); + $name = $this->normalizeName($row['歌手姓名'] ?? ''); if (empty($name) || Artist::where('name', $name)->exists()) { continue; @@ -79,4 +79,9 @@ class ImportArtistChunkJob implements ShouldQueue } Artist::insert($toInsert); } + + public function normalizeName(?string $str): string + { + return strtoupper(mb_convert_kana(trim($str ?? ''), 'as')); + } } \ No newline at end of file diff --git a/app/Jobs/ImportSongChunkJob.php b/app/Jobs/ImportSongChunkJob.php index ac36604..47045e0 100644 --- a/app/Jobs/ImportSongChunkJob.php +++ b/app/Jobs/ImportSongChunkJob.php @@ -52,7 +52,7 @@ class ImportSongChunkJob implements ShouldQueue try { // 字元處理 - $songName=trim($row['歌名'] ?? ''); + $songName=$this->normalizeName($row['歌名'] ?? ''); $simplified=ChineseNameConverter::convertToSimplified($songName);// 繁體轉簡體 if (!$row->has('注音')) { $phoneticAbbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);// 注音符號 @@ -104,11 +104,11 @@ class ImportSongChunkJob implements ShouldQueue // 處理關聯 - 歌手 $artistIds = []; foreach (['歌星A', '歌星B'] as $key) { - $artistName = trim($row[$key] ?? ''); + $artistName = $this->normalizeName($row[$key] ?? ''); if ($artistName === '') continue; // 若是歌星B,且與歌星A相同,則跳過 - if ($key === '歌星B' && $artistName === trim($row['歌星A'] ?? '')) continue; + if ($key === '歌星B' && $artistName === $this->normalizeName($row['歌星A'] ?? '')) continue; $artistMap[$songId][] = $this->getOrCreateArtistId($artistName); } @@ -160,6 +160,12 @@ class ImportSongChunkJob implements ShouldQueue return $this->artistCache[$name] = $artist->id; } + + public function normalizeName(?string $str): string + { + return strtoupper(mb_convert_kana(trim($str ?? ''), 'as')); + } + protected function formatText($value) { if (is_numeric($value) && $value < 1 && $value > 0) {