数据库的一些优化
在很多系统和网站中,数据库是不得不涉及的。一般使用的比较多的数据库包括SQLServer,Access,MySQL,Orleace等,但是一般相对国内使用比较多的还是SqlServer。因为他和Windows这一系列的操作系统能够更好的融合起来。网上有很多程序和数据性能相比较的例子。说得最多的就是Java+unix和NET+Windows server。闲话说多了。数据在几乎大多数的系统来说都是重中之重。可以说它是系统的核心。数据本身就是一个系统的重点。
首先我们从数据分析说起吧。很多时候,数据库分析的程序决定了你的系统以后的发展的方向。很多时候系统功能的扩展都会受到数据本身的局限性。
例如:我原来有这样一张表:
Students
{
[s_Id] identity(1,1),
[s_Name] varchar(20),
[s_Sex] bit
}
突然校长说:我需要统计下现在普遍来上学的学生的年龄。我们好针对的进行宣传。难道这个时候,你要对校长说:对不起,这个功能以前的系统里面没有。如果要加上这个功能只有重新开发系统。等你的系统猴年马月出来的时候,却发现,校长都已经换了。你的系统还有什么用。在这个时候,可能就会涉及系统的升级,而不是重新的开发。但是因为你的系统的局限性。没有相对应的字段来存储。必然的,就会要求你添加数据库字段,同时修改你的前台....。
例2:校长说:我需要把一个学生退学。说什么也没有用,你只有新增数据字段。结果,过了两天,校长说:那个学生家长给我送了大礼,我觉得我们还是要把那个学生收下来。!@#¥%……&*。你是不是又增加字段。当然,这这个时候你可以使用一个States来表示这个学生的状态。但是我想说的是,我现在说得只是一个简单的东西。如果是一个复杂的呢?那你用一个States能可以了。所以,可扩展性是一个必须考虑的东西。如果你少考虑了,现在也许没有用,但是当你的系统需要进行扩展的时候,会让你前台后台,反攻很多地方的。
还有就是一些字段的表示。例如说:学生退学这个状态,我在数据库里面使用IsQuitschool来进行表示,如果他正在离校你再使用IsExeat来进行表示,那你数据库里面的垃圾数据实在不敢恭维。所以,这个时候需要结合业务逻辑思维,进行分析。从而减少垃圾数据。就好像上面的学生状态,因为一个学生,一个时期只能有一个状态。那我们为什么不使用一个states来表示.0表示正常上学,1表示离校 2表示退学即使说新增加了一个状态。例如:休学。我们也能在不修改任何数据库结构的情况下,扩展了相对需要的功能。我以前预见过这个一个东西。票务系统,他涉及这么几个操作:订票=>审核订票=>发票=>送票可是等开发完成以后,那边委托方却说,因为可能涉及到送票客户接受这样的环节,这个样子是不行的。结果我们只是在后台的选择状态中新增加一个 【客户确定】 这样的一项就解决了。如果我们不是使用的一个字段来表示,那我们可能修改的不知道要有多少了。
校长今天看了一北大的网站,说道:我们也需要有外文的网站。!@#¥%……&*,没的说的,开发吧。难道为了外语这个功能,你会新建和原来的表结构相同的。那你实在是太有闲心了。这个时候我们完全可以在里面加上【Languages】这样的一个字段。然后把以前的全部加上Chaninese英文的就加上【English】即使你们校长更加洋气需要法语的,你只需要在选择语种的下拉中加上France就解决问题了。
关于数据库的范式:
1 第一范式(1NF)无重复的列
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。
说明:在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。
1.2 第二范式(2NF)属性完全依赖于主键[消除部分子函数依赖]
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。例如员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主码。
第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式就是属性完全依赖于主键。
1.3 第三范式(3NF)属性不依赖于其它非主属性[消除传递依赖]
满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。简而言之,第三范式就是属性不依赖于其它非主属性。
但是如果你真正的安装这个样子来,那么你的系统的效率应该会让人不敢恭维。在真正的数据库分析中,这些范式是被一个一个剔除的东西。因为 【子查询】,【连接查询】是相当耗费资源的。但是当你考虑到了这个问题,修改数据又是相当耗费资源的。例如:
Role 角色表
{
id int identity(1,1),角色ID
[Name] varchar(20), 角色名称
[ParentID] int, 角色父ID
[states] int 角色状态
}
Operate 操作功能
{
id int identity(1,1),功能id
[Name] varchar(20), 功能名称
[function] varchar(20), 对应的方法
[Parentid] int 父id号
}
因为角色要和操作的功能相进行对应,而且他们的功能是多对多的关系。于是就有了第三张表
RoleAndOperate
{
id int identity(1,1),
Role_id int,
Operate_id int,
}
当需要查询功能的时候,就进行连接查询。当数据量庞大的时候。你的计算机肯定直接就面临崩溃。链接查询所考费的资源不是我们所能想象的。这个时候我们就应该。
Role 角色表
{
id int identity(1,1),角色ID
[Name] varchar(20), 角色名称
[ParentID] int, 角色父ID
[states] int 角色状态
}
Operate 操作功能
{
id int identity(1,1),功能id
[Name] varchar(20), 功能名称
[function] varchar(20), 对应的方法
[Parentid] int 父id号
roelIDs varchar(255),
}
这个样式查询的时候,只主要把RoleID传进来使用一个简单的like查询就可以了。耗费的资源相对链接查询少了。不过,当你进行更新的时候,资源却比前一个方案慢多了,他可能涉及的是批量的修改,而不是以前的单个的修改。
在方案1中,我们需要修改一个角色,我们只需要修改相对应的那个角色就可以了,但是在方案二中却是不行的,因为他把roleID加载了一起,需要进行多项的批量的修改。所以,如果修改的频率比查询的频率还要高,那肯定还是应该选择第一方案。
数据库字段长度的使用:
很多人害怕数据的例如想字符串长度以后不够用,直接使用varchar(8000)或者,varchar(max)。这个以后扩张肯定是比10或者255的长度少些,但是,你没有去计算过,录入数据,读出数据所耗费的内存也是相当庞大的。他会给你分配多大的空间给你。一般来说,255就是一个分界线。>255的时候,数据读取数据明显比<255慢多了。不要过多的使用8000 max,数据长度越少,耗费的内存越小。效率越高。同时有的时候考虑语言的支持。在varchar的时候,如果你使用的是汉语,最好还是使用nvarchar text使用ntext。因为他能够更好的支持汉语。