場景:庫 A 的 user(uid, username, email, password, regdate, salt) 導入庫 B 的 account(id, name, email, password, type, salt),僅導入 username, email, password, salt 且 regdate > 1418313600。本文對比四種導入策略的行為差異與適用場景。
-- 庫 A
CREATE TABLE `A`.`user` (
`uid` INT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL UNIQUE,
`email` VARCHAR(100),
`password` CHAR(64),
`regdate` INT,
`salt` CHAR(16)
);
-- 庫 B
CREATE TABLE `B`.`account` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL UNIQUE,
`email` VARCHAR(100),
`password` CHAR(64),
`type` TINYINT DEFAULT 0,
`salt` CHAR(16)
);
| 策略 | SQL 範例 | 衝突行為 | 適用場景 | 風險 |
|---|---|---|---|---|
| INSERT INTO | INSERT INTO B.account(name,email,password,salt) SELECT username,email,password,salt FROM A.user WHERE regdate>1418313600; | 主鍵/唯一鍵衝突報錯,整條語句回滾 | 目標表確定無衝突(全新導入) | 衝突導致全量失敗 |
| REPLACE INTO | REPLACE INTO B.account(name,email,password,salt) SELECT username,email,password,salt FROM A.user WHERE regdate>1418313600; | 衝突時先刪除整行再插入,非導入列(如 type)重置為默認值 | 需覆蓋整行、非導入列可重置 | 誤刪寶貴數據(type、創建時間等) |
| INSERT IGNORE | INSERT IGNORE INTO B.account(name,email,password,salt) SELECT username,email,password,salt FROM A.user WHERE regdate>1418313600; | 衝突行靜默跳過,不報錯、不寫入 | 增量同步、只補缺漏、不覆蓋舊數據 | 無法更新已有行的變更字段 |
| INSERT ... ON DUPLICATE KEY UPDATE | INSERT INTO B.account(name,email,password,salt) SELECT username,email,password,salt FROM A.user WHERE regdate>1418313600 ON DUPLICATE KEY UPDATE password=VALUES(password), salt=VALUES(salt); | 衝突時只更新指定列,保留其它列原值 | 增量同步且需更新部分字段(如密碼、鹽值) | 需明確列出更新列,略繁瑣 |
以上三種「衝突感知」策略(REPLACE/IGNORE/ON DUPLICATE KEY)要求目標表有主鍵或唯一索引。本例中 B.account.name 已有 UNIQUE,滿足條件。
若庫 A、B 在不同物理機:
mysqldump -h hostA -u u -p A user | mysql -h hostB -u u -p B 先同步到 B 庫臨時表,再跑上述跨表 SQL。INSERT ... SELECT,但效能差、不支援事務,不推薦生產大量數據。type、created_at)。SET autocommit=0; SET unique_checks=0; SET foreign_key_checks=0; 導入後恢復,顯著提速(InnoDB)。SELECT COUNT(*), COUNT(DISTINCT name) FROM B.account; 確認行數與唯一鍵數一致。「INSERT 保守、REPLACE 暴力、IGNORE 保守、ON DUPLICATE KEY 精準」——按業務對數據覆蓋/保留的容忍度選擇,跨庫導入不再踩坑。