带有数学运算的 MySQL 子查询

标签 mysql sql

我有两张 table 。

一个包含产品列表,主键是产品 ID。假设大约 10 列产品信息已被压缩为一列。

另一个包含用户对产品给出的评分列表。这些列是产品 ID、用户 ID 和评分。此表中的条目可能比产品表多一个数量级。

我想在单个查询中获取产品的所有信息,以及它的平均用户评分和用户评分数量。

这似乎是一种正确的方法:

SELECT 
    p.p_id,
    p.product_info,
    ( SELECT AVG(score) FROM ratings AS r WHERE r.p_id = p.p_id ) avg_rating,
    ( SELECT COUNT(score) FROM ratings AS r WHERE r.p_id = p.p_id ) num_ratings
    FROM products AS p

真正的问题:随着我的数据库扩展,从性能的角度来看这看起来如何?这可以使用更少的子查询并用连接替换它们吗?

附带问题:我曾经有一个计划,我会在产品表中缓存每个产品的平均评分和评分数量,并在新分数或更新分数到达时更新它。这使得查询非常简单,但我的直觉告诉我这真的很天真。假设这是一个 InnoDB 表,有人可以更明确地解释为什么这种缓存可能是也可能不是一个好主意吗?

最佳答案

如果 product_info 是一个相当长的 VARCHAR,下面的查询可能会更快(假设您有一个关于 ratingsp_id 的复合索引 (p_id, score) products 中编入索引):

SELECT 
  p_id,
  product_info,
  avg_rating,
  num_ratings
FROM (
  SELECT p_id, AVG(score) as avg_rating, COUNT(score) as num_ratings
  FROM ratings
  GROUP BY p_id
) as aggr
JOIN products USING (p_id);

连接的顺序反射(reflect)了 MySQL 更愿意执行查询的顺序(因为子查询的结果没有索引)。

但是当 ratings 至少包含每个产品的单个记录时,查询效果很好,否则您将需要为其余的添加一个带零的 UNION ALL产品(这可能会使速度明显变慢)。

当第一个查询不够快时,使用预先计算的聚合的解决方案成为一个好主意。

关于带有数学运算的 MySQL 子查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9016632/

相关文章:

android - 如何将Android sqlite BLOB数据上传到MySQL BLOB

sql - DB2 SQL 全选,列为

php - 为基于 PHP/MySQL 关键字的搜索分配多个关键字

mysql - "SELECT"当表中存在变音符号时选择了错误的行

c# - 无法使用 IP 地址连接到应用程序

php - 如何在 laravel 中跟踪购物车表的 sessionID

sql - 在 SQL 中,尝试为触发 from 条件的每个实例返回一条记录

mysql - 如何将其编写为 SQL 查询

sql - 计算所有 child 都属于特定类型的 parent 类型

MySQL 生成许多新的结果集