Sql规范一、数据库设计规范设计阶段可以说是系统性能的关键阶段1.1、数据库逻辑设计的规范化遵守数据的设计规范3NF 规定✧无重复的列要求表中的每一列只包含一个实例信息例如:员工信息表,不能将员工信息都放在一列中显示,也不能将其中的两列或多列在一列中显示;员工信息表的每一行只表示一个员工的信息,一个员工的信息在表中只出现一次。
✧表内的每一行都应该被唯一的标识(有唯一键)例如:员工信息表中加上了员工编号(UserId)列,因为每个员工的员工编号是唯一的,因此每个员工可以被唯一区分。
这个唯一属性列被称为主关键字或主键、主码。
✧表内不应该存储依赖于其他键的非键信息。
要求一个数据库表中不包含其他表中的非主键信息例如:一个部门信息表,其中每个部门有部门编号(DeptId)、部门名称、部门简介等信息。
那么在员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。
如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。
1.2、合理的冗余没有冗余的数据库设计可以做到。
但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据例如:商品的基本表,如下所示“金额”这个字段的存在,表明该表的设计不满足第三范式,因为“金额”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。
但是,增加“金额”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。
1.3、字段规范字段是数据库最基本的单位,其设计对性能的影响是很大的➢一行记录必须表内唯一,表必须有主键➢用尽量少的存储空间来存数一个字段的数据.数据类型尽量小,这里的尽量小是指在满足可以预见的未来需求的前提下。
例如能用int的就不用char或者varchar能用nvarchar(20)就不用nvarchar(500)➢字段必须定义合适的数据类型,以减少使用过程中的数据类型转换例如日期类型应用datetime 禁止用nvarchar➢尽量不要允许NULL,除非必要,可以用默认值代替➢尽量少用TEXT和IMAGE,二进制字段的读写是比较慢的➢枚举类型的字段,需要有comment 中文注释例如用户表中的用户状态用1、2、需要注释1:正常、2:禁止1.4、索引规范在设计阶段,可以根据功能和性能的需求进行初步的索引设计,这里需要根据预计的数据量和查询来设计索引。
➢根据数据量决定哪些表需要增加索引,数据量小的可以只有主键➢在合适的列上创建索引根据使用频率决定哪些字段需要建立索引,选择经常作为连接条件、筛选条件、聚合查询、排序的字段作为索引的候选字段。
优化器查找到WHERE子句或连接条件列上的索引,如果可用,可避免全表扫描➢使用窄索引对表编制大量索引会影响 INSERT、UPDATE、DELETE 和 MERGE 语句的性能,因为当表中的数据更改时,所有索引都须进行适当的调整。
例如如果某个列在几个索引中使用且您执行修改该列数据的UPDATE 语句,则必须更新包含该列的每个索引以及基础的基表(堆或聚集索引)中的该列。
总结A、避免对经常更新的表进行过多的索引,并且索引应保持较窄,就是说,列要尽可能少。
B、使用多个索引可以提高更新少而数据量大的查询的性能。
大量索引,可以提高不修改数据的查询(例如 SELECT 语句的性能)单表索引不能超过六个➢检查索引的数据类型索引列的数据类型也是很重要的。
例如在一个整数键值上的索引查询是非常快的,这是因为int数据类型的尺寸很小,而且算数操纵很容易二、程序书写规范2.1、大小写风格2.2 、注释规范注释总是加在程序的需要一个概括性说明或不易理解或易理解错的地方。
注释应语言简炼、易懂而又准确。
2.2.1、注释的书写规范可采用单行/多行注释。
(-- 或 /* */ 方式)2.2.2、源代码文件的注释✧在文件的头部必须标明程序名称,它所完成的主要功能。
✧文件的作者,及完成时间。
✧文件的状态:测试/未测试。
✧主要修改活动的修改人、时间、简单原因说明列表、版本号。
✧维护过程中需要修改程序时,应在被修改语句前面注明修改时间和原因说明。
例如:/**文件名:功能描述:状态:作者:完成时间:修改时间:修改:修改原因:**/2.2.3、语句注释✧应对不易理解的分支条件表达式加注释;✧不易理解的循环,应说明出口条件(有GOTO的程序还应说明入口条件);✧对重要的计算应说明其功能;✧过长的函数实现,应将其语句按实现的功能分段加以概括性说明;✧供别的文件或函数调用的函数,绝不应使用全局变量交换数据;✧每条SQL语句均应有注释说明2.2.4、常量和变量的注释注释说明放在常量和变量定义语句的后面2.3、缩进规则2.3.1、sql语句的缩进风格✧查询列表的书写风格一行有多列,超过80个字符时,基于列对齐原则,采用下行缩进SELECT col1,col2,....colm,coln,...✧WHERE 子句的书写规范①每个条件占一行②嵌套查询条件书写规范WHERE con1AND con2AND col3NOT IN(SELECT col3FROM t2WHERE......);✧SET/SELECT子句的书写规范每个表达式占一行select@sdate=convert(nvarchar(10),getdate()-1,120)+' 00:00:00', @edate=convert(nvarchar(10),getdate()-1,120)+' 23:59:59',@database='[jumipay_device_dx].[dbo]',@database1='[jumipay_base_dx].[dbo]',2.3.2、控制结构的缩进程序应以缩进形式展现程序的块结构和控制结构。
✧下列保留字的下一行缩进三格BEGIN、THEN、ELSE、ELSIF、LOOP✧下列保留字所在行前移三格END、ELSE、ELSIF、END IF、END LOOP2.4、例子/**文件名:ChageOrder功能描述:在订单支付失败时修改订单状态状态:已测试作者:XX完成时间:2016-10-28修改时间:修改:修改原因:**/create proc[dbo].[ChageOrder]ASDECLARE@sql nvarchar(4000)--执行语句set@sql='update [jmp_order]set o_state=-1-- dateadd(n,-30,getdate()) 获取当前时间减去30分钟的时间 where o_ctime < dateadd(n,-30,getdate())and o_state=0 '-- 修改订单生成日期小于当前时间(减去分钟)以及未支付的订单beginSET NOCOUNT ON;BEGIN tran ok--开始一个事务OKEXEC (@sql)if@@error<>0 --判断修改数据有没有出错begin--如果出错rollback tran-- 回滚事务到endelse--没有出错begincommit tran ok--提交事务endEND;GO三、sql 编程优化规则使用select的时候,避免使用*在解析的时候会将 *,依次转换为所有的列名。
如不需要查询所有的列名应明确列出所需要查询的列名✧COUNT(1) 、COUNT(*)、COUNT(col)A、Count(1)和Count(*) 实际的意思是:评估count()中的表达式是否为NULL,如果为NULL则不计数,而非NULL则会计数表上没有主键或者唯一索引,两者都是全表扫描表上有主键或者唯一键索引,两者都是走主键或者唯一索引并没有区别B、Count(col)则是统计 col 列中不为空的总行数,如果没有索引则全表扫描✧Union 和Union ALLUnion:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;Union All:对两个结果集进行并集操作,包括重复行,不进行排序;✧尽量避免在where子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描例如:SELECT a_id,a_user_id,a_nameFROM jmp_appWHERE a_user_id is null可以在 a_user_id 上设置默认值0 ,确保表中a_user_id表没有用 null值然后可以这样查询SELECT a_id,a_user_id,a_nameFROM jmp_appWHERE a_user_id=0即:在where子句中使用is null 或 is not null的语句,引擎将放弃索引✧应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
✧避免使用or 做为索引条件,可以使用UNION代替例如:SELECT a_id,a_user_id,a_name,a_stateFROM jmp_appWHERE a_user_id=65 or a_name='益智乐园'可用下面语句替换SELECT a_id,a_user_id,a_name,a_stateFROM jmp_appWHERE a_user_id=65UNIONSELECT a_id,a_user_id,a_name,a_stateFROM jmp_appWHERE a_name='益智乐园'✧避免在索引列上使用计算和函数WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描例如:SELECT a_id,a_user_id,a_name,a_stateFROM jmp_appWHERE a_id*10>200可以这样写SELECT a_id,a_user_id,a_name,a_stateFROM jmp_appWHERE a_id>200/10即:任何对索引列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
✧In 与between andin会使系统无法使用索引,而只能直接搜索表中的数据如对于连续的数值可以用 between andSELECT a_id,a_user_id,a_name,a_stateFROM jmp_appWHERE a_user_id in(1,2,3,4,5,6,7,8,9,10)可换成SELECT a_id,a_user_id,a_name,a_stateFROM jmp_appWHERE a_user_id between 1 and 10✧In 与EXISTSEXISTS只返回TRUE和False,不返回列表的值。