虽然后台慢不是不能用,但是销售一直在反映操作很慢让优化。销售后台时间选择器粒度只精确到天,不知道这个地方是不是可以做什么效果比较好的优化。

正常情况下日订单在五百万左右。这个页面需要显示每个 SKU 在不同阶段(状态)的订单的数量。有考虑过用 Redis 但是我们的 Redis 是单机的只用来缓存,经常 flushall 。再单独加一台 Redis 觉得不划算

return Ok(dbContext.Orders.Where(x => x.CreatedAt >= DateTimeOffset.FromUnixTimeMilliseconds(queryForm.StartDate) &&
                                             x.CreatedAt <= DateTimeOffset.FromUnixTimeMilliseconds(queryForm.EndDate))
            .Include(x => x.Sku).Where(x => x.Sku != null)
            .GroupBy(o => o.SkuId)
            .Select(g => new
            {
                SkuId = g.Key,
                SkuName = g.Select(o => o.Sku.TitleEng).FirstOrDefault(),
                Delivering = g.Count(o => o.Status == (int)OrderStatusEnum.Delivering),
                Cancelled = g.Count(o => o.Status == (int)OrderStatusEnum.Cancelled),
                InProcess = g.Count(o => o.Status == (int)OrderStatusEnum.InProcess),
                InReview = g.Count(o => o.ReviewTasks.Any(t => t.Pending && t.Result == false)),
                Total = g.Count()
            })
            .ToList());

能想到的索引都已经加了

[Index(nameof(Status))]
[Index(nameof(Input))]
[Index(nameof(SkuId))]
[Index(nameof(UserId))]
[Index(nameof(CreatedAt))]
[Index(nameof(UpdatedAt))]
[Index(nameof(OrderTag))]
[Index(nameof(SendPending))]
[Index(nameof(OrderSource))]
[Index(nameof(UserId), nameof(SkuId), nameof(FromMobileApp))]
[Index(nameof(UserId), nameof(Status))]
[Index(nameof(SkuId), nameof(Status))]
[Index(nameof(Status), nameof(RiskyScore))]
[Index(nameof(UserId), nameof(Input))]
[Index(nameof(UserId), nameof(InputTailing))]
public class Order : BaseEntity
{ ... }
举报· 1030 次点击
登录 注册 站外分享
9 条回复  
hez2010 小成 昨天 22:05
1. 你在代码里加的索引有通过 migration 应用到数据库吗?没同步到数据库表里面是没用的。 2. 建议用异步方法 ToListAsync 。 3. 你可以看看具体生成了什么 SQL ,你这个需求完全没有必要在 SQL 做 GroupBy 和 Select ,你可以先 Select 出来然后 ToList 再在应用端进行 GroupBy ,比如像下面这样,毕竟 MySQL 的数据库引擎的索引做的本身就完全是依托答辩,最好只把 MySQL 当作一个大号 KV 来用。 ```cs return Ok((await dbContext.Orders.Where(x => x.CreatedAt >= DateTimeOffset.FromUnixTimeMilliseconds(queryForm.StartDate) && x.CreatedAt <= DateTimeOffset.FromUnixTimeMilliseconds(queryForm.EndDate)) .Include(x => x.Sku).Where(x => x.Sku != null) .Select(o => new { SkuId = o.SkuId, SkuName = o.Sku.TitleEng, Status = o.Status, ReviewTasks = o.ReviewTasks }) .ToListAsync()) .GroupBy(o => o.SkuId) .Select(g => new { SkuId = g.Key, SkuName = g.Select(o => o.SkuName).FirstOrDefault(), Delivering = g.Count(o => o.Status == (int)OrderStatusEnum.Delivering), Cancelled = g.Count(o => o.Status == (int)OrderStatusEnum.Cancelled), InProcess = g.Count(o => o.Status == (int)OrderStatusEnum.InProcess), InReview = g.Count(o => o.ReviewTasks.Any(t => t.Pending && t.Result == false)), Total = g.Count() }) .ToList()); ```
drymonfidelia 楼主 小成 昨天 22:07
@hez2010 1. 有,这些索引是很早以前就加的,在 MySQL 里看了有应用 3. 感谢,我测试下这种实现的效果
sagaxu 初学 昨天 22:27
日订单在五百万个还请不起 DBA 或者资深开发嘛,单表 15 个索引,且好几个重复无意义
drymonfidelia 楼主 小成 昨天 22:32
@sagaxu 以前有,离职了没招到新的。而且订单单价低,利润率不高
drymonfidelia 楼主 小成 昨天 22:36
@sagaxu 这些索引为什么是无意义的?都是根据代码里不同查询建的,MySQL 好像没有像 MongoDB 那样自动统计不同索引命中次数的功能,不懂怎么看哪些没用
MoYi123 小成 昨天 23:07
问数据库优化的问题不贴 explain 就算了, 现在连 sql 都没有了.
yinmin 小成 4 小时前
直接在 mysql 里用 sql 的 select ,看看需要多久时间。另外,每天 500 万条记录,通常是需要每天凌晨做昨天数据预汇总(数据清洗),例如按小时先预汇总一次,然后从汇总表里取数据。
yinmin 小成 4 小时前
清洗掉客户 id ,按小时(或者 15 分钟)汇总订单数据到“订单汇总表 1”,然后再按天汇总到“订单汇总表 2”。根据查询颗粒度,从“订单汇总表 1”或“订单汇总表 2”取数应该能优化到几秒的级别吧
lbp0200 小成 4 小时前
统计分析,不适合 MySQL ,建议用分析型数据库,比如 duckdb
返回顶部