SELECT语句
WITH MonthlyOrderAmount AS (
SELECT
u.user_id,
u.user_name,
DATE_FORMAT(o.order_date, '%Y-%m') AS month,
SUM(o.total_amount) AS total_order_amount
FROM
users u
JOIN
orders o ON u.user_id = o.user_id
GROUP BY
u.user_id, u.user_name, DATE_FORMAT(o.order_date, '%Y-%m')
),
RankedMonthlyOrderAmount AS (
SELECT
user_id,
user_name,
month,
total_order_amount,
ROW_NUMBER() OVER (PARTITION BY month ORDER BY total_order_amount DESC) AS ranking
FROM
MonthlyOrderAmount
)
SELECT
user_id,
user_name,
month,
total_order_amount
FROM
RankedMonthlyOrderAmount
WHERE
ranking <= 10;
优化思路
- 索引优化:
- 在
orders
表的user_id
和order_date
列上创建联合索引,即CREATE INDEX idx_user_date ON orders(user_id, order_date);
。这样在连接users
表和orders
表时,以及按order_date
进行分组时,可以利用索引快速定位数据,提升查询性能。
- 在
users
表的user_id
列上确保有索引,如果没有,创建索引CREATE INDEX idx_user_id ON users(user_id);
,以加速连接操作。
- 使用CTE(Common Table Expressions):
- 通过CTE将复杂的查询分解为多个逻辑步骤,使查询更易读,同时数据库优化器可以对每个CTE进行独立优化。第一个CTE
MonthlyOrderAmount
计算每个用户每月的订单总金额,第二个CTE RankedMonthlyOrderAmount
对每个月的订单总金额进行排名。
- 避免函数操作:虽然在这个查询中
DATE_FORMAT
函数是必要的,但在其他情况下,应尽量避免在查询条件或连接条件的列上使用函数,因为这会阻止索引的使用。例如,如果要过滤某个月的数据,最好是将日期范围以BETWEEN
的形式进行比较,而不是在日期列上使用函数。
- 分区表(如果适用):如果数据量非常大,可以考虑对
orders
表按order_date
进行分区,例如按月分区。这样在查询某个月的数据时,可以快速定位到对应的分区,减少扫描的数据量,提升查询性能。