perf: use channel index order and avoid redundant metric grouping
This commit is contained in:
@@ -2,11 +2,37 @@ package business
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"kra/internal/biz/business"
|
||||
)
|
||||
|
||||
func whereMetricChannels(db *gorm.DB, keys []business.ChannelKey) *gorm.DB {
|
||||
bySource := map[string][]uint64{}
|
||||
for _, key := range keys {
|
||||
bySource[key.SourceDB] = append(bySource[key.SourceDB], key.ID)
|
||||
}
|
||||
sources := make([]string, 0, len(bySource))
|
||||
for source := range bySource {
|
||||
sources = append(sources, source)
|
||||
}
|
||||
sort.Strings(sources)
|
||||
if len(sources) == 0 {
|
||||
return db.Where("1=0")
|
||||
}
|
||||
var condition *gorm.DB
|
||||
for _, source := range sources {
|
||||
part := db.Session(&gorm.Session{NewDB: true}).Where("source_db=? AND promote_id IN ?", source, bySource[source])
|
||||
if condition == nil {
|
||||
condition = part
|
||||
} else {
|
||||
condition = condition.Or(part)
|
||||
}
|
||||
}
|
||||
return db.Where(condition)
|
||||
}
|
||||
|
||||
func (r *channelRepo) Metrics(ctx context.Context, roots, statKeys []business.ChannelKey, dedup bool) (*business.ChannelMetricData, error) {
|
||||
db := r.data.DB().WithContext(ctx)
|
||||
metrics := &business.ChannelMetricData{Games: map[business.ChannelKey]int64{}, Players: map[business.ChannelKey]int64{}, Pay: map[business.ChannelKey]string{}}
|
||||
@@ -31,7 +57,7 @@ func (r *channelRepo) Metrics(ctx context.Context, roots, statKeys []business.Ch
|
||||
if metrics.GamesAvailable {
|
||||
for start := 0; start < len(roots); start += 300 {
|
||||
var rows []countRow
|
||||
if err := db.Table("tab_promote_apply").Select("source_db,promote_id,COUNT(DISTINCT game_id) AS count").Where("status = 1 AND (source_db,promote_id) IN ?", channelPairs(roots[start:min(start+300, len(roots))])).Group("source_db,promote_id").Scan(&rows).Error; err != nil {
|
||||
if err := whereMetricChannels(db, roots[start:min(start+300, len(roots))]).Table("tab_promote_apply").Select("source_db,promote_id,COUNT(DISTINCT game_id) AS count").Where("status = 1").Group("source_db,promote_id").Scan(&rows).Error; err != nil {
|
||||
return nil, business.ErrStorage
|
||||
}
|
||||
for _, row := range rows {
|
||||
@@ -41,9 +67,9 @@ func (r *channelRepo) Metrics(ctx context.Context, roots, statKeys []business.Ch
|
||||
}
|
||||
// 每批按平台/渠道一起查询,避免逐个渠道访问数据库,也避免参数数量无限增长。
|
||||
for start := 0; start < len(statKeys); start += 300 {
|
||||
pairs := channelPairs(statKeys[start:min(start+300, len(statKeys))])
|
||||
keys := statKeys[start:min(start+300, len(statKeys))]
|
||||
if metrics.PlayersAvailable {
|
||||
q := db.Table("tab_user").Where("(puid = 0 OR puid IS NULL) AND (source_db,promote_id) IN ?", pairs)
|
||||
q := whereMetricChannels(db, keys).Table("tab_user").Where("puid = 0 OR puid IS NULL")
|
||||
if dedup {
|
||||
var players []struct {
|
||||
SourceDB string `gorm:"column:source_db"`
|
||||
@@ -72,7 +98,7 @@ func (r *channelRepo) Metrics(ctx context.Context, roots, statKeys []business.Ch
|
||||
PromoteID uint64
|
||||
Amount string
|
||||
}
|
||||
if err := db.Table("tab_spend").Select("source_db,promote_id,COALESCE(SUM(pay_amount),0) AS amount").Where("pay_status = 1 AND (source_db,promote_id) IN ?", pairs).Group("source_db,promote_id").Scan(&rows).Error; err != nil {
|
||||
if err := whereMetricChannels(db, keys).Table("tab_spend").Select("source_db,promote_id,COALESCE(SUM(pay_amount),0) AS amount").Where("pay_status = 1").Group("source_db,promote_id").Scan(&rows).Error; err != nil {
|
||||
return nil, business.ErrStorage
|
||||
}
|
||||
for _, row := range rows {
|
||||
|
||||
Reference in New Issue
Block a user