咨询:按指定产品家族与日期范围统计已售产品数量的最优方案
嘿,我来帮你梳理下这个统计需求的最优实现方式~
最优实现方案
针对你给出的模型结构,我从直接数据库查询(性能最优)和ORM框架实现两种常见场景来给方案,同时附上性能优化的关键点。
1. 直接SQL查询(大数据量首选)
直接通过数据库SQL完成关联、过滤和聚合是性能最高的方式,尤其是数据量较大时,能减少应用层的处理压力。
基础SQL查询(通用型)
适用于大多数关系型数据库(MySQL、PostgreSQL等):
SELECT p.id AS product_id, CONCAT('product_', p.id) AS product_key, SUM(oi.amount) AS total_sold FROM "Order" o -- 注意Order是关键字,部分数据库需要加引号 JOIN OrderItem oi ON o.id = oi.order_id JOIN Product p ON oi.product_id = p.id JOIN Family f ON p.family_id = f.id WHERE o.placed_on BETWEEN '2024-01-01' AND '2024-01-07' -- 替换为你的d1和d2 AND f.id = 123 -- 替换为指定的家族ID GROUP BY p.id ORDER BY total_sold DESC;
这个查询会返回每个产品的ID、格式化后的键名和总销量,你可以在应用层把结果转换成你需要的[{"product_xxx": 数量}, ...]格式。
PostgreSQL专属优化(直接生成目标JSON)
如果用PostgreSQL,能直接在数据库层面生成你要的JSON结构,省去应用层转换步骤:
SELECT json_agg(json_build_object(CONCAT('product_', p.id), SUM(oi.amount))) AS sales_data FROM "Order" o JOIN OrderItem oi ON o.id = oi.order_id JOIN Product p ON oi.product_id = p.id JOIN Family f ON p.family_id = f.id WHERE o.placed_on BETWEEN '2024-01-01' AND '2024-01-07' AND f.id = 123 GROUP BY f.id;
执行后直接返回类似[{"product_24": 3435}, {"product_34": 56}]的结果,完全匹配你的输出需求。
2. ORM框架实现(以Django为例)
如果用ORM开发(比如Django、SQLAlchemy),代码更易维护,同时也能保证性能:
from django.db.models import Sum from django.db.models.functions import Concat from django.db.models import Value # 配置参数:替换为你的家族ID和日期范围 target_family_id = 123 start_date = "2024-01-01" end_date = "2024-01-07" # 构建查询 sales_queryset = ( Product.objects .filter( family_id=target_family_id, # 跨表过滤日期范围内的订单 orderitem__order__placed_on__range=(start_date, end_date) ) # 生成指定格式的产品键名,同时统计总销量 .annotate( product_key=Concat(Value('product_'), 'id'), total_sold=Sum('orderitem__amount') ) # 只保留需要的字段 .values('product_key', 'total_sold') ) # 转换成目标JSON格式 result = [{item['product_key']: item['total_sold']} for item in sales_queryset]
这个代码会直接生成你需要的列表嵌套字典结构,ORM会自动优化底层SQL,避免N+1查询问题。
3. 性能优化关键点
不管用哪种方式,这些优化能让你的查询更快:
- 添加索引:给
Order.placed_on、OrderItem.order_id、OrderItem.product_id、Product.family_id这几个字段建立索引,大幅提升JOIN和过滤的速度。 - 预聚合(可选):如果数据量极大且实时性要求不高,可以每天定时跑统计任务,把各家族产品的销量存入专门的统计表,查询时直接读取预统计数据,性能提升非常明显。
- 减少数据传输:尽量让数据库完成聚合和过滤,只返回需要的字段,避免把大量原始数据拉到应用层处理。
内容的提问来源于stack exchange,提问作者pzin
相关产品推荐
相关产品推荐

