perf: 减少统计页面资料读取并优化区服选项查询
This commit is contained in:
@@ -213,9 +213,6 @@ func (r *analyticsRepo) Aggregate(ctx context.Context, kind business.AnalyticsKi
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
if err := fillAnalyticsNames(db, kind, scope, f, rowMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, row := range rowMap {
|
||||
result.Rows = append(result.Rows, row)
|
||||
}
|
||||
@@ -228,6 +225,18 @@ func (r *analyticsRepo) Aggregate(ctx context.Context, kind business.AnalyticsKi
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *analyticsRepo) FillNames(ctx context.Context, kind business.AnalyticsKind, scope business.AnalyticsScope, f business.AnalyticsFilter, rows []*business.AnalyticsRow) error {
|
||||
if len(rows) == 0 {
|
||||
return nil
|
||||
}
|
||||
byKey := make(map[business.AnalyticsKey]*business.AnalyticsRow, len(rows))
|
||||
for _, row := range rows {
|
||||
byKey[row.AnalyticsKey] = row
|
||||
}
|
||||
return fillAnalyticsNames(r.data.DB().WithContext(ctx), kind, scope, f, byKey)
|
||||
}
|
||||
|
||||
func analyticsPairs(keys []business.AnalyticsKey) [][]any {
|
||||
result := make([][]any, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
@@ -269,6 +278,12 @@ func fillAnalyticsNames(db *gorm.DB, kind business.AnalyticsKind, scope business
|
||||
for key := range rows {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
if keys[i].ID != keys[j].ID {
|
||||
return keys[i].ID < keys[j].ID
|
||||
}
|
||||
return keys[i].SourceDB < keys[j].SourceDB
|
||||
})
|
||||
type entityPO struct {
|
||||
ID int64
|
||||
SourceDB string `gorm:"column:source_db"`
|
||||
|
||||
@@ -34,6 +34,9 @@ func TestAnalyticsChannelTreeAndAdminOfficialRows(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := repo.FillNames(context.Background(), business.ChannelAnalytics, scope, filter, data.Rows); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(data.Rows) != 3 || data.GlobalCounts != nil {
|
||||
t.Fatalf("普通商务统计范围错误: %+v", data)
|
||||
}
|
||||
@@ -69,6 +72,12 @@ func TestAnalyticsFiltersKeepHierarchyAndSnapshotNames(t *testing.T) {
|
||||
kind := 1
|
||||
filter.PromoteType = &kind
|
||||
data, err = repo.Aggregate(context.Background(), business.ChannelAnalytics, scope, filter)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := repo.FillNames(context.Background(), business.ChannelAnalytics, scope, filter, data.Rows); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err != nil || len(data.Rows) != 1 || data.Rows[0].ID != 100 || portraitTestMoney(data.Rows[0].Pay) != "20.20" || data.Rows[0].PromoteType == nil || *data.Rows[0].PromoteType != 0 {
|
||||
t.Fatalf("类型筛选应限制参与渠道,同时显示归根后的当前资料: %+v %v", data, err)
|
||||
}
|
||||
@@ -78,6 +87,9 @@ func TestAnalyticsFiltersKeepHierarchyAndSnapshotNames(t *testing.T) {
|
||||
if err != nil || len(data.Rows) != 2 {
|
||||
t.Fatalf("按游戏快照名筛选错误: %+v %v", data, err)
|
||||
}
|
||||
if err := repo.FillNames(context.Background(), business.GameAnalytics, scope, filter, data.Rows); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, row := range data.Rows {
|
||||
if row.SourceDB == "lx" && (row.ID != 1 || row.Name != "游戏甲" || row.Counts.Register != 1) {
|
||||
t.Fatalf("应按报表快照筛选、用当前游戏名展示: %+v", row)
|
||||
|
||||
@@ -155,7 +155,11 @@ func (r *serverAnalysisRepo) Servers(ctx context.Context, sources, games []strin
|
||||
return nil, business.ErrServerOptionsUnavailable
|
||||
}
|
||||
}
|
||||
q := db.Table("tab_game_server s").Where("EXISTS (?)", db.Table("tab_game g").Select("1").Where("g.source_db=s.source_db AND g.id=s.game_id AND g.game_name IN ?", games))
|
||||
// MySQL 5.7 不会将相关 EXISTS 展开为半连接,导致扫描全部区服。
|
||||
// 多列 IN 让优化器先按游戏名索引定位,再使用区服的 game_id 索引,
|
||||
// 同时保留平台匹配和重复游戏资料不扩增结果的语义。
|
||||
gamesQuery := db.Table("tab_game g").Select("g.source_db,g.id").Where("g.game_name IN ?", games)
|
||||
q := db.Table("tab_game_server s").Where("(s.source_db,s.game_id) IN (?)", gamesQuery)
|
||||
if len(sources) > 0 {
|
||||
q = q.Where("s.source_db IN ?", sources)
|
||||
}
|
||||
|
||||
@@ -85,3 +85,30 @@ func TestServerAnalysisStorageScopeSnapshotAndPreference(t *testing.T) {
|
||||
t.Fatal("缺身份表应明确未接入")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerOptionsPreservePlatformFilterAndDoNotDuplicateMatches(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
for _, sql := range []string{
|
||||
"CREATE TABLE tab_game(id INTEGER,source_db TEXT,game_name TEXT)",
|
||||
"INSERT INTO tab_game VALUES(1,'lx','甲'),(1,'lx','甲'),(1,'hw','乙'),(2,'lx','乙')",
|
||||
"CREATE TABLE tab_game_server(id INTEGER,source_db TEXT,game_id INTEGER,server_num TEXT,server_name TEXT,start_time INTEGER)",
|
||||
"INSERT INTO tab_game_server VALUES(1,'lx',1,'001','一区',100),(2,'lx',1,'002','二区',200),(3,'hw',1,'001','其他平台',300),(4,'lx',2,'001','其他游戏',400)",
|
||||
} {
|
||||
if err := db.Exec(sql).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
repo := NewServerAnalysisRepo(testData{db})
|
||||
rows, err := repo.Servers(context.Background(), nil, []string{"甲"}, "", 100)
|
||||
if err != nil || len(rows) != 2 || rows[0].Name != "一区" || rows[1].Number != "002" {
|
||||
t.Fatalf("相同游戏资料不能扩增区服,异平台同号不能匹配: %+v %v", rows, err)
|
||||
}
|
||||
rows, err = repo.Servers(context.Background(), []string{"lx"}, []string{"甲", "乙"}, "区", 1)
|
||||
if err != nil || len(rows) != 1 || rows[0].Name != "一区" {
|
||||
t.Fatalf("名称筛选、排序或数量限制改变: %+v %v", rows, err)
|
||||
}
|
||||
rows, err = repo.Servers(context.Background(), []string{"hw"}, []string{"甲"}, "", 100)
|
||||
if err != nil || len(rows) != 0 {
|
||||
t.Fatalf("平台筛选被忽略: %+v %v", rows, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user