萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL REPLACE() 函數實戰:字串批量替換、巢狀替換、效能與陷阱全解析

基本語法

REPLACE(str, from_str, to_str)
  • 返回將 str 中**所有** from_str 替換為 to_str 後的新字串。
  • 區分大小寫(依欄位校對規則,utf8mb4_general_ci 不區分)。
  • from_str 不能為空字串,否則返回原字串。

UPDATE 批量替換欄位內容

UPDATE `table_name` 
SET `field_name` = REPLACE(`field_name`, 'from_str', 'to_str')
WHERE `field_name` LIKE '%from_str%';
  • WHERE 子句可利用索引快速縮小掃描範圍,**務必加上**。
  • 無 WHERE 會全表掃描並觸發大量行鎖/寫入,極其危險。

實戰範例

1. 域名遷移

UPDATE client_table 
SET url = REPLACE(url, 'old-domain.com', 'new-domain.com')
WHERE url LIKE '%old-domain.com%';

2. 清理 HTML 標籤

UPDATE dede_addonarticle 
SET body = REPLACE(body, '', ''),
    body = REPLACE(body, '', ''),
    body = REPLACE(body, '', ''),
    body = REPLACE(body, '../../../../../../', 'https://special.fsaf/meal/');

⚠️ 多次 REPLACE 可鏈式寫在同一 SET,單次掃描完成多重替換。

3. 標題去除固定前綴

UPDATE dede_archives 
SET title = REPLACE(title, '大洋新聞 - ', '')
WHERE title LIKE '大洋新聞 - %';

進階技巧

巢狀 REPLACE(多模式替換)

-- 將 a→b, b→c 同時處理(避免 a→b→c 連鎖)
SELECT REPLACE(REPLACE(str, 'a', '|TEMP|'), 'b', 'c');  -- 需臨時佔位符

配合 CASE WHEN 條件替換

UPDATE products
SET description = CASE
    WHEN description LIKE '%舊詞1%' THEN REPLACE(description, '舊詞1', '新詞1')
    WHEN description LIKE '%舊詞2%' THEN REPLACE(description, '舊詞2', '新詞2')
    ELSE description
END;

跨表同步替換

UPDATE target t
JOIN source s ON t.id = s.id
SET t.content = REPLACE(t.content, s.old_val, s.new_val);

效能與限制

層面說明
索引使用WHERE col LIKE 'prefix%' 可用索引;%prefix% 全表掃描
鎖行數影響行數 = WHERE 篩選行數,大批次建議分塊 (LIMIT 1000 循環)
Binlog 體積Row 格式記錄完整前後值,大量替換會暴增 Binlog,影響主從延遲
字元集若 from_str/to_str 編碼與欄位不一致,可能導致截斷或亂碼
最大長度受限於欄位定義,超長會截斷並警告(嚴格模式報錯)

大表安全替換腳本範例

<?php
$pdo = new PDO('mysql:host=localhost;dbname=db;charset=utf8mb4', 'user', 'pass');
$batchSize = 1000;
$offset = 0;

while (true) {
    $stmt = $pdo->prepare("
        UPDATE large_table 
        SET content = REPLACE(content, 'old', 'new')
        WHERE content LIKE '%old%'
        LIMIT :limit OFFSET :offset
    ");
    $stmt->bindValue(':limit', $batchSize, PDO::PARAM_INT);
    $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
    $affected = $stmt->execute() ? $stmt->rowCount() : 0;
    echo "Batch offset $offset: $affected rows updated\n";
    if ($affected < $batchSize) break;
    $offset += $batchSize;
    usleep(100000); // 0.1s 緩衝,減輕主從壓力
}

總結

REPLACE() 是 MySQL 字串處理的瑞士刀。**永遠加 WHERE 縮小範圍、大表分批執行、關注 Binlog 膨脹、驗證字元集一致性**。複雜多模式替換請在應用層處理或用 REGEXP_REPLACE (MySQL 8.0+),單純定點替換 REPLACE() 最簡高效。

copyright © 萬盛學電腦網 all rights reserved