1.1数据库对象
对象 | 前缀 |
数据库 | 无 |
表 | 无 |
视图 | VI |
索引 | IX |
存储过程 | SP |
函数 | FN |
触发器 | TR |
自定义数据类型 | ud |
Default | DF |
主键 | pct. |
外键 | FK |
rule | ru |
序列 | Sq |
UNIQUE | uq |
数据库对象采用26个英文字母(区分大小写)和0-9这十个自然数,加上下划线_组成,共63个字符。不能出现其他字符(注释除外)。
同一个数据库中这些对象名都是不能重复
C CHECK_CONSTRAINT
D DEFAULT_CONSTRAINT
F FOREIGN_KEY_CONSTRAINT
IT INTERNAL_TABLE
P SQL_STORED_PROCEDURE
PK PRIMARY_KEY_CONSTRAINT
S SYSTEM_TABLE
SQ SERVICE_QUEUE
TR SQL_TRIGGER
U USER_TABLE
UQ UNIQUE_CONSTRAINT
V VIEW
1.2命名规范规定
1.表名使用单数名
例如:对用户信息的表(User)不使用Users
2.避免无谓的表格后缀
1、 表是用来存储数据信息的,表是行的集合。那么如果表名已经能够很好地说明其包含的数据信息,就不需要再添加体现上面两点的后缀了。
2、 GuestInfo(存储客户信息)应写成Guest,FlightList(存储航班信息的表)应写成Flight
3.所有表示时间的字段,统一以 Date 来作为结尾(而不是有的使用Date,有的使用Time)
以大家都熟悉的论坛来说,需要记录会员最后一次登录的时间,这时候一般人都会把这个字段命名为LoginTime 或者 LoginDate。这时候,已经产生了一个歧义;如果仅看表的字段名称,不去看表的内容,很容易将LoginTime理解成登录的次数,因为,Time还有一个很常用的意思,就是次数
4.所有表示数目的字段,都应该以Count作为结尾
5.所有代表链接的字段,均为Url结尾
6.所有名称的字符范围为:A-Z, a-z, 0-9 和_(下划线)。不允许使用其他字符作为名称。
7.采用英文单词或英文短语(包括缩写)作为名称,不能使用无意义的字符或汉语拼音。
8.名称应该清晰明了,能够准确表达事物的含义,最好可读,遵循“见名知意”的原则。
为避免无法达到“见名知意”的效果,表和字段的都需要添加备注(MS_Description)
9.为避免关键词冲突,所有字段使用f开头。例如 用户Id(fUserId)
1.3数据库命名规范
数据库名称不需要简写,根据实际意义来命名。例如:ReportServer
数据库名:ReportServer
逻辑数据名:ReportServer;逻辑日志名:ReportServer_log
物理数据名:ReportServer.mdf;物理日志名:ReportServer_log.LDF
CREATE DATABASE [ReportServer] ON PRIMARY
( NAME = N'ReportServer', FILENAME = N'D:\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\useData\ReportServer.mdf' , SIZE = 3328KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'ReportServer_log', FILENAME = N'D:\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\useData\ReportServer_log.LDF' , SIZE = 6400KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
注意:避免所有数据库的逻辑名称使用相同的名称。
1.4表设计命名规范
注意字段名不能使用保留关键字:如action,avg等
1、不使用tab或tbl作为表前缀(本来就是一个表,为什么还要说明)
2、表名以代表表内的内容的一个和多个名词组成,以下划线分隔,每个名词的第一个字母大写,例如:User、UserLogin,UserGroupRelation等
3、使用表的内容分类作为表名的前缀:如,与用户信息相关的表使用前缀User,与内容相关的信息使用前缀Content。
4、表的前缀以后,是表的具体内容的描述。如:用户登录信息的表名为:UserLogin,用户在论坛中的信息的表名为:UserBBSInfo
5、一些作为多对多连接的表,可以使用两个表的前缀作为表名:
如:用户登录表UserLogin,用户分组表GroupInfo,这两个表建立多对多关系的表名为:UserGroupRelation
1.4.1字段命名规范
1. 字段名不要存在无用前缀,例如表‘WeiXinConfig’,既然我已经知道这张表是关于微信的表,里面的名称字段可以使用Name,不需要添加无用的前缀类似‘WeiXinName’,‘WeiXinGuanZhuMsg’,‘WeiXinUpImgMsg’等
2. 字段使用实际英文翻译作为命名字段,见名知意,不要使用让人看了半天都不知道是啥意思的字段(类似:lev1,lev2…)
1.5存储过程命名
存储过程名=[SP_]+[表名]+[操作名字]
[操作名字]=[insert|delete|update|calculate|confirm]
例如:SP_community_update
1.5.1只允许应用程序通过存储过程访问数据库
只允许应用程序通过存储过程访问数据库,而不允许直接在代码中写SQL语句访问数据库。
在数据库开发项目中,大量使用存储过程有很多的好处,首先看微软提供信息:
使用 SQL Server 中的存储过程而不使用存储在客户计算机本地的 Transact-SQL 程序的优势有: 允许模块化程序设计: 只需创建过程一次并将其存储在数据库中,以后即可在程序中调用该过程任意次。存储过程可由在数据库编程方面有专长的人员创建,并可独立于程序源代码而单独修改。 允许更快执行: 如果某操作需要大量 Transact-SQL 代码或需重复执行,存储过程将比 Transact-SQL 批代码的执行要快。将在创建存储过程时对其进行分析和优化,并可在首次执行该过程后使用该过程的内存中版本。每次运行 Transact-SQL 语句时,都要从客户端重复发送,并且在 SQL Server 每次执行这些语句时,都要对其进行编译和优化。 减少网络流量: 一个需要数百行 Transact-SQL 代码的操作由一条执行过程代码的单独语句就可实现,而不需要在网络中发送数百行代码。 可作为安全机制使用: 即使对于没有直接执行存储过程中语句的权限的用户,也可授予他们执行该存储过程的权限。
|
除此以外,使用存储过程的好处还有:
1、 在逻辑上,存储过程将应用程序层和数据库物理结构分离开来。存储过程形成了一个应用程序和数据库之间的接口。这样的接口抽象了复杂的数据库结构,符合极限编程中“基于接口编程”的思想。
2、 将主要的业务逻辑封装在存储过程中,能够避免在应用程序层写大量的代码(在应用程序中通过字符串插入太长的SQL语句影响效率,而且维护困难)。有助于提高开发效率,并且直接在查询分析器中调试存储过程,能够更早的发现系统中的逻辑问题,从而提高代码的质量。
3、 在网站一类的应用系统中,SQL注入式漏洞一直是难以完全杜绝的漏洞。如果只通过存储过程来访问数据库,能够大大减少这类安全性问题。(因此,就算是简单的只有一句的SQL语句,也应该写成存储过程。)
4、 由于采用存储过程,应用程序的层面可以不关心具体的数据库结构,而只关心存储过程的接口调用。因此,在以下一些情况,存储过程的优势非常明显:
·需求变更,表的结构必须要改变。使用存储过程,只要参数不变,我们就只需要修改相应的存储过程,而不需要修改应用程序的代码。这样的设计将减小需求变更对项目的影响。
·为提高效率,使部分字段冗余:一些经常性访问的字段,我们可以在相关的表中进行冗余存储。这样既提高了效率,又通过存储过程屏蔽了冗余细节。
·为提高效率,使用冗余表(拆分表):一些大的表,为了提高查询效率,可能需要将记录分别保存到多个表中去。使用存储过程,有存储过程来决定从哪些拆分的表中获取或插入数据。这样提高了效率,又不必在应用程序层面关心具体的拆分规则。
5、 使用存储过程,便于在项目后期或者运行中集中优化系统性能。在项目开发过程中,由于各种原因,往往无法编写高效的代码,这个问题常常在项目后期或者在运行期体现出来。通过存储过程来封装对数据库的访问,可以在项目集成以后,通过试运行观察系统的运行效率,从而很容易找出系统的瓶颈,并能够通过优化存储过程的代码来提高系统的运行效率。这样的优化,比在运用程序中优化更有效,更容易。
同时,过多的使用存储过程,也存在以下一些疑虑:
问题一:存储过程编译后,将作为数据库的全局对象保存,太多的存储过程将占用大量的数据库服务器的内存。
问题二:在存储过程中实现大量的逻辑,将使大量的运算在数据库服务器上完成,而不是在应用服务器上完成。当访问量很大的时候,会大大消耗数据库服务器的CPU占用率。
在此还存在这个一个案例:有一个访问量巨大的网站,有多台WEB服务器构成一个负载均衡的服务器群集,但是只有一台中心的数据库服务器。当访问量持续增加的时候,接入更多的WEB服务器来满足高并发量的访问;但是数据库服务器却没办法一直增加。因此,就需要尽量在WEB服务器上完成业务逻辑,尽量避免消耗数据库服务器的资源。
对于这两个担心,我的想法是:
问题一的解决:存储过程是经过编译后的SQL语句,在内存中是二进制的代码,并不会消耗太多内存。并且,存储过程比起直接使用SQL语句来说,效率大大提高。换个角度来说,这是一个“以空间换时间”的方案,多消耗一点内存来换取效率的提高,是值得的。
问题二的解决:首先,在实现业务逻辑的问题上,在存储过程中实现比在应用程序中实现更容易;其次,从开发效率上,存储过程的开发比应用程序更简单(就完成相同逻辑而言)。在高访问量的系统中,应用服务器和数据库服务器的资源分配的问题,应该从成本的角度来开率:软件开发中的成本,人工支出的费用远远高于硬件支出的成本。我们可以很容易花钱购买更好的服务器,但是很难花钱让开发人员使程序有大幅度的提高。
使用存储过程来封装业务逻辑,首先节省的是大量的开发时间和调试时间,并能够大大提高代码的质量。因此,从成本来说,应该使用存储过程。
对于大访问量的情况,最简单的办法是投入更多的硬件成本:更快的硬盘,更大的内存和更多的CPU,还有更好的网卡…………等等。
其次,在应用程序的层面,可以大量的使用静态文件缓存的办法来减轻数据库的压力。如:不经常变化的信息,可以从数据库服务器中读取,保存为应用服务器上的XML静态文件等。
实在不行的话,应该在系统设计之初,考虑可能的访问量,将系统设计成分布式的。这样就能从根本上解决大访问量的问题。
1.5.2命名规范
1、存储过程的前缀和表名的前缀类似:把一系列表看成一个对象,字段为对象的属性,存储过程则为访问对象的方法。如:添加用户的存储过程取名为:User_AddUser
2、存储过程使用模块的前缀来命名。如,用户管理的存储过程使用前缀user_。
3、存储过程的前缀之后,是动词+名词形式的存储过程名(也可以是动词短语)。
1.5.3存储过程的参数命名
1、参数名采用匈牙利命名法,使用类型的前缀
2、每个存储过程都有:@errno int和@errmsg varchar(255)两个输出参数。应用程序中可以根据这两个参数得到存储过程执行的情况。(这两个参数使用默认值,可以忽略)
errno为整型的错误信息代码,执行成功返回0。Errno的值的具体含义通过errmsg参数说明,或者通过代码中的注释或文档。
Errmsg为错误信息的字符串描述,这个参数主要用于调试期作为说明,避免在应用程序中使用该值。同时,要注意英文版系统和中文版系统中,信息的语言选择对程序的影响。
1.5.4存储过程返回的记录集
1、存储过程的输出记录集:为程序的结构清晰,存储过程最好只返回一个记录集。但在某些为了提高性能的场合,还是可以输出多个记录集
2、记录集中,每个输出的字段最后都指定字段的别名,以面真实的字段名信息流失到客户端,从而加大黑客找到系统漏洞的可能。
1.5.5格式约定
1、 所有SQL关键字大写
2、 使用良好的变量命名规范
3、 保持良好的结构,包括空行、缩进和空格等。
4、 块状的语句,一定要写上BEGIN…END
5、 在每个存储过程的开头加上详细的注释:包括存储过程名称、参数说明、功能说明、返回数据集说明、以及作者和版权声明。
6、 每个存储过程内的代码前后必须加上SET NOCOUNT ON 和SET NOCOUNT OFF。
7、 存储过程格式的示例如下:
CREATE PROCEDURE SP_User_update
(
@Options VarChar(100),
@strUserName varchar(20),
@strPwd varchar(50),
@errno int = 0 OUTPUT,
@errmsg varchar(255)=NULL OUTPUT
)
AS
BEGIN
IF @Options='UP1'
BEGIN
SET NOCOUNT ON
/*以下是存储过程的代码*/
SET NOCOUNT OFF
END
IF @Options='UP2'
BEGIN
SET NOCOUNT ON
/*以下是存储过程的代码*/
SET NOCOUNT OFF
END
END
1.6视图命名
一个数据库中的视图名不能重复
视图名=VI(前缀)+[表名]..[表名]+[描述]
1.7主键命名
一个数据库中的主键名不能重复
主键名=PK_(前缀)+[表名]
例如:PK_Community
1.8外键命名
一个数据库中的外键名不能重复
外键名=FK_(前缀)+[主表名]+[从表名]+[字段名]
考虑这样一个关系,表Hotel,字段fId, fName, fCityId。表fCity,字段fId,fName。因为一个城市可能有好多家酒店,所以是一个一对多的关系,fCity是主表(1方),fHotel是从表(多方)。在fHotel表中,fCityId是做为外键使用。
在实现外键的时候我们可以这样写:
ALTER TABLE HotelInfo
ADD CONSTRAINT FK_Hotel_City_Cityid FOREIGN KEY (CityID) REFERENCES City(ID)
1.9触发器命名
1. 前缀(tr),描述了数据库对象的类型。
2. 基本部分,描述触发器所加的表。
3. 后缀(_I、_U、_D),显示了修改语句(Insert, Update及Delete)
触发器名=TR_(前缀)+[表名]+[ _I、_U、_D]+[字段\描述]
例如:TR _Communtiy_u_name(对表community的字段name进行更新)
1.10 default约束
使用格式如:DF_[表名]_[列名]
例如:DF _Community_Age
1.11 check约束
格式:CK_[表名]_[列名]
例如:CK_Community_Number
1.12 unique约束
格式:UQ_[表名]_[列名]
例如:UQ_Community_Name
1.13字段命名规范
1、字段不使用任何前缀(表名代表了一个名称空间,字段前面再加前缀显得罗嗦)
2、字典名也避免采用过于普遍过于简单的名称:例如,用户表中,用户名的字段为UserName比Name更好。
3、布尔型的字段,以一些助动词开头,更加直接生动:如,用户是否有留言HasMessage,用户是否通过检查IsChecked等。
4、字段名为英文短语、形容词+名词或助动词+动词时态的形式表示,大小写混合,遵循“见名知意”的原则。
1.14 SQL语句规范
1、不允许写SELECT * FROM ……,必须指明需要读取的具体字段。
2、不允许在应用程序代码中直接写SQL语句访问数据库。
3、避免在一行内写太长的SQL语句,在SQL关键字的地方将SQL语句分成多行会更加清晰。
如:SELECT fUserID,fUserName,fUserPwd FROM User_Login WHERE fAreaID=20
修改成:
SELECT fUserID,fUserName,fUserPwd
FROM User_Login
WHERE fAreaID=20
更加直观
4、在一些块形式的SQL语句中,就算只有一行代码,也要加上BEGIN…END块。
如:IF EXISTS(…)
SET @nVar = 100
应该写成:
IF EXISTS(…)
BEGIN
SET @nVar = 100
END
5、SQL批处理语句的空行和缩进与一般的结构化程序语言一致,应该保持良好的代码格式。
6、所有的SQL关键字大写
1.15游标使用约定
1、 若无必要,不要使用游标
2、 包含游标的存储过程,必须对性能进行认真测试。
1.16索引命名规范
对于数据库的维护建索引是很平常的事情,但是如果没有一个规范化的命名,我们对于一个表的诸多索引可能需要花上一段时间的了解。
1. 如果表中存在主键默认情况下,表的聚集性索引也就是主键列,主键的命名前面已经有提到过,索引名也跟主键名一样,(PK_表名)
2. 对于表上的非聚集索引,建议使用(IX_表名_字段简写),对于很多命名文章上提到的需要详细表达出具体的列,我个人觉得没有必要,首先非聚集索引经常涉及多列,很难罗列出所有列;还有影响美观
当你执行SELECT fNAME FROM SYS.COLUMNS 查询索引时,你根据NAME名很快就知道索引来自那张表,是否是非聚集索引,而不用根据OBJECTID列去跟对象表关联。
1.17函数命名规范
函数命名分两类:1.针对对象的函数,2.用作辅助功能操作的函数(不针对具体的数据库对象)
1. 第一类命名:FN_+[User]+_+[对象名] 例如:FN_User_Student(对于Student进行操作函数)
2. 第二类命名:FN_[具体函数解释] 例如:FN_Spit(对字段进行拆分函数)
----------------------------------------------------------
作者:纸飞机的青春
来源:博客园