SELECT与索引的UPDATE性能

时间:2011-07-14 15:47:17

标签: mysql performance

如果我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}}列 已编入索引。

7 个答案:

答案 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.htmlhttp://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)

您是否有复合索引或单独的索引?

如果它是ida列的综合索引,

第二次更新语句中,a列的索引将不会被使用。原因是只使用了最左边的前缀索引(除非aPRIMARY 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会在更新期间锁定所有行。 如果第二个会话正在执行相同的命令,则它将有一个等待时间,直到行被解锁。 因此,没有竞争条件是可能的,以牺牲时间为代价。