游戏开发

MySQL WHERE IN还是范围查询

2021-04-21  本文已影响0人  higher2017

我经常遇到需要查询MySQL表中大量数据的情形。在游戏行业,一次性对一张表进行很多数据的查询一般意味都着不怎么好的情况发生了(一般是出bug需要捞线上数据进行补偿、修复等操作)。这种时候采用什么手段是有一点点的讲究的(尤其是游戏还没有停服的时候)。要求:不影响线上服务器的性能又快速查出数据。
下面我用自己遇到的一个场景来说明一下。

实际案例:

线上出了一个bug:参与集福气活动的很多玩家奖励少发了。

现在我们能取到的相关数据:

  1. 能计算出玩家真实可获得奖励数量的:表A(表A中有数据的玩家也有可能是正常玩家,主键是userId);

  2. 参与集福气活动真实发放的奖励数量:实际奖励发放表(可能存在少发奖励);

要补发给玩家的奖励可以通过表A和奖励发放表计算得出(需要补发的奖励 = 表A - 实际奖励发放表)。

现在的做法是写个job把这份补发奖励的名单拉取来(没错不等关服维护了,直接在线跑job)。这里要强调一点:只有在“实际奖励发放表”存在的玩家才有可能需要补发奖励。

这里我给了3个方案来确定所有需要补发奖励的名单:

// 实际奖励发放表数据加载
Map<Long, UserRealGainRewardInfo> map = loadUserRealGainRewardInfos();
// 获得所有可能要补发奖励的userId列表
Collection<Long> effectUserIds = map.keys(); 
// SELECT * FROM A WHERE userId IN(effectUserIds...)
Map<Long, A_TableInfo> map1 = DbManager.selectATbaleInfosWhereIn(effectUserIds);
// 根据 表A 和 实际奖励发放表 补发奖励
sendMail(map, map1);
// 实际奖励发放表数据加载
Map<Long, UserRealGainRewardInfo> map = loadUserRealGainRewardInfos();
// 循环取一定范围userId的玩家不断处理: SELECT * FROM A WHERE userId >= 0 AND userId < ?
List<A_TableInfo> list = DbManager.selectATableInfos();
sendMail(list, map);
// 实际奖励发放表数据加载
List<UserRealGainRewardInfo> list = loadUserRealGainRewardInfos();
for (UserRealGainRewardInfo info : list) {
    // SELECT * FROM A WHERE userId = ?
    A_TableInfo aInfo = DbManager.selectATableInfo(info.getUserId());
    sendMail(aInfo, map);
}

第三个方法是我用来凑数的,请各位千万不要这么做。除非实际奖励发放表中玩家人数只有个位数。那到底是用第一个还是第二个呢?这个问题主要看两点:

  1. 实际奖励发放表的数据量;

  2. 表A的数据量;

涉及的知识:

我们的实际情况:

我们最后决定使用的方式:

采用方法二:范围查询的方式把数据加到内存中然后再筛选

原因:

需要查询的MySQL数据很多(玩家名单list有几万个),使用范围查找能加快查询速度并且即使将表A的数据全部加载在内存中job服务器也是没有压力。

上一篇下一篇

猜你喜欢

热点阅读