2

我正在使用 mysql 数据库,现在我必须确保列中的值应该是1,而它可能1已经是。因此,考虑以下两个陈述:

UPDATE category SET is_leaf=1 WHERE id=9

或者

UPDATE category SET is_leaf=1 WHERE id=9 AND is_leaf=0

id是主键,区别是当is_leaf已经是1的时候,再更新还是不更新,哪个效率更高?

我知道这并不重要,但我想找出更好地理解mysql。

4

2 回答 2

2
UPDATE category SET is_leaf=1 WHERE id=9 AND is_leaf=0

效率更高。因为那样它只会更新相关数据。否则即使is_leaf=1记录也要去更新。

假设表上有1000条记录,更新一条记录需要1s。如果您尝试更新所有记录,则需要 1000 秒。但假设在这种情况下 is_leaf=0记录数为 150,那么如果您使用第二条语句,则只需 150 秒而不是 1000 秒。

编辑 :

带有搜索参数的查询 (SARG)

WHERE 子句可帮助您限制查询返回的行数。但是,指定 WHERE 条件的方式会影响查询的性能。如果写入 WHERE 条件以使其使用将索引列作为输入的函数,则忽略索引并扫描整个表。这会导致性能下降。例如,以下结果会导致表扫描,因为在函数中使用了列 OrderDate:

SELECT CustomerID, EmployeeID FROM Orders
WHERE DATEDIFF(m, OrderDate, GetDate())>3

如果函数被重写如下所示,那么查询会使用索引来寻找所需的值,这会提高性能:

SELECT CustomerID, EmployeeID FROM Orders
WHERE OrderDate < DATEADD(m, -3, GetDate())

据说第二个查询中的过滤条件使用可搜索参数或 SARG,因为查询优化器可以在执行期间使用索引查找操作。

有关这方面的更多信息,您最好阅读提高查询性能

并阅读本文以加快搜索和过滤器

于 2013-01-24T05:01:18.140 回答
1

包含的查询AND is_leaf=0有时会更有效。

根据主键定位行时,它不会有太大的不同。(索引的可用性 on (id,is_leaf)可能会产生很小的差异。)但是一旦 MySQL 确定没有要更新的行,它就可以采用更短的代码路径。

但是,如果没有该谓词,MySQL 将不得不定位行,获取行锁(在 InnoDB 的情况下),并触发任何“BEFORE UPDATE FOR EACH ROW”触发器。然后 MySQL 必须检查是否有任何列值实际被更改(请注意,触发器的执行可能会将一个或多个列设置为不同的值)。如果 MySQL 检测到行没有更改,它可以跳过任何“ON UPDATE”时间戳列的设置,触发任何“AFTER UPDATE FOR EACH ROW”触发器,并将受影响的行数设置为零。(在事务的上下文中,不清楚 MySQL 是否可以在确定行没有被更改时释放行锁,或者行锁是否会继续保持直到提交或回滚。)

因此,这两个语句之间的一大区别是,即使行没有实际更改,MySQL 也会触发“FOR EACH ROW”触发器;但它不会为 WHERE 子句排除的行触发任何“FOR EACH ROW”触发器。

在简单的情况下,没有任何触发器,我不希望在性能上有任何可测量的差异。

我个人的偏好是包含额外的谓词。这确保不会请求或持有(InnoDB)意向行锁,并且不会触发 FOR EACH ROW 触发器。


除了行锁定和触发器执行之外,只要这两个语句完全相同,它们就不是真的。至少在一般情况下不会,因为有可能is_leaf包含 NULL 或 0 或 1 以外的值。

鉴于此声明:

UPDATE category SET is_leaf=1 WHERE id=9

对于当它不等于 1 时设置为 1 的等效语句is_leaf,我们实际上需要检查 NULL 和任何不同于 1 的值,例如:

UPDATE category SET is_leaf=1 WHERE id=9 AND NOT (is_leaf <=> 1)

考虑一下当is_leaf为 NULL 或 2 时会发生什么,例如,使用以下语句:

UPDATE category SET is_leaf=1 WHERE id=9 AND is_leaf=0
于 2013-01-24T05:27:12.933 回答