2016-07-07 87 views
2

不幸的是我没有更好的想法如何命名这个问题,所以如果你有更好的建议继续和编辑它:-)RDBM - 一对一 - >检查条目是否存在并插入/更新OR总是删除并只插入?

年以来试图插入的时候我一直在使用这种方法/更新一到-one资源:执行DELETE以确保不存在具有此类PK的行,然后仅执行INSERT。我一直认为这是性能和简单性最好的例子。当谈到性能时,我的意思是双方 - 数据库和应用层(即执行DELETE查询似乎比执行SELECT更便宜并检查结果,同时考虑到有数据正在双向传输)。

不过,当然也有其他的方法,例如INSERT ... ON DUPLICATE KEY UPDATE ...IF EXISTS (SELECT ...) UPDATE ... ELSE INSERT...UPDATE ... ;IF ROWCOUNT = 0 INSERT ...(取决于底层RDBMS),当然执行相同的应用层上的,即,首先检查该数据项是否存在,并且如果它执行UPDATE ,否则INSERT(或执行UPDATE并检查受影响的行的数量,如果为零,则执行INSERT [这会带来另一复杂化,因为如果UPDATE不改变底层资源,它也返回零作为受影响行的数量,因此在INSERT之后将返回重复PK错误])...

我现在好奇什么是最好的方法?我最好的意思是如果你考虑性能,最佳实践等...

回答

3

使用ON DUPLICATE KEY UPDATE是唯一的理智的事情;它更简单,它的意图很明确 - 很容易阅读。它也会表现得更好,因为索引条目不需要改变。

使用DELETE那么INSERT容易受到竞争条件的影响,如果两个进程试图同时更新相同的密钥,这将导致其中一个进程的唯一键违例。它也慢得多,因为不仅要删除一行并插入新行,还必须删除索引条目并插入。

使用IF EXISTS也不是一个好的选择,因为您必须在存储过程中执行此操作,因此它被锁定到该调用选项,并且无法移植到应用程序中。另外,这只是试图复制ON DUPLICATE KEY UPDATE内置命令,所以它永远不会有效。


回应关于程序员性能,即效率,恕我直言,这是非常重要的太发表评论。

如果你想避免重复参数,加少许重构的方便:

void applyTwice(PreparedStatement stmt, int fromIndex, Object... values) { 
    for (int i = 0; i < values.length; i++) { 
     stmt.setObject(i + fromIndex, values[i]); 
     stmt.setObject(i + fromIndex + values.length, values[i]); 
    } 
} 

调用此类似:

applyTwice(stmt, 3, "foo", "bar", 99); 

将有效地做到这一点:

stmt.setObject(3, "foo"); 
stmt.setObject(4, "bar"); 
stmt.setObject(5, 99); 
stmt.setObject(6, "foo"); 
stmt.setObject(7, "bar"); 
stmt.setObject(8, 99); 

fromIndex参数允许不重复的非重复参数,如ID等在查询中。

你也可以做,在多个索引应用单个值的简单方法:

void apply(PreparedStatement stmt, Object value, int... indexes) { 
    for (int i = 0; i < indexes.length; i++) { 
     stmt.setObject(indexes[i], value); 
    } 
} 

,你会叫这样的:

apply(stmt, "foo", 3, 6); 
+0

OK,似乎是合理的,我,尤其是在谈论时性能。它有一个背景 - 如果我准备*一个语句,然后*执行*它,同时提供所有的变量作为参数,使用'ON DUPLICATE KEY UPDATE',我将不得不复制它们,导致例如, 20参数,而不是10 ...但我的目标是性能,所以输入一点点它是值得的:-) – shadyyx

+0

@shadyyx我已经添加了一些可能的减轻你的加倍输入 – Bohemian

+0

好吧,感谢您的代码样本,但我必须得到完全不同的解决方案,因为我的例子中的命名参数(GoLang)没有单独设置(即'stmt.setParam()',而是通过传递给'exec()',即'stmt。 Exec(param1,param2,param3,...,paramX)')。但是可以仅仅创建*数组*(在它的'slice'中)重复值,然后以这种方式传递它们'stmt.Exec(params ...)'(从字面上看就是这三个点)。尽管如此,INSERT ... ON DUPLICATE KEY UPDATE ...是否符合** REST PUT ** - 即资源被完全替换为PUT请求? – shadyyx

相关问题