Mysql "insert ... on duplicate key update "和"replace into"

1. INSERT ... ON DUPLICATE KEY UPDATE

http://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html

insert into tableName values (1,  "testvalue", now()) on duplicate key update value=values(value), gmt_modify=values(gmt_modify);

前置条件:

      1. 一定要有主键,或者唯一索引

      2. 确认需求是,欲插入的记录在主键存在的情况下,需要做update, 否则执行insert.

 

语法解释:

      该语法可能要执行的动作是insert/update。

      如果主键已存在,执行update,否则执行insert。

 

说明:

      1. update 可更新多个字段

      2. 更新值可以从values中获取,也可自定义。

 

2. REPLACE

http://dev.mysql.com/doc/refman/5.6/en/replace.html

 

replace有多种用法,我只介绍replace into。

replace into tableName(id,value, gmt_modify) values(1, "testvalue", now());

前置条件:

      1. 一定要有主键,或者唯一索引

 

语法解释:

      该语法可能要执行的动作是insert/delete&insert。

      如果主键已存在,先删后增,否则执行insert。

 

 

<think> 我们之前讨论了MySQLREPLACE操作的效率,现在用户想了解INSERT ... ON DUPLICATE KEY UPDATE(以下简称IODKU)的效率使用情况,特别是与REPLACE操作(REPLACE INTO)的对比。根据引用,我们可以从以下几个方面分析: 1. **效率对比**:引用[3]提到,使用UPDATE更新数据速度为2000/s,而使用IODKU更新速度达到40000/s,效率提升显著。而REPLACE INTO在冲突时是先删除再插入,IODKU则是直接更新,避免了删除操作的开销,因此在更新操作时IODKU效率更高。 2. **工作原理**:IODKU在遇到主键或唯一键冲突时,执行UPDATE操作(只更新指定字段),而不是删除整行再插入。这减少了索引变动、触发器触发(如删除相关的触发器)以及自增ID的浪费。 3. **使用场景**:适合需要根据唯一键判断记录是否存在,存在则更新部分字段,不存在则插入的场景。如用户引用[4]中的例子:记录用户对单词的录音,如果已有记录则更新录音路径时间。 4. **使用方法**:基本语法如下: ```sql INSERT INTO table (col1, col2, ...) VALUES (val1, val2, ...) ON DUPLICATE KEY UPDATE col1 = val1, col2 = val2, ...; ``` 注意:UPDATE后面可以更新为新的值,也可以引用VALUES函数来使用插入时的值,例如: ```sql INSERT INTO test (a, b) VALUES (1, 2) ON DUPLICATE KEY UPDATE b = VALUES(b); ``` 5. **与REPLACE INTO的对比**: - **操作差异**:REPLACE INTO是删除后插入,整行替换;IODKU是直接更新部分列。 - **效率**:IODKU在更新时效率更高(避免删除重新插入,减少索引维护)。 - **自增ID**:REPLACE INTO会改变自增ID(旧行删除,新行插入,自增ID增加),而IODKU不会(因为只是更新,原ID保留)。 - **触发器**:REPLACE INTO会触发DELETEINSERT触发器,而IODKU只触发UPDATE触发器(如果存在)INSERT触发器(当插入时)或UPDATE(当更新时)。 6. **注意事项**: - 必须存在主键或唯一索引才能触发更新。 - 在高并发下,IODKU比REPLACE INTO性能更好,因为减少了锁的持有时间(引用[3]的实践数据)。 - 使用IODKU会绑定MySQL(引用[1]),因为这是MySQL的扩展语法。 7. **优化建议**: - 只更新需要变更的字段,避免不必要的更新。 - 如果不需要更新所有字段,在UPDATE子句中只列出需要更新的字段。 结合用户之前的问题(REPLACE效率),我们可以这样总结: - 在需要更新部分字段且存在冲突的情况下,优先使用IODKU,因为它效率更高(引用[3]的数据)。 - 在需要整行替换时(即冲突时希望用新数据完全覆盖旧数据),可以使用REPLACE INTO,但要注意其效率较低以及自增ID变化的问题。 接下来,我们将详细说明IODKU的使用方法效率分析。 </think>### MySQL中`INSERT ... ON DUPLICATE KEY UPDATE`效率与使用分析 结合您关注的效率对比(特别是与`REPLACE INTO`的对比)以及引用内容,以下从效率机制、使用方法场景建议展开: --- ### 一、核心效率机制 #### 1. **与`REPLACE INTO`的效率对比** | **操作** | **底层行为** | **效率优势** | **效率劣势** | |-------------------------------|-----------------------------|---------------------------------------------------|-------------------------------------| | **REPLACE INTO** | 冲突时:先删除旧行 → 插入新行 | 逻辑简单,适合整行替换 | 1. 自增ID不连续<br>2. 触发`DELETE`触发器<br>3. 索引重建成本高 | | **ON DUPLICATE KEY UPDATE** | 冲突时:直接更新指定字段 | 1. **避免删除操作**<br>2. **仅更新差异字段**<br>3. **保留原自增ID** | 需显式指定更新字段 | **实测数据**(引用[3]): - `UPDATE`:约 2000次/秒 - `ON DUPLICATE KEY UPDATE`:约 **40000次/秒**(效率提升20倍)[^3] > 原因:避免行删除重建,减少I/O索引维护。 #### 2. **高效原理** - **最小化写操作**:仅修改冲突字段(如引用[4]中只更新`path``time`)[^4] - **原子性保证**:单语句完成"存在则更新,不存在则插入",减少事务开销[^2] - **锁优化**:InnoDB引擎下行级锁,并发性能更高(对比`REPLACE INTO`的表级锁风险) --- ### 二、使用方法与示例 #### 1. **基础语法** ```sql INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...) ON DUPLICATE KEY UPDATE 列1 = 新值1, 列2 = 新值2; ``` #### 2. **实战案例** **场景**:记录用户单词录音,存在相同记录时更新路径时间(引用[4])[^4] ```sql INSERT INTO kid_big_cat_course_word_recording (user_id, word_id, path, time) VALUES (#{userId}, #{pk}, #{path}, NOW()) ON DUPLICATE KEY UPDATE path = VALUES(path), -- 使用VALUES()引用插入值 time = NOW(); ``` > **关键技巧**: > - 使用`VALUES(列名)`获取插入值,避免重复传参 > - 只更新必要字段(`path``time`) #### 3. **自动识别冲突** - **触发条件**:主键(Primary Key)或唯一索引(Unique Index)冲突 - **错误写法**: ```sql ON DUPLICATE KEY UPDATE path = 'new_path'; -- 直接赋固定值(错误!) ``` - **正确写法**: ```sql ON DUPLICATE KEY UPDATE path = VALUES(path); -- 动态引用插入值[^4] ``` --- ### 三、适用场景与限制 #### ✅ **推荐场景** 1. **高并发写入**(如计数器、实时日志) ```sql INSERT INTO page_views (page_id, views) VALUES (123, 1) ON DUPLICATE KEY UPDATE views = views + 1; -- 原子性递增 ``` 2. **数据同步**(避免`SELECT`检查存在性)[^2] 3. **部分字段更新**(如用户配置表,仅更新最后修改时间)[^4] #### ⚠️ **使用限制** 1. **数据库绑定**:MySQL特有语法,迁移到其他数据库需重写(引用[1])[^1] 2. **更新字段**:必须显式列出需更新的列(`REPLACE INTO`默认更新所有列) 3. **触发器行为**: - 冲突时触发`BEFORE UPDATE``AFTER UPDATE` - **不触发**`DELETE`相关触发器(与`REPLACE INTO`关键区别) --- ### 四、性能优化建议 1. **精简更新字段** ```sql -- 只更新必要字段 ON DUPLICATE KEY UPDATE status = VALUES(status), update_time = NOW(); -- 而非更新所有列 ``` 2. **避免全表更新** 结合`WHERE`条件限制范围(但需注意:WHERE在IODKU中无效,需前置过滤数据) 3. **索引优化** - 确保冲突检测列(主键/唯一索引)覆盖高频查询 - 避免对更新列建立过多索引(减少写放大) 4. **批量操作加速** ```sql INSERT INTO table (id, data) VALUES (1, 'a'), (2, 'b'), (3, 'c') ON DUPLICATE KEY UPDATE data = VALUES(data); ``` --- ### 五、总结:何时选择`ON DUPLICATE KEY UPDATE` | **需求** | 推荐方案 | |-------------------------|----------------------------| | 冲突时需**更新部分字段** | ✅ `ON DUPLICATE KEY UPDATE` | | 冲突时需**完全替换整行** | ⚠️ `REPLACE INTO`(注意副作用) | | 需要**保留原自增ID** | ✅ `ON DUPLICATE KEY UPDATE` | | 高并发增量更新(如计数器) | ✅ `ON DUPLICATE KEY UPDATE` | > **结论**:在更新为主的场景中,`ON DUPLICATE KEY UPDATE`因避免删除操作精准字段更新,效率显著高于`REPLACE INTO`(引用[3]实测数据验证)[^3]。唯需注意其MySQL依赖性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值