如果我SELECT
ID然后UPDATE
使用这些ID,则UPDATE
查询比使用UPDATE
条件SELECT
更快SELECT id FROM table WHERE a IS NULL LIMIT 10; -- 0.00 sec
UPDATE table SET field = value WHERE id IN (...); -- 0.01 sec
举例说明:
UPDATE
上述速度比具有相同条件的UPDATE table SET field = value WHERE a IS NULL LIMIT 10; -- 0.91 sec
快约100倍:
a
为什么?
注意:{{1}}列 已编入索引。
答案 0 :(得分:29)
第二个UPDATE
语句很可能会锁定更多的行,而第一个使用唯一键并仅锁定它要更新的行。
答案 1 :(得分:4)
两个查询不完全相同。您只知道表中的ID是唯一的。
UPDATE ... LIMIT 10将最多更新10条记录。
UPDATE ...如果有重复ID,则id IN(SELECT ... LIMIT 10)可能会更新10条以上的记录。
答案 2 :(得分:4)
我不认为你的“为什么会有一个直截了当的答案?”没有做某种分析和研究。
SELECT查询通常是高速缓存的,这意味着如果多次运行相同的SELECT查询,则第一个查询的执行时间通常大于以下查询。请注意,这种行为只能在SELECT很重的情况下出现,而不是在第一个SELECT更快的情况下。因此,在您的示例中,由于缓存,SELECT可能需要0.00。 UPDATE查询使用不同的WHERE子句,因此它们的执行时间可能不同。
尽管列a
已编入索引,但在执行SELECT或UPDATE时MySQL不一定必须使用索引。请研究EXPLAIN输出。另外,请参阅SHOW INDEX
的输出并检查“注释”列是否为任何索引读取“已禁用”?您可以在此处阅读更多内容 - http://dev.mysql.com/doc/refman/5.0/en/show-index.html和http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html。
此外,如果我们暂时忽略SELECT并仅关注UPDATE查询,很明显它们都不是使用相同的WHERE条件 - 第一个在id
列上运行而后者在后面运行在a
。尽管两列都已编制索引,但并不一定意味着所有表索引的执行情况都相同。某些索引可能比另一索引更有效,具体取决于索引的大小或索引列的数据类型,或者它是单列还是多列索引。肯定可能有其他原因,但我不是专家。
另外,我认为第二个UPDATE正在做更多的工作,因为与第一个UPDATE相比,它可能会放置更多的行级锁。确实,两个UPDATES最终都会更新相同的行数。但是在第一次更新中,锁定了10行,我认为在第二次UPDATE中,所有行a
为NULL(超过10)的行在执行UPDATE之前都被锁定。也许MySQL首先应用锁定然后运行LIMIT子句来仅更新有限的记录。
希望上面的解释有意义!
答案 3 :(得分:3)
您是否有复合索引或单独的索引?
如果它是id
和a
列的综合索引,
在第二次更新语句中,a
列的索引将不会被使用。原因是只使用了最左边的前缀索引(除非a
是PRIMARY KEY
)
因此,如果您希望使用a
列的索引,则还需要在id
子句中包含WHERE
,然后先id
a
}}
此外,它取决于您使用的存储引擎,因为MySQL在引擎级别执行索引,而不是服务器。
你可以试试这个:
UPDATE table SET field = value WHERE id IN (...) AND a IS NULL LIMIT 10;
执行此操作id
位于最左侧的索引后跟a
同样来自您的评论,查找速度要快得多,因为如果您使用InnoDB
,更新列将意味着InnoDB
存储引擎必须将索引移动到不同的页面节点,或者如果页面已满,则必须拆分页面,因为InnoDB
按顺序存储索引。此过程非常缓慢且昂贵,如果您的索引碎片,或者您的表格非常大,则会变得更慢
答案 4 :(得分:1)
Michael J.V的评论是最好的描述。此答案假设a
是未编入索引的列,并且“#id;'是
第一个UPDATE命令中的WHERE子句正在处理表的主键id
第二个UPDATE命令中的WHERE子句正在处理非索引列。这使得更新列的查找速度明显变慢。
永远不要低估索引的力量。如果正确使用索引而不是没有索引的十分之一的表,那么表将表现得更好。
答案 5 :(得分:0)
关于“MySQL不支持更新您从”
中选择的同一个表格UPDATE table SET field = value
WHERE id IN (SELECT id FROM table WHERE a IS NULL LIMIT 10);
这样做:
UPDATE table SET field = value
WHERE id IN (select id from (SELECT id FROM table WHERE a IS NULL LIMIT 10));
答案 6 :(得分:0)
接受的答案似乎正确但不完整,存在重大差异。
据我了解,我不是SQL专家:
第一个查询您选择N行并使用主键更新它们 这非常快,因为您可以根据最快的索引直接访问所有行。
第二个查询使用LIMIT更新N行 这将锁定所有行并在更新完成后再次释放。
最大的区别在于你在案例1中有一个RACE条件,在案例2中有一个原子UPDATE)
如果您有两个或更多同时调用案例1)查询,您将遇到从表中选择SAME ID的情况。 两个调用将同时更新相同的ID,相互覆盖。 这被称为“竞争条件”。
第二种情况是避免这个问题,mysql会在更新期间锁定所有行。 如果第二个会话正在执行相同的命令,则它将有一个等待时间,直到行被解锁。 因此,没有竞争条件是可能的,以牺牲时间为代价。