1、优化用户留存记录(按天)接口,解决查询阻塞问题;
This commit is contained in:
parent
401eaaaaba
commit
5ff7aeab26
|
@ -1550,8 +1550,28 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
||||||
|
|
||||||
// 使用 goroutine 处理并发查询
|
// 使用 goroutine 处理并发查询
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
// 创建一个 channel 来接收每一天的查询结果
|
// 创建一个 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 执行
|
sem := make(chan struct{}, 10) // 同时最多 10 个 goroutine 执行
|
||||||
|
@ -1577,15 +1597,16 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
||||||
|
|
||||||
var retainedUserCount int64
|
var retainedUserCount int64
|
||||||
var unsubOnDay 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).
|
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).
|
Or("state = 2 AND unsubscribe_time > ? AND created_at between ? and ?", date+" 23:59:59", currentMonthFirstDay, currentMonthNextFirstDay).
|
||||||
Count(&retainedUserCount).Error
|
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+" 00:00:00").
|
||||||
Where("unsubscribe_time <= ?", date+" 23:59:59").
|
Where("unsubscribe_time <= ?", date+" 23:59:59").
|
||||||
Where("created_at >= ?", currentMonthFirstDay).
|
Where("created_at >= ?", currentMonthFirstDay).
|
||||||
|
@ -1593,8 +1614,8 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
||||||
Where("state = 2"). // 状态为2表示退订
|
Where("state = 2"). // 状态为2表示退订
|
||||||
Count(&unsubOnDay).Error
|
Count(&unsubOnDay).Error
|
||||||
|
|
||||||
if err != nil {
|
if localErr != nil {
|
||||||
e.Logger.Error(err)
|
e.Logger.Error(localErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1636,6 +1657,7 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
||||||
|
|
||||||
var retainedUserCount int64
|
var retainedUserCount int64
|
||||||
var unsubOnDay int64
|
var unsubOnDay int64
|
||||||
|
var localErr error // 使用局部变量
|
||||||
|
|
||||||
// 查询该天的留存用户数
|
// 查询该天的留存用户数
|
||||||
err = e.Orm.Model(&models.MgOrder{}).
|
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).
|
Or("state = 2 AND unsubscribe_time > ? AND created_at between ? and ?", date+" 23:59:59", currentMonthFirstDay, currentMonthNextFirstDay).
|
||||||
Count(&retainedUserCount).Error
|
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+" 00:00:00").
|
||||||
Where("unsubscribe_time <= ?", date+" 23:59:59").
|
Where("unsubscribe_time <= ?", date+" 23:59:59").
|
||||||
Where("created_at >= ?", currentMonthFirstDay).
|
Where("created_at >= ?", currentMonthFirstDay).
|
||||||
|
@ -1652,8 +1676,8 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
||||||
Where("state = 2"). // 状态为2表示退订
|
Where("state = 2"). // 状态为2表示退订
|
||||||
Count(&unsubOnDay).Error
|
Count(&unsubOnDay).Error
|
||||||
|
|
||||||
if err != nil {
|
if localErr != nil {
|
||||||
e.Logger.Error(err)
|
e.Logger.Error(localErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1716,6 +1740,39 @@ func (e MiGuDeployService) UserDayRetentionList(c *gin.Context) {
|
||||||
e.OK(resp, "success")
|
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 查询系统渠道编码
|
// SysChannelList 查询系统渠道编码
|
||||||
// @Summary 查询系统渠道编码
|
// @Summary 查询系统渠道编码
|
||||||
// @Tags 2024-咪咕-管理后台
|
// @Tags 2024-咪咕-管理后台
|
||||||
|
@ -2081,25 +2138,25 @@ func (e MiGuDeployService) CalculateRevenueAnalysis(c *gin.Context) {
|
||||||
query = query.Where("channel_code = ?", req.Channel)
|
query = query.Where("channel_code = ?", req.Channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取每个月的新用户数和有效用户数,以下代码是按退订时间超过1天来统计数据
|
//// 获取每个月的新用户数和有效用户数,以下代码是按退订时间超过1天来统计数据
|
||||||
var result []models.MonthlyRetention
|
var result []models.MonthlyRetention
|
||||||
err = query.
|
err = query.
|
||||||
Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
||||||
COUNT(DISTINCT phone_number) AS new_user_count,
|
COUNT(DISTINCT phone_number) AS new_user_count,
|
||||||
COUNT(DISTINCT CASE
|
COUNT(DISTINCT CASE
|
||||||
WHEN unsubscribe_time IS NULL OR TIMESTAMPDIFF(HOUR, subscribe_time, unsubscribe_time) > 24
|
WHEN unsubscribe_time IS NULL OR TIMESTAMPDIFF(HOUR, subscribe_time, unsubscribe_time) > 24
|
||||||
THEN phone_number END) AS valid_users_count`).
|
THEN phone_number END) AS valid_users_count`).
|
||||||
Group("month").
|
Group("month").
|
||||||
Order("month").
|
Order("month").
|
||||||
Find(&result).Error
|
Find(&result).Error
|
||||||
|
|
||||||
// 以下代码是按非1小时退订来统计数据
|
////以下代码是按非1小时退订来统计数据
|
||||||
//err = query.
|
//err = query.
|
||||||
// Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
// Select(`DATE_FORMAT(subscribe_time, '%Y-%m') AS month,
|
||||||
// COUNT(DISTINCT phone_number) AS new_user_count,
|
// COUNT(DISTINCT phone_number) AS new_user_count,
|
||||||
// COUNT(DISTINCT CASE
|
// COUNT(DISTINCT CASE
|
||||||
// WHEN is_one_hour_cancel != 1
|
// WHEN is_one_hour_cancel != 1
|
||||||
// THEN phone_number END) AS valid_users_count`).
|
// THEN phone_number END) AS valid_users_count`).
|
||||||
// Group("month").
|
// Group("month").
|
||||||
// Order("month").
|
// Order("month").
|
||||||
// Find(&result).Error
|
// Find(&result).Error
|
||||||
|
|
Loading…
Reference in New Issue
Block a user