[转载]ASP.NET Web Game 构架设计2--数据库设计

[转载]ASP.NET Web Game 构架设计2–数据库设计 – warensoft专注于.NET – 博客园.

前一篇BlogWebGame服 务器的物理结构做了一个简要说明,下面我们对各个组成元素进行详细说明。

首先来看一下数据库设计。

游戏的数据库设计是项目基础设计中很重要的一个环节,下面将说明以下几个要点:

u 为什么选用SQLServer

u 基本原则

u 表关系的设置

u 数据的冗余设计

u 什么时候使用存储过程

u 什么时候使用EntityFramework什么时候使用ADO.NET

1. 为什么先用SQL Server

首 先,不要对SQL Server的 性能表示怀疑。作为WebGame应 用来讲,它的吞吐能力,承载能力完全够用。

第 二,如果服务代码是使用C#来编写的,那么SQL Server2005/2008能得到最好的C#/Visual Studio兼容性。最重要的是C#中 很多组件都是为SQL Server设 计的,并且做了很多优化,例如:EntityFrameworkSQL CLR等。

第 三,SQL Server中 支持SQL CLR功能,即可以使用C#/VB.NET来 编写自定义函数,存储过程等,对于熟悉C#的 开发人员来讲是一个福音,不仅仅是代码编写规则熟悉,而且可以使用一部分.NET类 库来实现想要的功能,比如说基本.NET类 型,数学运算,WCF等功能。

第 四,可能很多人都觉得使用SQL CLR是 因为T-SQL用的不精,其实不然,SQL CLR实际上是利用C#写 好DLL文件,然后被SQL Server调用,本质上利用了.NET来 提高SQL Server的 性能,在某些情况下SQL CLR的 效率要高于T-SQL

2. 基本原则

在 设计游戏数据库时千万别怕表多,在一个常规的网页游戏中,数据表的数量应该大于150。 因为一个游戏项目,细分起来,是由少则10几 个,多则几十个子系统组织起来的,每个系统都有若干张表来辅助存储。

另 外,游戏系统的数据库可以按状态分为:配置数据存储表(如基本数值配置),状态数据存储表(如计时),以及数据极不稳定的用来表示某个物件所属的中间关系 数据表(如某个用户招募了某一个军官)。总之,要事无巨细,将90%的 数据以数据库的形式存储起来。这么作的原因在于,游戏中很多的数据都是敏感数据,如金币,某个物件的数量等,如果将过多的数据存储于内存中,一旦服务掉 电,丢失的数据将无法挽回,客服的电话会被打爆的。

当 然,如果将大多数数据存储在数据库,反复读写所带来速度问题,也是不可以忽略的,解决方法如下:

u 客户端在加载的时候,就把常用的只读配置数据存储到客户端。

u 客户端要修改数据时,先修改客户端的数据,然后立即显示出来,最后再异步调用服务器的接口,去修改数据。

u 如果客户端一定要等待服务器的处理结果,那么就直接利用异步方式调用服务器接口,但是一定要给用户提示,防止误操作的产生。

u 服务器一定要将常用的数值计算的操作数和结果储存在内存中,以提高响应速度,例如:游戏中常常用到Pow函数,那就在内存中建立一个Pow的函数值表,每次调用时,就直接从表中取出来。

3. 表关系的设计

一 个游戏中会存在很多个子系统,如:用户系统、道具系统、商城系统、社交系统、邮件系统、武将系统、建筑系统、资源系统、计时系统等,除了计时系统比较独 立,其他系统大多数都要用户系统以及用户相关的家系统(基地,城池等)相关联,这样复杂的结构如何设计呢?

首 先,一定要把握住ER的思想,哪些是实体表,哪些是关系表,实体 和实体之间一定要通过关系相联,最好不出现直接的主表子表关系。 同时,在各个关系中一定不要使用级联操作(级联更新,级联删除), 当然,这个约束在表关联比较多的时候就会自动加入。之所以要不存在“主表子 表”关系以及级联操作,是因为整个游戏系统就是一个小型的社会,一旦存在级联,很容易产生“雪崩”效应,修改或删除顶级表的某一条数据中,就有可能影响到N多 个子表,这种影响是的复杂程度是程序员根本无法控制的。比较合理的作法是如果要修改或删除某一个数据,就要从关联关系中的最底层表作起,手动的逐级向上进 行修改或删除。表面上看起来会比较麻烦,但是这种作法带来的好处也是显而易见的,手动控制,可以明确到底哪些数据该删除,哪些数据不该删除(有很多数据是 要用来做统计的,是不能删除的),同时,在这些数据表之间进行导航,可以让程序更清楚数据的存储结构,更清楚自己在做什么。

4. 数据的冗余设计

在 设计数据库时千万别想着什么精简字段,减少冗余,通过关系查找等所谓的优化手段,经过失败经验的证明,数据库设计的冗余越少,精简度越高,在数据查找时的 速度就会越慢,代码的复杂度就会越高。

下 面以常见的武将系统为例说明如何通过冗余设计来提高系统性能。

