1、优化用户留存记录(按天)接口,解决查询阻塞问题;
This commit is contained in:
parent
401eaaaaba
commit
5ff7aeab26
|
@ -1550,8 +1550,28 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
|||
|
||||
// 使用 goroutine 处理并发查询
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 创建一个 channel 来接收每一天的查询结果
|
||||
resultChan := make(chan models.MgUserDayRetention, 100)
|
||||
//resultChan := make(chan models.MgUserDayRetention, 100)
|
||||
|
||||
// 计算预计查询天数(或月份)
|
||||
var totalDays int
|
||||
if req.OnlyFirstDay {
|
||||
// 当前月的1号
|
||||
now := time.Now()
|
||||
currentMonthFirst := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||
// 计算从 nextMonth 到 currentMonthFirst 包含的1号数量
|
||||
totalDays = countFirstDays(nextMonth, currentMonthFirst)
|
||||
} else {
|
||||
// 按天查询:计算两个日期之间的天数
|
||||
startDateTime, _ := time.Parse("2006-01-02", startDate)
|
||||
currentTime, _ := time.Parse("2006-01-02", currentDate)
|
||||
totalDays = int(currentTime.Sub(startDateTime).Hours()/24) + 1
|
||||
if totalDays <= 0 {
|
||||
totalDays = 1
|
||||
}
|
||||
}
|
||||
resultChan := make(chan models.MgUserDayRetention, totalDays)
|
||||
|
||||
// 控制并发数的最大值,避免数据库过载
|
||||
sem := make(chan struct{}, 10) // 同时最多 10 个 goroutine 执行
|
||||
|
@ -1577,15 +1597,16 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
|||
|
||||
var retainedUserCount int64
|
||||
var unsubOnDay int64
|
||||
var localErr error // 使用局部变量
|
||||
|
||||
// 查询该天的留存用户数
|
||||
err = e.Orm.Model(&models.MgOrder{}).
|
||||
localErr = e.Orm.Model(&models.MgOrder{}).
|
||||
Where("state = 1 AND created_at between ? and ?", currentMonthFirstDay, currentMonthNextFirstDay).
|
||||
Or("state = 2 AND unsubscribe_time > ? AND created_at between ? and ?", date+" 23:59:59", currentMonthFirstDay, currentMonthNextFirstDay).
|
||||
Count(&retainedUserCount).Error
|
||||
|
||||
// 查询该天的退订用户数
|
||||
err = e.Orm.Table("mg_order").
|
||||
localErr = e.Orm.Table("mg_order").
|
||||
Where("unsubscribe_time >= ?", date+" 00:00:00").
|
||||
Where("unsubscribe_time <= ?", date+" 23:59:59").
|
||||
Where("created_at >= ?", currentMonthFirstDay).
|
||||
|
@ -1593,8 +1614,8 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
|||
Where("state = 2"). // 状态为2表示退订
|
||||
Count(&unsubOnDay).Error
|
||||
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
if localErr != nil {
|
||||
e.Logger.Error(localErr)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1636,6 +1657,7 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
|||
|
||||
var retainedUserCount int64
|
||||
var unsubOnDay int64
|
||||
var localErr error // 使用局部变量
|
||||
|
||||
// 查询该天的留存用户数
|
||||
err = e.Orm.Model(&models.MgOrder{}).
|
||||
|
@ -1643,8 +1665,10 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
|||
Or("state = 2 AND unsubscribe_time > ? AND created_at between ? and ?", date+" 23:59:59", currentMonthFirstDay, currentMonthNextFirstDay).
|
||||
Count(&retainedUserCount).Error
|
||||
|
||||
//retainedUserCount, localErr = getRetentionForDay(date, e.Orm, currentMonthFirstDay, currentMonthNextFirstDay)
|
||||
|
||||
// 查询该天的退订用户数
|
||||
err = e.Orm.Table("mg_order").
|
||||
localErr = e.Orm.Table("mg_order").
|
||||
Where("unsubscribe_time >= ?", date+" 00:00:00").
|
||||
Where("unsubscribe_time <= ?", date+" 23:59:59").
|
||||
Where("created_at >= ?", currentMonthFirstDay).
|
||||
|
@ -1652,8 +1676,8 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
|||
Where("state = 2"). // 状态为2表示退订
|
||||
Count(&unsubOnDay).Error
|
||||
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
if localErr != nil {
|
||||
e.Logger.Error(localErr)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1716,6 +1740,39 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
|||
e.OK(resp, "success")
|
||||
}
|
||||
|
||||
// monthsBetween 返回 start 和 end 之间完整的月份数。
|
||||
// 如果 end 的日期在 start 的日期之前(不满一个月),则不计入。
|
||||
func monthsBetween(start, end time.Time) int {
|
||||
// 保证 start 在前,end 在后
|
||||
if start.After(end) {
|
||||
start, end = end, start
|
||||
}
|
||||
|
||||
y1, m1, d1 := start.Date()
|
||||
y2, m2, d2 := end.Date()
|
||||
|
||||
// 计算年份和月份的差异
|
||||
months := (y2-y1)*12 + int(m2-m1)
|
||||
// 如果 end 的日子小于 start 的日子,说明还没有满一个月
|
||||
if d2 < d1 {
|
||||
months--
|
||||
}
|
||||
return months
|
||||
}
|
||||
|
||||
// countFirstDays 返回从 start 到 end(均为每月1号)之间包含的月份数。
|
||||
// 例如:start = 2024-11-01, end = 2025-02-01,则返回 4(分别是 2024-11-01, 2024-12-01, 2025-01-01, 2025-02-01)。
|
||||
func countFirstDays(start, end time.Time) int {
|
||||
// 如果 start 在 end 之后,返回 0
|
||||
if start.After(end) {
|
||||
return 1
|
||||
}
|
||||
y1, m1, _ := start.Date()
|
||||
y2, m2, _ := end.Date()
|
||||
// 计算月份差,注意此处 start 和 end 都应为当月1号
|
||||
return (y2-y1)*12 + int(m2-m1) + 1
|
||||
}
|
||||
|
||||
// SysChannelList 查询系统渠道编码
|
||||
// @Summary 查询系统渠道编码
|
||||
// @Tags 2024-咪咕-管理后台
|
||||
|
@ -2081,25 +2138,25 @@ func (e MiGuDeployService) CalculateRevenueAnalysis(c *gin.Context) {
|
|||
query = query.Where("channel_code = ?", req.Channel)
|
||||
}
|
||||
|
||||
// 获取每个月的新用户数和有效用户数,以下代码是按退订时间超过1天来统计数据
|
||||
//// 获取每个月的新用户数和有效用户数,以下代码是按退订时间超过1天来统计数据
|
||||
var result []models.MonthlyRetention
|
||||
err = query.
|
||||
Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
||||
COUNT(DISTINCT phone_number) AS new_user_count,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN unsubscribe_time IS NULL OR TIMESTAMPDIFF(HOUR, subscribe_time, unsubscribe_time) > 24
|
||||
THEN phone_number END) AS valid_users_count`).
|
||||
COUNT(DISTINCT phone_number) AS new_user_count,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN unsubscribe_time IS NULL OR TIMESTAMPDIFF(HOUR, subscribe_time, unsubscribe_time) > 24
|
||||
THEN phone_number END) AS valid_users_count`).
|
||||
Group("month").
|
||||
Order("month").
|
||||
Find(&result).Error
|
||||
|
||||
// 以下代码是按非1小时退订来统计数据
|
||||
////以下代码是按非1小时退订来统计数据
|
||||
//err = query.
|
||||
// Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
||||
// COUNT(DISTINCT phone_number) AS new_user_count,
|
||||
// COUNT(DISTINCT CASE
|
||||
// WHEN is_one_hour_cancel != 1
|
||||
// THEN phone_number END) AS valid_users_count`).
|
||||
// COUNT(DISTINCT phone_number) AS new_user_count,
|
||||
// COUNT(DISTINCT CASE
|
||||
// WHEN is_one_hour_cancel != 1
|
||||
// THEN phone_number END) AS valid_users_count`).
|
||||
// Group("month").
|
||||
// Order("month").
|
||||
// Find(&result).Error
|
||||
|
|
Loading…
Reference in New Issue
Block a user