将经常更新的列移到单独的表中以获得更好的性能

时间:2015-07-09 19:14:32

标签: mysql sql database database-design relational-database

(这与here几乎是同一个问题,但我正在寻求有关性能的具体说明,而不是解决任何错误。)

考虑一个包含中到大量属性(列)的数据库表,其中大多数属性是静态的或不经常更新的。该表非常频繁地用于读取操作

如果经常更新两个或三个属性(列) ,为了性能原因,建议将它们拆分为单独的表吗?

我理解这将是一个好处的一个原因是当表更新时,表的查询缓存被删除。在我的例子中,数据库是MySQL,表类型是InnoDB(行级锁定)。

编辑:经常更新的列之一不是频繁读取的一部分,但在读取后可能会立即更新。

另一个经常更新的列是一些频繁读取的一部分,并且每次读取都会更新,但我可以批量更新。

1 个答案:

答案 0 :(得分:1)

如果你有一个宽表和/或一组相对较窄的字段,这些字段比其他字段更频繁地访问,那么将这些字段与其余字段分开是有意义的。但是,请考虑在现有表中创建子表,而不是将它们标准化为自己的表。也就是说,创建一个覆盖索引。

select  a, b, c
from    table
where   c, d, e;

在这个简单的例子中,你可以在a,b,c,d,e上创建一个索引。可以通过仅访问索引来完成查询。与更新相同:

update  table
    set d = 'something'
where   a, b, e;

只要只调用索引中定义的字段,就只需要使用索引。

但永远不要假设任何事情。开发时序测试,以便您可以在之前和之后进行有意义的比较。开发回归测试,以便您可以通过过度减慢其他重要操作来查看它是否确实加速了您不希望的操作。

这是另一个需要考虑的因素。进行上面的查询。假设必须检查数千或数百万行(where子句)以便找到很少的结果。那么创建两个覆盖索引会更好吗 - 一个用于选择列表,一个用于where子句?如果 更好(更快),那么字段c应该在选择索引中定义哪个索引还是只在where索引中定义?

我不知道这些问题的答案。你必须测试。

<强>更新 如果我理解了注释,那么您对其他字段的某些字段和更新有很多查询,并且您不希望它们相互干扰,因为它们使用不同的字段集。您已经可以将查询与更新“隔离”了。只需在“无锁定”条件下查询。

在MySQL中,程序是(注意:这仅适用于InnoDB。请参阅其他引擎的文档):

set session transaction isolation level read uncommitted;
query1...
query2...
query3...
set session transaction isolation level repeatable read;

或只是

set transaction isolation level read uncommitted;
query1...
query2...
query3...
commit;

您仍然可能希望查看覆盖查询和/或更新的索引,但现在这是一个单独的问题。