首 先,我们来明确一下基本功能。武将系统中一定会存在三张有关系的表,一,是可选武将的列表,这个表是一张配置表;二,用户表;三,是用户所招募到的武将 表。比较精简表结构如下所示:

height=241

对 于关系表UserOwnedMilitaryOfficers来 讲,只需要存储对应的武将ID即可,如果想知道这个武将的详细信息,可以 通过关系进行想找,此种情况的EntityFramework查 询如下所示:

testModel.testEntities2 context = new testModel.testEntities2();

var myuid=“warensoft”;

var myMilitaryOfficers = context.UserOwnedMilitaryOfficers.

Where(mo => mo.Users.uid == myuid).

Select(mo => new

{

Name=mo.MilitaryOfficers .Name ,

Life=mo.MilitaryOfficers .Life ,

Exp=mo.MilitaryOfficers .Exp

});

//do something else…

不 难发现,上面代码中的查询是由两个函数组成的,首先要根据用户的ID找 到所有该用户所拥有的武将ID(使用Where函 数),然后,根据所找到的武将ID, 再反过来到武将表中找到对应的名字(Select函 数),生命以及初始经验。特点:两个函数查询,访问了两张表。

如 果我们在UserOwnedMilitaryOfficers表 中添加一些冗余数据的话,虽然存储量会增加,但是控制难度会大大下降,对该表进行修改,如下所示:

height=303

修 改后的关系表,是将一些冗余数据加了进来,对于这样的关系结构来讲,查询语句如下所示:

testModel.testEntities2 context = new testModel.testEntities2();

var myuid=“warensoft”;

var myMilitaryOfficers = context.UserOwnedMilitaryOfficers.

Where(mo => mo.Users.uid == myuid).

Select(mo => new

{

Name=mo .Name ,

Life=mo .Life ,

Exp=mo .Exp

});

//do something else…

对 于新版本的查询代码来讲,首先,从关系表中找到该用户所拥有的武将,这一点是不变的,但是在执行Select函 数的时候确不用再通过关系查找武将到,而直接对已经选出的数据进行组织,取出想到的字段而已。特点:两个函 数,一次查询。这种修改仅仅是添加了一些冗余,但是查询次数却减少了50%

5. 什么时候使用存储过程

存 储过程的使用是需要仔细考虑的,我们不应该走极端(要么所有数据访问逻辑都使用存储过程,要么所有数据访问逻辑都不使用存储过程),原则上来讲,是否使用 存储过程,取决于这个功能的调用密集程度和数据访问的密集程度。

如 果某一个功能的非数据访问逻辑很多又会被很频繁地调用,将这个功能写成存储过程的话,会导致SQL Server占用较多的资源,这 样作并没有真正的利用好SQL Server, 同时还会影响其他数据访问操作的执行。在遇到这种情况时,应该考虑使用EntityFrameworkADO.NET, 可以在应用程序中通过SQL语句对数据库进行外部调用。

如 果一个操作中,大部分的功能是访问各个表,并添加修改删除数据,其他的非数据访问逻辑很少,那么将这个功能写成存储过程,就是比较合理的,因为这样会大大 减少SQL语句在应用程序和数据库之间的传递次数。

6. 什么时候使用EntityFramework, 什么时候使用ADO.NET

首 先,要说明的是绝对不要对EntityFramework的 性能有所怀疑,经验证明,在大多数情况下EntityFramework的 性能都与ADO.NET不相上下。

使用EntityFramework的优点:

EntityFramework使 用类之间的关系进行导航,这样可以不去编写大量的级联SQL, 以操作类的形式代替了字符串形式的SQL操 作,我们的开发效率以及编码的正确率都会有大幅度的提高。

使用EntityFramework的缺点:

当 然使用EF也有不少问题,比如说,在指定的数据表中作 大量记录的相同修改,或者指删除,如果使用EF就 要先遍历一次所有的记录,然后再保存,最后SQL Server再 执行操作,数据里一大,数据的同步就存在问题。同时EF对 存储过程的调用也不方便。

使用ADO.NET的优点:

万 能的操作!没有什么数据库操作功能是ADO.NET作 不了的,而且操作起来更为灵活,速度也非常快。EF的 底层实现也大量的使用ADO.NET

使用ADO.NET的缺点:

显 而易见,使用ADO.NET,是要直接编写SQL语 句的,SQL语句是通过字符串体现的,没有智能感知,没 有语法检测,只有在运行时才能知道正确与否,这样的开发效率比较低。另外,ADO.NET是 较为底层的数据访问技术,在业务逻辑比较复杂的情况下,开发难度(事务控制,同步控制)比较高。

组合比例:

通 过已有经验,我们发现在60%的逻辑中使用EntityFramework, 另外20%的逻辑使用ADO.NET, 还有20%的逻辑是利用ADO.NET编 写的SQL CLR代码,这样的比例也许会比较合适(当然这 样的比例也要和具体的需要相匹配)。

今 天就写到这儿,如何大家需要技术支援,请给我发Email:warensoft@foxmail.com

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