设计查询切分策略
- 按季度切分:由于需求是按季度统计,可按时间维度(季度)对订单明细表
order_items
进行切分。假设订单表中有记录订单创建时间的字段order_date
,将不同季度的数据分布在不同的MySQL实例上。例如,通过在表创建时利用PARTITION BY RANGE (YEAR(order_date) * 10 + QUARTER(order_date))
进行分区,每个分区放置在不同实例。
- 按商品ID切分:对于商品表
products
,由于其数据量也较大,可按product_id
进行哈希切分,将不同范围的product_id
数据分布在不同实例。例如,通过MOD(product_id, N)
,其中N
为实例数量,将商品数据均匀分布在各实例。
处理跨实例数据聚合
- 中间结果收集:每个实例先独立计算出本实例内每个季度销量排名前5的商品及其销售总额。可以使用窗口函数实现此计算。
- 全局聚合:将各个实例的中间结果汇总到一个主实例上。在主实例上,对这些中间结果再次进行排名计算,得出最终每个季度销量排名前5的商品及其销售总额。
详细方案及SQL代码
- 每个实例内计算中间结果
-- 在每个实例上执行,假设当前实例处理的order_items数据是对应某几个季度的
WITH RankedSales AS (
SELECT
p.product_id,
p.product_name,
SUM(oi.quantity) AS total_quantity,
SUM(oi.quantity * p.price) AS total_sales,
YEAR(oi.order_date) * 10 + QUARTER(oi.order_date) AS quarter_key,
ROW_NUMBER() OVER (PARTITION BY YEAR(oi.order_date) * 10 + QUARTER(oi.order_date) ORDER BY SUM(oi.quantity) DESC) AS rn
FROM
products p
JOIN
order_items oi ON p.product_id = oi.product_id
GROUP BY
p.product_id, p.product_name, YEAR(oi.order_date) * 10 + QUARTER(oi.order_date)
)
SELECT
product_id,
product_name,
total_quantity,
total_sales,
quarter_key
FROM
RankedSales
WHERE
rn <= 5;
- 主实例上进行全局聚合
-- 在主实例上执行,假设将各实例的中间结果插入到临时表temp_ranked_sales中
WITH GlobalRankedSales AS (
SELECT
product_id,
product_name,
total_quantity,
total_sales,
quarter_key,
ROW_NUMBER() OVER (PARTITION BY quarter_key ORDER BY total_quantity DESC) AS global_rn
FROM
temp_ranked_sales
)
SELECT
product_id,
product_name,
total_quantity,
total_sales,
quarter_key
FROM
GlobalRankedSales
WHERE
global_rn <= 5;