背景:
数据库是 mysql 5.7, 表结构: id data modified_time data 是一个很长的 json 串,需求是批量插入每次最多要几千条,插入前比较 modified_time 和插入的数据比较,时间戳比较新的插入,否则失败 现在我的做法是用 insert into on ON DUPLICATE KEY UPDATE,但是如何比较这个时间就不会了,试了用触发器来写,但是批量插入如果有一条时间对不上的话,整个 sql 就不会再执行了,没办法跳过,请教大家有更好的做法吗
![]() | 1 encro 2020-02-21 14:58:24 +08:00 一条一条插入,然后采用事务批量提交看看,性能也可以的。 |
![]() | 3 hhyvs111 2020-02-21 15:46:17 +08:00 via iPhone 不要在数据库里弄触发器之类的,后期很难维护,建议在逻辑层去判断这个时间。 |
![]() | 4 encro 2020-02-21 15:57:24 +08:00 采用事务提交后,应该几秒钟可以插入几千条吧,你 modified_time 没有索引? 其实这个方案不好,因为 modified_time 可能存在同一秒有多条数据吧。 不知道你具体的需求场景是什么,脱离需求场景谈 SQL 优化很不靠谱。 |
5 zjq123 2020-02-21 16:04:29 +08:00 via iPad 弄张临时内存表 insert into xx select from a join b ... where |
6 littlewing 2020-02-21 16:10:25 +08:00 multi query |
![]() | 7 jswh 2020-02-21 16:12:51 +08:00 一次几千应该也不多吧,先把 id 对应的 time 一次都拿出来,在代码里比较确定要不要插入就好了。 |
![]() | 8 akira 2020-02-21 18:07:45 +08:00 先插入到一个表,然后再把数据更新过来 |
![]() | 12 encro 2020-02-21 20:49:29 +08:00 采用事务后,如果几千条数据,插入更新下应该几秒钟搞定了。前提是建立了合理的索引。当然如果你 data 非常大可能久一点。 你这个需求还是不明确,INSERT ... ON DUPLICATE KEY UPDATE Statement 的意思如果唯一索引不存在就插入否则更新。并不能指定其他条件。这篇文章讲得很清楚了 https://blog.csdn.net/analogous_love/article/details/71085001。官方语法也没有提供扩展 https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html。 所以除非你是根据 ID 来的,或者定了一个唯一索引。且实际不是你说的 “比较新的插入,否则失败”。 我理解你的需求应该是“如果数据有更新,那么执行更新,否则忽略这个数据更新。” 如果是我理解的,那么方案是: update order set data=new_data where id=xxx and modified_time < new_time; (只需要 id 主键即可,性能最好) 比如你的目的表数据不全部来自来源表,那么可能需要加一个唯一索引字段 from_id update order set data=new_data where from_id=xxx and modified_time < new_time;(需要对 from_id 建立唯一索引) 你首先要做的是,确定性能问题出在查找数据时的读取磁盘速度慢还是写入磁盘慢。 |
![]() | 13 MoYi123 2020-02-21 22:14:08 +08:00 直接不检查直接插入,查找时候找时间戳最大的那条,定时删除过期数据,这样的话需要经常重建索引。如果量特别大可以考虑时序数据库。 |
14 mawerss1 OP @encro 还是我没有说清楚,场景是一个接受数据的推送库,这个库是没有任何操作权限,只能查询,要查询推送库里的数据到业务库,这两个库表结构是不同的要对数据做些处理,另外还有别的应用对业务库插入,主要还要新增插入,只靠 update 不行,所以用了 insert on dup key,看来还是要在程序里查询 modified 时间进行比较,然后决定是 insert 还是 update |
![]() | 16 ASpiral 2020-02-21 23:21:05 +08:00 建个中间表,把数据都插进去;写个存储过程,把中间表的数据有选择性地插入目标表,再清空中间表;不知这样会不会比较快… |
![]() | 17 wind3110991 2020-02-22 01:00:57 +08:00 碰什么都不要碰触发器,坑死你,而且你的 mysql 版本也太低了,是大厂吗 |
![]() | 18 llussy 2020-02-22 07:49:49 +08:00 via iPhone @wind3110991 大厂都是 8.0 吗?我们还是 5.6 呢 |
19 polymerdg 2020-02-22 08:35:14 +08:00 1000 不多 事 查出 在代里比较后插入即可 |
21 anjuyiyu 2020-02-22 12:42:38 +08:00 id + 时间做一个临时表? 另:这里是否可以考虑下时间分片做日结表? |
![]() | 22 Aresxue 2020-02-24 16:54:01 +08:00 1.别用触发器; 2.考虑做分表; 3.在代码里做好数据的清洗,最好是先删除数据库中较老时间的数据然后再插入,能不用 update 就尽量规避; 4.注意调整 max_allowed_packet 的限制。 |