Php 如何有效地从一个大表中计算平均值?

Php 如何有效地从一个大表中计算平均值?,php,mysql,sql,Php,Mysql,Sql,我有一个名为ratings的表,其中包含以下字段: +-----------+------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+------------+------+-----+---------+----------------+ | rating_id | bigint(20

我有一个名为ratings的表,其中包含以下字段:

+-----------+------------+------+-----+---------+----------------+
| Field     | Type       | Null | Key | Default | Extra          |
+-----------+------------+------+-----+---------+----------------+
| rating_id | bigint(20) | NO   | PRI | NULL    | auto_increment |
| user_id   | int(11)    | NO   | MUL | NULL    |                |
| movie_id  | int(11)    | NO   |     | NULL    |                |
| rating    | float      | NO   |     | NULL    |                |
+-----------+------------+------+-----+---------+----------------+
+----------------+---------+------+-----+---------+-------+
| Field          | Type    | Null | Key | Default | Extra |
+----------------+---------+------+-----+---------+-------+
| movie_id       | int(11) | NO   | PRI | NULL    |       |
| average_rating | float   | NO   |     | NULL    |       |
+----------------+---------+------+-----+---------+-------+
此表上的索引:

+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| ratings |          0 | PRIMARY  |            1 | rating_id   | A         |      100076 |     NULL | NULL   |      | BTREE      |         |               |
| ratings |          0 | user_id  |            1 | user_id     | A         |         564 |     NULL | NULL   |      | BTREE      |         |               |
| ratings |          0 | user_id  |            2 | movie_id    | A         |      100092 |     NULL | NULL   |      | BTREE      |         |               |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
我有另一个名为
movie\u average\u ratings
的表,其中包含以下字段:

+-----------+------------+------+-----+---------+----------------+
| Field     | Type       | Null | Key | Default | Extra          |
+-----------+------------+------+-----+---------+----------------+
| rating_id | bigint(20) | NO   | PRI | NULL    | auto_increment |
| user_id   | int(11)    | NO   | MUL | NULL    |                |
| movie_id  | int(11)    | NO   |     | NULL    |                |
| rating    | float      | NO   |     | NULL    |                |
+-----------+------------+------+-----+---------+----------------+
+----------------+---------+------+-----+---------+-------+
| Field          | Type    | Null | Key | Default | Extra |
+----------------+---------+------+-----+---------+-------+
| movie_id       | int(11) | NO   | PRI | NULL    |       |
| average_rating | float   | NO   |     | NULL    |       |
+----------------+---------+------+-----+---------+-------+
这一点很明显,我想从评级表中计算电影的平均评级,并更新
movie\u average\u评级
表。我尝试了以下SQL查询

UPDATE movie_average_ratings
SET average_rating = (SELECT AVG(rating)
                            FROM ratings
                            WHERE ratings.movie_id = movie_average_ratings.movie_id);
目前,大约有10000个电影记录和100000个评级记录,我得到
锁等待超时;尝试重新启动事务
错误。记录的数量可能会显著增加,因此我认为增加超时不是一个好的解决方案


那么,如何编写“可伸缩”查询来实现这一点呢?迭代电影平均评分表记录并单独计算平均值是否是最有效的解决方案?

我在另一个表中发现了一些东西:

现在发生的是,另一个线程正在锁定记录 某些记录(您正在更新表中的每条记录!)时间过长, 您的线程正在超时

这意味着您的某些记录被锁定,您可以在控制台中强制解锁它们:

1) 输入MySQL
MySQL-u您的用户-p

2) 让我们看看锁定表的列表
mysql>show open tables where in_use>0

3) 让我们看看当前进程的列表,其中一个是锁定 您的表
mysql>显示进程列表

4) 杀死其中一个进程
mysql>Kill-put\u-process\u-id\u


您可以重新设计电影平均评分表,以

movie_id (int)
sum_of_ratings (int)
num_of_ratings (int)

然后,如果添加了一个新的评级,您可以将其添加到电影“平均”评级中,并根据需要计算平均值,而无需解释,很难弄清楚是什么阻碍了您。还不清楚通过将此聚合数据存储为非规范化表是否会提高性能-如果计算评级的查询在0.04秒内执行,则查询非规范化表的速度不太可能快得多

一般来说,我建议只有当您知道自己有性能问题时才进行非规范化

但这不是问题所在

我会这样做:

delete from movie_average_ratings;

insert into movie_average_ratings
Select movie_ID, avg(rating) 
from ratings 
group by movie_id;

我不确定我是否会费心存储派生数据。您是否有性能问题?请显示一个架构(带索引)和一个解释。对于一个索引良好的数据库来说,10000条记录几乎不算什么。@我希望通过存储平均值来获得一些轻微的性能提升。@NevilleK我更新了这个问题。在
ratings
表中,在
user\u id
movie\u id
上有一个复合唯一键@NevilleK我有10000条电影记录,但100000条评级记录将显著增长。我知道,只要更新操作正在运行,表就会被锁定。我的问题是更新表的更好方法是什么?如果表中有100000或100万条记录,则需要的时间太长。要计算总和,我必须再次使用
sum
函数。让我们回到原点。在建立了平均值表之后,我确实计划使用“移动平均值”方法来更新评级。但问题是表的初始设置。您不在电影平均评分表中存储单个评分!如果你得到了一个新的评分,只需将其添加到评分的总和和评分的增量num中。我在问题中包含了
解释
。我看不到它-你读了吗?你确定吗?我已经更新了这个问题,包括
explain
的控制台输出。几小时前。