在MySQL中盲目使用INSERT是否有缺点?

时间:2008-09-29 17:37:58

标签: sql mysql

我经常想要为表添加一个值,或者如果它的键已经存在则更新该值。这可以通过多种方式实现,假设在示例中的'user_id'和'pref_key'列上设置了主键或唯一键:

1。盲插,如果收到重复键错误则更新:

// Try to insert as a new value
INSERT INTO my_prefs 
(user_id, pref_key, pref_value)
VALUES (1234, 'show_help', 'true');

// If a duplicate-key error occurs run an update query
UPDATE my_prefs 
SET pref_value = 'true'
WHERE user_id=1234 AND pref_key='show_help';

2。检查是否存在,然后选择或更新:

// Check for existence
SELECT COUNT(*) 
FROM my_prefs
WHERE user_id=1234 AND pref_key='show_help';

// If count is zero, insert
INSERT INTO my_prefs 
(user_id, pref_key, pref_value) 
VALUES (1234, 'show_help', 'true');

// If count is one, update
UPDATE my_prefs 
SET pref_value = 'true' 
WHERE user_id=1234 AND pref_key='show_help';

第一种方式似乎更可取,因为它只需要一个查询用于新插入,两个用于更新,其中第二种方式总是需要两个查询。是否有任何我想念的东西虽然盲目地插入会是一个坏主意?

9 个答案:

答案 0 :(得分:12)

查看http://dev.mysql.com/doc/refman/5.0/en/insert-select.html

中的ON DUPLICATE KEY语法
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

答案 1 :(得分:7)

有第三种MySQL方式,这是RDBMS

中首选的方式
INSERT INTO my_prefs 
(user_id, pref_key, pref_value) 
VALUES (1234, 'show_help', 'true')
ON DUPLICATE KEY 
UPDATE pref_value = 'true'

答案 2 :(得分:4)

就我个人而言,我从不喜欢基于异常的编程(期望在应用程序的正常操作中出现异常),对我而言,第二个示例更具可读性/可维护性。

在某些情况下,这会产生影响(例如非常严格的循环),但我认为应该有一个很好的理由来编写这样的代码而不是默认代码。

答案 3 :(得分:3)

如果你想通过插入双重调整来避免“异常”并且你想使用标准SQL(并且你的编程语言/数据库返回更新行的计数)那么使用下面的“SQL” - 命令(伪-code):

int i = SQL("UPDATE my_prefs ...");
if(i==0) {
    SQL("INSERT INTO my_prefs ...");
}

这也考虑到 - 对于大多数用例 - 更新确实比插入更频繁。

答案 4 :(得分:2)

您可能可以使用REPLACE,或者如果使用更新的MySQL,您可以选择使用“INSERT ... ON DUPLICATE KEY UPDATE

有几个人快速连续提起这个事实说“当你遇到问题时,总是检查MySQL文档”,因为它们很不错,在许多情况下直接导致解决方案。

答案 5 :(得分:2)

这些行会有并发INSERT吗?的DELETE

“ON DUPLICATE”听起来很棒(行为正是你想要的)只要你不关心非MySQL数据库的可移植性。

“盲插”似乎合理且健壮,前提是永远不会删除行。 (如果由于行存在而INSERT大小写失败,则后续的UPDATE应该成功,因为该行仍然存在。但是如果删除行则假设为假 - 那么您需要重试逻辑。)在没有“ON DUPLICATE”的其他数据库上,如果发现延迟不好,可以考虑进行优化:通过将此逻辑放在存储过程中,可以避免已存在的数据库往返。

如果存在并发INSERT,那么“检查存在”是非常棘手的。可以在SELECT和UPDATE之间添加行。事务甚至不会真正有用 - 我认为即使在隔离级别“可序列化”,您也会看到“由于并发更新而无法序列化访问”错误(或者无论MySQL等效错误消息是什么)。你需要重试逻辑,所以我要说上面那个建议使用这种方法来避免“基于异常的编程”的人是错误的,因为建议首先出于同样的原因进行UPDATE的人。

答案 6 :(得分:0)

据我所知,第一种方式是首选方式。

答案 7 :(得分:0)

在您的DAO模型中,您可以拥有一个id字段。

  • 如果设置为null / -1 / whatever,则数据尚未保留。

  • 当您持久化(或从数据库中检索)时,请将其设置为数据库中的id值。

  • 您的persist方法可以检查ID并将其传递给update()或add()实现。

  • 缺陷:与数据库等不同步我确信还有更多,但我真的应该完成一些工作......

答案 8 :(得分:0)

只要您使用MySQL,就可以使用ON DUPLICATE关键字。例如:

INSERT INTO my_prefs (user_id, pref_key, pref_value) VALUES (1234, 'show_help', 'true') 
ON DUPLICATE KEY UPDATE (pref_key, pref_value) VALUES ('show_help', 'true');