Mysql 使非规范化模式保持最新的最佳实践?

Mysql 使非规范化模式保持最新的最佳实践?,mysql,database-design,optimization,Mysql,Database Design,Optimization,我正在创建一个游戏,游戏中的分数用于做一些小事,因此我有一个这样的模式: create table points ( id int, points int, reason varchar(10) ) 要获得用户的点数非常简单: select sum(points) as total from points where id = ? 但是,随着积分表的扩展,性能已成为越来越多的问题。我想做一些类似的事情: create table pointtotal ( id int,

我正在创建一个游戏,游戏中的分数用于做一些小事,因此我有一个这样的模式:

create table points (
  id int,
  points int,
  reason varchar(10)
)
要获得用户的点数非常简单:

select sum(points) as total from points where id = ?
但是,随着积分表的扩展,性能已成为越来越多的问题。我想做一些类似的事情:

create table pointtotal (
  id int,
  totalpoints int
)
保持它们同步的最佳实践是什么?我是否尝试在每次更改时更新pointtotal?我是否运行每日脚本

假设我有正确的钥匙-为了简洁起见,它们被遗漏了

编辑:

以下是我遗漏的一些特征,但应该会有所帮助:

对点的插入/更新并不那么频繁 有大量的条目,也有大量的请求——正如您所看到的,键非常简单。

最佳实践是使用规范化的数据库模式。然后DBMS会使它保持最新,所以您不必这样做

但我理解使非规范化设计具有吸引力的权衡。在这种情况下,最佳做法是在每次更改时更新总数。调查触发因素。这种做法的好处是,你可以使总数与变化保持同步,这样你就不必考虑它是否过时了。如果提交了一个更改,则更新的总数也将提交

然而,这在并发更改方面有一些弱点。如果您需要同时对相同的总计进行更改,并且您可以容忍总计最终保持一致,那么请使用定期重新计算总计,这样您就可以确保一次只有一个进程在更改总计

另一个好的做法是在数据库外部缓存聚合总计,例如memcached或在应用程序变量中,这样就不必每次需要显示值时都访问数据库


查询选择sumpoints作为id=?即使您有大量的行和大量的请求,也不应该花费2秒钟

如果您有一个定义的over id,那么查询可以生成结果,而无需从表中读取数据;它可以通过读取索引本身的值来计算总数。用于分析查询并在额外列中查找Using index注释

CREATE TABLE Points (
  id     INT,
  points INT,
  reason VARCHAR(10),
  KEY    id (id,points)
);

EXPLAIN SELECT SUM(points) AS total FROM Points WHERE id = 1;

+----+-------------+--------+------+---------------+------+---------+-------+------+--------------------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref   | rows | Extra                    |
+----+-------------+--------+------+---------------+------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | points | ref  | id            | id   | 5       | const |    9 | Using where; Using index | 
+----+-------------+--------+------+---------------+------+---------+-------+------+--------------------------+

无论如何都要使基础表规范化。如果您可以处理可能只有一天的数据,请在您可以安排的每个晚上运行一个脚本,以进行汇总并填充新表。最好每晚从源表重新创建这个东西,以防止两者之间出现任何不一致


也就是说,根据记录的大小,您必须拥有非常慢的服务器或非常大的记录,因为这样小的记录,id上有索引字段,对您来说应该可以非常快地求和-但是,我的想法是,如果您可以将用户响应时间提高几秒钟,没有理由不使用汇总表——即使DB purists对象

在同一个表上有额外的totalpoints列,并为每一行的创建/更新创建/更新totalpoints的值

如果需要某个记录的totalpoints,则可以在不计算totalpoints的情况下查找该值。例如,如果您需要totalpoint的最后一个值,可以按如下方式获得:

SELECT totalpoint FROM point ORDER BY id DESC LIMIT 1;

还有另一种方法:缓存。即使它只被缓存几秒钟或几分钟,这也是对频繁访问的值的胜利。并且可以将缓存提取与缓存更新分离。这样,一个合理的当前值总是以恒定的时间返回。棘手的一点是让fetch生成一个新的进程来进行更新。

我建议创建一个层,用于访问和修改数据。您可以使用这些DB访问函数将数据维护封装在所有表中,以保持冗余数据的同步。

在这种情况下,您可以选择任何一种方式,因为这并不十分复杂

作为一般规则,我更喜欢通过有足够的冗余来允许数据暂时不一致,并有一个周期性的过程来解决不一致。然而,有一个触发机制来鼓励尽早执行定期程序并没有什么害处


我之所以这样认为,是因为在更复杂的情况下,依赖基于事件的通知样式代码来保持一致性会使代码变得非常复杂,并使验证变得困难。

您还可以创建另一个报告模式,并通过执行计算的某个进程以固定的时间间隔重新加载它。这不适用于实时信息,但这是非常标准的处理方式。

后端语言是Perl,不确定它是否重要。理想情况下,请尝试说服人们等待2秒钟进行查询!从id=?的点中选择sumpoints作为总计?不应花费2秒钟。触发器可能是解决方法。我没有提到插入/更新不是那么频繁。另外,最好避免
按查询的和点类型排序的文件排序..记录和请求的数量较大。