【问题标题】:Do mysql update queries benefit from an index?mysql 更新查询是否受益于索引?
【发布时间】:2011-07-21 00:04:11
【问题描述】:

我有一个主要更新的表,我想知道更新查询是否会受益于在 where 列和更新的列上设置索引或在 where 列上设置索引?

【问题讨论】:

  • WHERE 中的列上的索引(可能)会有所帮助。可能意味着它会帮助等效的SELECT。例如,如果您有 WHERE id > 3 条件并且几乎所有 id 都 > 3,则不会使用索引。
  • 关于问题的第二部分,(wherecolumn, updatedcolumn) 上的索引也可能有所帮助。但我认为只是因为 MySQL 检查并且不更新更新值与列的现有值相同。因此,如果grp=47a 已经等于7 的行有很多行,UPDATE t SET a=7 WHERE grp=47 可能会形成(grp,a) 索引。
  • 你用的是什么存储引擎,表的结构是什么,更新查询是什么?这些都可能对答案产生影响。

标签: mysql indexing


【解决方案1】:

这不是一个直截了当的答案。就这样吧。

UPDATE table SET ColumnA = 'something' 

如果 ColumnA 上存在索引,那么您的性能会受到轻微影响,因为每行会有两个写入操作。首先是表中的数据,然后是索引更新的写入。
您甚至可以有多个索引,每个索引都将 ColumnA 作为索引的一部分,这意味着除了表行之外,您还将有多个写入。您可以看到拥有多个索引如何开始真正减慢您的更新速度。
但是如果 ColumnA 根本没有被索引,那么它将只对每一行进行一次写入。

UPDATE table SET ColumnA = 'something' WHERE ColumnB = 'something else'

对于这个查询,如果索引存在于 ColumnB 而不是 ColumnA,定位记录(称为查找)和单次写入更新将非常快,并且由于索引不关心列 A,它不需要更新。
但是如果您索引 ColumnA 而不是 ColumnB,您将首先读取表中的每一行(称为扫描,通常是一件坏事),虽然读取比写入快,但它仍然非常慢,然后它将写入表,然后再写入索引。基本上是最慢的做事方式。

DELETE table WHERE ColumnB = 'somethingelse'

现在,如果您在此表中的任何列上都有索引,则两次写入、从表中删除和更新/删除索引中的记录。
再次,如果 ColumnB 未编入索引,您将扫描表然后删除表中的行并更新索引(如果有)。

INSERT INTO table (ColumnA, ColumnB) VALUES ('something','something else')

如果不存在索引,则对表进行一次写入即可完成。
同样,如果确实存在索引,则为每个索引额外写入一次。

我没有提到主键唯一约束,因为当你需要一个主键时你真的无法绕过它们,但是在插入之前必须检查每条记录以查看该键是否已经存在。这将是一个快速的主键索引搜索,但无论如何,它是该过程中的另一个步骤。步骤越少,速度就越快。

现在回到您的,基本上,如果您需要更新特定记录,索引将帮助您比扫描整个表更快地找到该记录。查找记录所节省的时间将远远超过更新索引所损失的时间。如果您只插入而不读取,那么索引会减慢您的速度。它变成了一个平衡的东西。如果您需要阅读特定记录,那么索引将有很大帮助。但是索引越多,写入的速度就越慢。

【讨论】:

  • 您在回答中指的是哪个存储引擎?
  • 最佳答案在这里。谢谢!
【解决方案2】:

就在 where 列上。更新列上的索引实际上会减慢您的查询速度,因为索引必须与数据一起更新。 where 列上的索引将加速更新和选择,但会减慢一些插入。

删除行时,索引也会产生开销。一般来说,尽管在您经常使用WHERE 的列上它们是一件好事,而且它们基本上在您连接的列上是必需的,或者ORDER BY

【讨论】:

  • 更新索引完全在内存中完成,速度非常快。更新查询是简单地增加一列的查询。我想知道将第二列添加到索引是否会节省额外的读取时间来查找原始值。
  • 这是个好问题。我认为 MySQL 优化器会利用索引,但很难说。您可以随时打开分析并尝试这两个查询,看看是否有任何发现。
【解决方案3】:

这里的大多数人不知道索引在 MySQL 中是如何工作的。

这取决于您使用的存储引擎。 InnoDB 使用与 MyISAM 完全不同的索引。这是因为 MySQL 在存储引擎级别而不是 MySQL 服务器级别实现索引。

恐怕这里的大多数人都会根据其他数据库给你答案,在这些数据库中,索引工作方式与 MySQL 不同

InnoDB

InnoDB的情况下。这是因为每当在InnoDB 中更新一行时,索引也必须更新,因为InnoDB's 索引必须是连续的,所以它必须找出它应该在索引的哪个页面节点并插入那里。有时该特定页面可能已满,因此必须拆分页面,既浪费空间又增加时间。无论您为哪一列建立索引都会发生这种情况,因为InnoDB 使用聚集索引,该索引存储整行的数据。

MyISAM

MyISAM 没有这个问题。 MyISAM 实际上只使用 1 列索引,即使您可以在超过 1 列上设置多个唯一性。此外,MyISAM's 索引不是按顺序存储的,因此更新非常快。同样插入也很快,MyISAM 只是将它插入到行尾。

结论

因此,关于您的问题,您应该考虑您的架构设计,而不是担心查询是否会使用索引。如果您主要在表上进行更新,我建议您不要使用InnoDB,除非您需要行级锁定、高并发和事务。否则MyISAM 会更适合更新任务。如果您使用 InnoDB 索引并不能真正帮助更新,则不会,尤其是在表非常大的情况下。

【讨论】:

  • 如果不使用事务,您将如何处理 MyISAM 表中的数据损坏,例如,如果服务器在更新期间崩溃?这对于以更新为主要操作的表可能很重要。
  • 您可以使用CHECK TABLE tablenameREPAIR TABLE tablenamemyisamchk。除了崩溃后损失的时间之外,通常这不是问题。相反,InnoDB 索引很容易碎片化,无法像其他存储引擎那样使用ALTER TABLE innodbtable ENGINE=InnoDB 进行修复。所以这真的取决于你的情况。
  • 如果发生崩溃时正在进行更新,那么 MyISAM 表是否会损害数据完整性 - 根据正在执行的更新,可能很难判断哪些记录具有已更新,哪些还没有?至于索引碎片,docs state可以ALTER TABLE tbl_name ENGINE=INNODB修复。我错过了什么吗?无论如何,我在这里偏离主题,我同意这取决于情况。但数据完整性是一个重要的考虑因素。
  • 是的,如果他需要事务,那么一定要使用它,但是我们不知道他将在什么上下文中使用数据库。是的,你是对的,ALTER TABLE tbl_name ENGINE=INNODB 确实可以通过再次构建表来对索引进行碎片整理,我将其与OPTIMIZE TABLE 混合在一起,并为碎片整理索引转储和重新加载数据,这不适用于 InnoDB。
  • 我补充一下我的经验:我必须更新 100 万行的 MyIsam 表上的多个列,其中 WHERE 部分包含 3 列。经过多次实验,我发现最好的组合是删除表上的所有索引,只在 WHERE 部分的最小列上添加一个 tmp 索引。这里是更新查询的示例: UPDATE radio16 SET grp_flg = "S", ind = 570, adu = 570, uom = 470, don = 670, res = 670, m34 = 360 WHERE cod_test = 958010 AND dow = 6 AND qtd = 715;
猜你喜欢
  • 1970-01-01
  • 2010-09-12
  • 2020-07-23
  • 1970-01-01
  • 1970-01-01
  • 2020-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多