perf: avoid correlated channel scans in portrait queries

This commit is contained in:
Yvan
2026-11-05 17:11:59 +08:00
parent a43d140339
commit aaee077253
3 changed files with 11 additions and 9 deletions
+7 -5
View File
@@ -96,11 +96,13 @@ func (r *businessPortraitRepo) PlatformBusiness(ctx context.Context, key busines
return &business.PortraitPlatformBusiness{ID: po.ID, Account: po.Account, RealName: po.RealName, Level: po.Level, Status: po.Status, Commerce1: po.Commerce1, Commerce2: po.Commerce2, CreatedUnix: po.CreatedUnix}, nil
}
func portraitPromoteScope(db *gorm.DB, scope business.PortraitReportScope, sourceColumn, promoteColumn string) *gorm.DB {
// Build an uncorrelated channel set once, so MySQL can use a semijoin instead
// of reevaluating a descendant-tree predicate for each historical event.
func portraitPromoteScope(db *gorm.DB, scope business.PortraitReportScope) *gorm.DB {
if scope.Root != nil {
return channelGameTree(db, business.ChannelGameScope{Root: scope.Root, IncludeSub: scope.IncludeSub}).Select("1").Where("p.source_db = " + sourceColumn + " AND p.id = " + promoteColumn)
return channelGameTree(db, business.ChannelGameScope{Root: scope.Root, IncludeSub: scope.IncludeSub}).Select("p.source_db,p.id")
}
q := db.Table("tab_promote scope_promote").Select("1").Where("scope_promote.source_db = " + sourceColumn + " AND scope_promote.id = " + promoteColumn)
q := db.Table("tab_promote scope_promote").Select("scope_promote.source_db,scope_promote.id")
if len(scope.Pairs) == 0 {
return q.Where("1=0")
}
@@ -115,7 +117,7 @@ func portraitReportQuery(db *gorm.DB, scope business.PortraitReportScope, table,
if len(scope.Sources) > 0 {
q = q.Where("r.source_db IN ?", scope.Sources)
}
return q.Where("EXISTS (?)", portraitPromoteScope(db, scope, "r.source_db", "r.promote_id"))
return q.Where("(r.source_db,r.promote_id) IN (?)", portraitPromoteScope(db, scope))
}
func portraitIdentity(db *gorm.DB, dedup bool) string {
if dedup {
@@ -249,7 +251,7 @@ func portraitHourly(db *gorm.DB, scope business.PortraitReportScope, result *bus
table, column, aggregate, condition string
series map[string]string
}{{"tab_user", "register_time", "COUNT(*)", "(r.puid = 0 OR r.puid IS NULL)", result.RegisterSeries}, {"tab_spend", "pay_time", "COALESCE(SUM(r.pay_amount),0)", "r.pay_status = 1", result.PaySeries}} {
q := db.Table(metric.table+" r").Where("r."+metric.column+" >= ? AND r."+metric.column+" < ?", start, end).Where(metric.condition).Where("EXISTS (?)", portraitPromoteScope(db, scope, "r.source_db", "r.promote_id"))
q := db.Table(metric.table+" r").Where("r."+metric.column+" >= ? AND r."+metric.column+" < ?", start, end).Where(metric.condition).Where("(r.source_db,r.promote_id) IN (?)", portraitPromoteScope(db, scope))
if len(scope.Sources) > 0 {
q = q.Where("r.source_db IN ?", scope.Sources)
}