在更新一行时,许多 ORM 工具发出一个 UPDATE 语句,设置与该特定实体关联的每一列。
优点是您可以轻松地批量更新语句,因为UPDATE无论您更改什么实体属性,语句都是相同的。此外,您甚至还可以使用服务器端和客户端语句缓存。
所以,如果我加载一个实体并且只设置一个属性:
Post post = entityManager.find(Post.class, 1L);
post.setScore(12);
Run Code Online (Sandbox Code Playgroud)
所有列都将被更改:
UPDATE post
SET score = 12,
title = 'High-Performance Java Persistence'
WHERE id = 1
Run Code Online (Sandbox Code Playgroud)
现在,假设我们也有一个关于该title属性的索引,数据库难道不应该意识到该值无论如何都没有改变吗?
在这篇文章中,Markus Winand 说:
所有列的更新显示了我们在前几节中已经观察到的相同模式:响应时间随着索引的增加而增加。
我想知道为什么会有这种开销,因为数据库将关联的数据页从磁盘加载到内存中,因此它可以确定是否需要更改列值。
即使对于索引,它也不会重新平衡任何内容,因为对于未更改的列,索引值不会更改,但它们已包含在 UPDATE 中。
是不是和冗余不变列关联的B+树索引也需要导航,数据库才意识到叶子值还是一样的?
当然,一些 ORM 工具允许您只更新更改的属性:
UPDATE post
SET score = 12,
WHERE id = 1
Run Code Online (Sandbox Code Playgroud)
但是,当不同行的不同属性更改时,这种类型的 UPDATE 可能并不总是从批量更新或语句缓存中受益。
我经常看到人们说索引变慢了update,delete并且insert。这被用作笼统的陈述,就好像它是绝对的一样。
在调整我的数据库以提高性能的同时,我不断遇到这种情况,这对我来说在逻辑上似乎与该规则相矛盾,而且我找不到任何人以其他方式说或解释。
在 SQL Server 中,我相信/假定大多数其他 DBMS,您的索引是根据您指定的特定列创建的。插入和删除总是会影响整行,因此它们不可能不影响索引,但更新似乎更独特一些,它们只能专门影响某些列。
如果我有未包含在任何索引中的列并且我更新它们,它们是否会因为我在该表中的其他列上有索引而变慢?
例如,在我的User表中,我有一个或两个索引,主键是 Identity/Auto Increment 列,另一个可能是某个外键列。
如果我直接更新一个没有索引的列,比如他们的电话号码或地址,这个更新是否会变慢,因为我在这两种情况下的其他列上都有索引?我正在更新的列不在索引中,所以从逻辑上讲,索引不应该更新,不是吗?如果有的话,我认为如果我在 WHERE 子句中使用索引,它们会加速。
我正在尝试使用一组值更新表。数组中的每一项都包含与 SQL Server 数据库表中的行匹配的信息。如果该行已存在于表中,我们将使用给定数组中的信息更新该行。否则,我们在表中插入一个新行。我已经基本上描述了 upsert。
现在,我试图在采用 XML 参数的存储过程中实现这一点。我使用 XML 而不是表值参数的原因是,执行后者时,我必须在 SQL 中创建自定义类型并将此类型与存储过程相关联。如果我以后更改了存储过程或数据库架构中的某些内容,则必须重做存储过程和自定义类型。我想避免这种情况。此外,TVP 相对于 XML 的优势对我的情况没有用,因为我的数据数组大小永远不会超过 1000。这意味着我不能使用这里提出的解决方案:How to insert multiple records using XML in SQL server 2008
此外,这里的类似讨论(UPSERT - 是否有更好的替代 MERGE 或 @@rowcount?)与我所问的不同,因为我试图将多行插入到表中。
我希望我可以简单地使用以下一组查询来更新 xml 中的值。但这行不通。当输入是单行时,这种方法应该有效。
begin tran
update table with (serializable) set select * from xml_param
where key = @key
if @@rowcount = 0
begin
insert table (key, ...) values (@key,..)
end
commit tran
Run Code Online (Sandbox Code Playgroud)
下一个替代方法是使用详尽的 IF EXISTS 或其以下形式的变体之一。但是,我以次优效率为由拒绝了这一点:
IF (SELECT COUNT ... ) > 0 …Run Code Online (Sandbox Code Playgroud)