避免游戏中的批量 sql

本文介绍了一种游戏数据管理的方法,将玩家数据分为个人数据和交互数据,并探讨了如何通过逻辑处理避免批量SQL操作,减少数据库压力,提高效率。

先说明我比较喜欢的服务端的数据存储的设计是把玩家数据分成两部分,一部分是玩家的个人数据,这种数据只会被玩家自己更新,比如装备系统,任务系统等;另一部分是玩家的交互数据,这部分数据在自己不在线时,也可被其他的操作更新。个人数据由统一的个人数据管理模块管理,交互数据由不同的玩法模块管理,该模块会根据需要从数据库拉取数据,并把内存的数据落地到数据库。下面说的内容是针对交互数据。

处理交互数据时,有时会需要批量更新玩家信息。这里总结一些情况下的处理,通过逻辑避免批量的 sql 操作,数据库可以使用 MySQL 或者 MongoDB 。通常情况下,一个游戏进程支撑的在线人数是一定的,并且注册玩家的数量也是一定的。我经历的几款普通的游戏都是一个服的注册玩家最多几万人,最多同时在线人数也就是开服前三天,其实人数最多时也就几百人。所以在这个量级下,某次操作批量更新几百个玩家完全不是问题。但是总要有一点追求吧,万一后面进了项目组游戏会上微信,这个玩家数量就很大了。所以写逻辑时还是保持些追求,有一些追求,就会先在逻辑上避免批量的 sql 。
写避免批量 sql 逻辑的另一个直观的原因是不需要同时更新这些玩家数据。

全服邮件

最常见的就是全服邮件逻辑。全服邮件是运营人员只发一封邮件,然后程序通过逻辑让每个玩家都可以领取到这封邮件。如下是最直接一种实现方式,模块接收到包后解析 GlobalMail 数据,然后再插入到每个玩家的邮件数据表中。

          +----> Player1Mail
          +----> Player2Mail
GlobalMail+----->Player3Mail
          +----->....

其实没有必要此刻插入的。玩家打开邮箱收取邮件,完全可以在玩家打开客户端邮箱时才处理。这样就把批量更新邮件数据分散到不同的玩家的操作中。每次打开界面时客户端发送查询邮件的数据包,服务端处理此协议时,检查已经处理过全服邮件,如果未处理此时为玩家添加此邮件。

OpenMailUI++-->GlobalMail+--->Player1Mail
           |            |
OpenMailUI +           +--->Player2Mail

排行榜奖励

排行榜类型的玩法通常是活动期间大家参与活动,积分越高排名也就越高,然后在结算时间内发送排行榜奖励。发送排行榜奖励时,一种直接的做法就是遍历排行榜上的玩家,然后给每个玩家发送一封奖励邮件。假如排行榜上有 10000 名玩家,但就会需要发送 10000 封奖励邮件。但是仔细观察一下,人数很多时的排行榜奖励是分类的,可能前 10 名是 10 种奖励,然后 11 到 99 是一种,100 到 199 是一种,越往后越是很多人的奖励是相同的,总的来说差不多就是几十种不同的奖励。
因此如下所示,把不同的奖励邮件分类,每种类型的奖励邮件对应一个玩家列表,列表中可以有一个或者多个玩家。这种归类的邮件有点类似于全服邮件,可以把全服邮件也看成是这种类型的邮件,只是全服的邮件的玩家列表针对的是全服玩家。所以全服邮件的邮件数据中不需要记录玩家的 id ,但是这种归类的邮件需要记录列表中的玩家 id ,这样才知道列表中有哪些玩家。
这种归类后的邮件处理方式也与全服邮件类似,不批量更新玩家数据,而是分流的把领取邮件分散到不同的玩家打开客户端邮箱界面的行为中去。所以服务端收到客户端发送来的邮件查询包后,此时需要检查玩家是否领取过全服邮件,玩家是否有一些归类邮件还未领取。

MailKind1 - PlayerList
MailKind2 - PlayerList
...
MailKindn - PlayerList

结算后,把某字段清 0

比如还是排行类玩法,现在根据玩家积分产生的排行榜,结算后需要把玩家的积分清 0 。这个和该玩法的实现有关。有一种实现是排行榜上所有玩家数据都被保存在一个字段中,结算后直接清除这个字段即可,简单而且一条 sql 就搞定了。还有一种实现活动中每个玩家的数据稍微复杂,而且有些字段会更新比较频繁,数据存储就分玩家来存,每个玩家一条记录,这样结算时,需要清除其中的积分字段时,直接的方式就是通过批量 sql 更新来清除积分字段。其实这时的批量更新也是可以通过逻辑绕开的。方法与上面一致,在需要时才更新
所以如下所示。在获取玩家数据时(若此时不在内存,则先从 db 加载)根据上次刷新时间RefreshTime 判断玩家数据是否过期,如果过期则执行 Clear 操作清除一些过期字段,比如积分。然后再返回玩家数据,如果已经清除了,则在玩家数据中记录当前清除的时间,这样玩家的清除时间大于或者等于刷新时间,之后再获取时数据就未过期,直接返回即可。

GetPlayerData+-->RefreshTime+--------->PlayerData
                            |       +-^
                            +->Clear+

总结

避免批量 sql 的思想就是玩家的数据此时并不需要被更新,可以在需要时才更新,这样就把更新操作分散到每个玩家的某次操作中。所以选择合适的操作来进行更新,就可以达到很好的分散效果,逻辑也不会太复杂。

转载于:https://my.oschina.net/iirecord/blog/1524521

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值