MySQL - 多个查询或单个查询
MySQL - Multiple Queries or Single Query
所以我有一个包含选票的 table。此问题的相关列是 user
和 timestamp
.
我需要获取用户的总票数,以及他们这个月.
的票数
我知道这些问题 - 我不是在问这些问题。我同时使用这些:
本月票数/总票数:
SELECT COUNT( 0 ) FROM votes WHERE ( timestamp BETWEEN DATE_FORMAT( NOW( ) ,'%Y-%m-01' ) AND NOW( ) ) AND user = ?;
SELECT COUNT( 0 ) FROM votes WHERE user = ?;
目前,我的数据库不够大(甚至查询不够),以至于性能成为问题。然而,这种情况预计很快就会改变。我应该将查询分开,还是应该:
SELECT COUNT( 0 ) AS totalVotes,
SUM( IF( timestamp BETWEEN DATE_FORMAT( NOW( ) ,'%Y-%m-01' )
AND NOW( ), 1, 0 ) ) AS votesThisMonth
FROM votes WHERE user = ?;
最佳做法是什么?从同一个 table 中查询多位信息是否有任何技巧可以避免搜索两次?我的组合查询是否甚至是我应该使用的?
谢谢!
我会推荐第二种解决方案,它使用带有条件总和的唯一查询。
基本原理:要生成第二个结果集,您需要扫描第一个结果集的子集。因此,无论如何,所需的额外处理都非常小。另一方面,运行 两个单独的查询涉及到服务器的更多往返、查询规划器的更多查询解析以及对 table.
的额外扫描
为了性能,您需要 (user, timestamp)
上的索引。
在MySQL,我会推荐:
SELECT COUNT(*) AS totalVotes,
SUM(EXTRACT(YEAR_MONTH FROM timestamp) = EXTRACT(YEAR_MONTH FROM NOW())) AS votesThisMonth
FROM votes
WHERE user = ?;
上述的替代方法是:
SUM(timestamp >= CURRENT_DATE - (DAY(CURRENT_DATE) - 1) DAY)
我强烈建议您不要对日期使用字符串,除非您确实必须这样做。有多种方法可以从当前日期获取值,这些方法不涉及将 date/time 值隐式或显式转换为字符串。
此外,IF()
是多余的。 MySQL 允许您只添加布尔值。两者都不是标准的SQL,所以你不妨使用更简洁的版本。
COUNT(0)
对我来说很刺耳。虽然有效,但 COUNT(*)
或 COUNT(1)
似乎更简单。
略有不同,不一定比其他建议快:
SELECT COUNT(*) AS total,
SUM(LEFT(timestamp, 7) = LEFT(NOW(), 7)) AS this_month
FROM tbl
WHERE user_id = ?
并且有
INDEX(user_id, timestamp) -- in this order. ("Covering")
回到1对2查询的问题:
- 我的组合查询对用户的所有行进行一次扫描。
- 'total' 查询还需要对用户的所有行进行一次扫描。
- 'this month' 查询,如果使用
BETWEEN
或 >=
,则仅扫描用户本月的行。 (我的没做到,不过没关系。)
所以我有一个包含选票的 table。此问题的相关列是 user
和 timestamp
.
我需要获取用户的总票数,以及他们这个月.
的票数我知道这些问题 - 我不是在问这些问题。我同时使用这些:
本月票数/总票数:
SELECT COUNT( 0 ) FROM votes WHERE ( timestamp BETWEEN DATE_FORMAT( NOW( ) ,'%Y-%m-01' ) AND NOW( ) ) AND user = ?;
SELECT COUNT( 0 ) FROM votes WHERE user = ?;
目前,我的数据库不够大(甚至查询不够),以至于性能成为问题。然而,这种情况预计很快就会改变。我应该将查询分开,还是应该:
SELECT COUNT( 0 ) AS totalVotes,
SUM( IF( timestamp BETWEEN DATE_FORMAT( NOW( ) ,'%Y-%m-01' )
AND NOW( ), 1, 0 ) ) AS votesThisMonth
FROM votes WHERE user = ?;
最佳做法是什么?从同一个 table 中查询多位信息是否有任何技巧可以避免搜索两次?我的组合查询是否甚至是我应该使用的?
谢谢!
我会推荐第二种解决方案,它使用带有条件总和的唯一查询。
基本原理:要生成第二个结果集,您需要扫描第一个结果集的子集。因此,无论如何,所需的额外处理都非常小。另一方面,运行 两个单独的查询涉及到服务器的更多往返、查询规划器的更多查询解析以及对 table.
的额外扫描为了性能,您需要 (user, timestamp)
上的索引。
在MySQL,我会推荐:
SELECT COUNT(*) AS totalVotes,
SUM(EXTRACT(YEAR_MONTH FROM timestamp) = EXTRACT(YEAR_MONTH FROM NOW())) AS votesThisMonth
FROM votes
WHERE user = ?;
上述的替代方法是:
SUM(timestamp >= CURRENT_DATE - (DAY(CURRENT_DATE) - 1) DAY)
我强烈建议您不要对日期使用字符串,除非您确实必须这样做。有多种方法可以从当前日期获取值,这些方法不涉及将 date/time 值隐式或显式转换为字符串。
此外,IF()
是多余的。 MySQL 允许您只添加布尔值。两者都不是标准的SQL,所以你不妨使用更简洁的版本。
COUNT(0)
对我来说很刺耳。虽然有效,但 COUNT(*)
或 COUNT(1)
似乎更简单。
略有不同,不一定比其他建议快:
SELECT COUNT(*) AS total,
SUM(LEFT(timestamp, 7) = LEFT(NOW(), 7)) AS this_month
FROM tbl
WHERE user_id = ?
并且有
INDEX(user_id, timestamp) -- in this order. ("Covering")
回到1对2查询的问题:
- 我的组合查询对用户的所有行进行一次扫描。
- 'total' 查询还需要对用户的所有行进行一次扫描。
- 'this month' 查询,如果使用
BETWEEN
或>=
,则仅扫描用户本月的行。 (我的没做到,不过没关系。)