《SQL_Server开发通用规范.doc》由会员分享,可在线阅读,更多相关《SQL_Server开发通用规范.doc(25页珍藏版)》请在课桌文档上搜索。
1、1.1 目的规sql的编写格式,提高SQL语句的可读性,共享性和执行效率。1.2 使用范围 所有需要与数据库交互的应用系统。1.3 概述 大局部业务系统需要与数据库进展交互,与数据库交互的主要方式就是SQL语句,编写规的SQL语句不但利于阅读,而且被数据库重复使用的几率也较大,执行效率相对较高,编写的好的SQL与编写的差的SQL在执行性能上可能会差几倍甚至几千几万倍,因此养成好的SQL编写规对于提高工程质量及提高开发人员自身素质有着潜在的极大的影响。1.4 书写 SQL书写遵守如下规:u 在同一个工程中,为了最大限度实现SQL的共享,要求书写sql语句时大小写要一致,为了阅读方便和统一起见,所
2、有SQL语句全部小写如SQL谓词,字段名,表名等,常量除外,常量可以按需要书写。举例:下面两个一样的语句除常量外都要统一起来。1)select name from emp;2)select NAMEfrom emp where emp_no=QD001u SQL语句尽可能放在一行,假设SQL太长放在一行中影响阅读时可分多行,但要保持缩进一致,缩进可用TAB或者空格,但TAB数和空格数最好一致。u SQL语句中,各谓词之间以空格分割的,尽量保持空格数量一致,即假设用一个空格分割,则全部都用一个空格分割,便于数据库能够共享。u 能使用绑定变量的,尽量使用绑定变量,尤其是在前台程序中.u 对下面列出
3、的情况,慎重使用绑定变量:1) 列值倾斜严重,如:*一状态列大局部值是1,只有极少数值为2,这种情况不宜用绑定变量,而应该用常量,便于数据库使用柱状图统计信息。2) 日期时间列。总之:书写SQL的目标是假设sql的用途是一样的,则sql应该完全一致,包括空格,大小写。下面的语句由于写法不完全一样,数据库会理解为4条不同的语句从而导致重复编译,降低了性能。1) select name from emp where emp_no=1112) Select name From emp Where emp_no=1113) select Name from EMP where emp_no=1114)
4、 select name from emp where EMP_NO=111 下面的语句,由于语句规,可以只编译一次。1) select name from emp where emp_no=1112) select name from emp where emp_no=2223) select name from emp where emp_no=3334) select name from emp where emp_no=:b11.5 注释1.5.1 开头注释所有的过程、函数、触发器、包都应该在开头有注释,注释中要列出对象名称;完成功能简述;调用模块,调用时机;创立日期;作者信息;历次修
5、改日期;历次修改人;历次修改原因和其它作者认为重要的容,在每次修改的注释之间建一空行。举例如下:/*名称:PRO_WO_MULTI_REPAIR_JOB功能:屡次维修判定程序调用:自动统计月结前,后台调用 *时间:2009-02-20修改人:*修改时间:2009-03-08修改容:重写局部SQL优化性能修改人: *修改日期:2008-03-23修改容:增加判断条件*/1.5.2 块注释对于复杂的语句块,必须提供块注释,清晰描述该语句块的功能逻辑、数据构造以及算法;块注释应该和它们所描述的代码具有一样的缩进格式;块注释之首应该有一个空行,用于把块注释和代码分割开来;块注释构造如下所示:/*计算配
6、送能力系数:派工系数 a*b+c*d+e*fa:考评成绩,取*的考评成绩c:承当度度,根据当前遗留量和总效劳能力计算所得,c=当前遗留配送量/总配送能力 .*/1.5.3 行注释对于复杂的SQL语句,必须提供行注释,清晰描述该SQL语句功能以及目的;行注释构造如下所示:-计算动态能力得分,当负荷率超高时,可能出现负值,注意处理。添加注释时要注意:注释中包含 GO 命令时会生成一个错误消息。1.5.4 过程和函数1.5.5 命名规存储过程/函数的命名代码使用以下方式:存储过程名 = SP_ + 模块代码 + 存储过程代码函数名 = F_ + 模块代码 + 函数代码存储过程以表现其功能的简洁语言进
7、展命名,定义好后,放置于每一个Diagram的特定区域一般置于右边局部的上边。1.5.6 过程/函数头定义规包括过程/函数名称定义、参数定义、注释说明、变量定义四局部。u 参数定义所有的参数必须显示指出变量类型,对于返回参数,必须指出其方向;参数变量定义格式为:“a“+参数类型简写“_参数名称,其中a是单词argument(参数)的第一个字母,参数类型如下:文本型:s日期时间型:d数字型:n整形:i布尔型:b举例:as_name 标识文本型 ad_birthdate 表示日期时间型 an_age 表示数字型u 注释说明见前面描述。1.5.7 变量定义规(1).变量的命名除游标变量以外,所有的变
8、量命名采用此方式:变量名 = “v_ + 变量名称游标变量采用:变量名 = “cur + 变量名(第一个字母大写)。其中变量名称由代表变量确切含意的单词代码组合而成,每一个单词的首字母根据阅读的方便性决定是否需要大写。举例:变量名:v_EmpName游标名:curNetlist(2).变量类型定义变量的类型时,尽量采用显示定义的方式。对于仅用于Oracle系列的数据库应用,也可以引用表、游标的引用定义方式。尽量将变量的定义分开来,并进展格式化,以便程序代码的阅读。例如: v_UserName CHAR(10) v_SE* CHAR(1)1.5.8 变量注释原则上要求对于一般变量定义时必须加上注
9、释,如变量有特定的值围,则必须显示描述各确切值及其含意说明;1.5.9 过程/函数体定义规在过程/函数的定义中,最重要的是过程代码的严谨性和可读性,主要包括以下的考前须知:(1).如无特殊需要,SQL中涉及的所有容都要小写。(2).原则上要求所有的SQL语句必须在其前面加上注释,对于IF/CASE等流程控制语句,必须在语句前/后说明控制处理和可能的流程方向;(3).所有的赋值语句要求变量与运算符之间要有空格。如:v_Count := v_Count + 1,并保持适当的对齐;(4).尽量防止复杂SQL,尤其是关联多个大表的SQL,对于需要关联多个大表的SQL最好分解成小的SQL分步处理,防止出
10、现性能问题,对于复杂的语句块之间,要求中间参加空行;(5).所有可能的返回结果,必须在过程体中显示定义和说明,并在注释中说明。在其它的过程、代码中调用本过程/函数时,必须在其代码中处理所有的各种可能的返回结果;(6).锁定数据时,尽可能只锁定要操作的数据行,防止锁定整个表,限制使用local table等DDL语句,假设要对数据表、数据行加锁时,需要考虑由此导致的并发操作失败的处理;(7).所有的过程/函数代码在编写之前,必须要有设计原型及其说明;u 存储过程/函数错误定义(1).所有的DML语句必须考虑死锁、并发、主关键字不唯一等的出错异常处理,应该对所有可能出现的异常进展捕获、编码处理,并
11、注明异常的容注:异常捕获及处理请参见1.2;(2).异常处理有两种需要考虑的问题,一是事务的完整性;二是错误的出错日志及返回处理。所有异常的根据其类型和等级进展以下的处理:类型容处理系统级数据库级发出的底层的异常,如主关键字不唯一冲突等;返回定义错误代码为其它错误,完全回退事务,登录异常日志;应用级应用系统定义并发出的异常,如指定记录不存在;定义应用级错误代码,根据实际情况处理事务;u 使用原则(1).存储过程功能尽量保持独立、复用,但尽量防止嵌套调用,充分考虑其性能表达;(2).使用前台代码调用存储过程时,必须考虑返回传入参数的有效性、代码的处理及展示、事务完整性处理;(3).直接使用参数作
12、为变量处理,不要在存储过程中定义参数同样含义的变量使用,防止由于值的不同导致性能问题。1.6 触发器1.6.1 命名规:触发器不同类型的命名构造如下操作时机命名构造InsertAfterai_表名UpdateAfterau_表名DeleteAfterad_表名1.6.2 触发器编写规请参见存储过程/函数编写规。1.7 异常所有过程和函数处理必须考虑可能出现的错误,一是数据库或操作系统底层错误;二是由于业务逻辑造成的错误;三是无反响或超时;四是输入参数不在指定围。设计所有的过程时,必须考虑出错后的恢复。1.8 优化1.8.1 SQL语句原则l Where子句尽量防止使用函数;l 防止在ORDER
13、 BY子句中使用表达式;l 限制在GROUP BY子句中使用表达式;l 慎用游标;l 大小写规统一,变量绑定统一,防止重复编译;l 尽可能少的返回结果集行的数量l 防止使用select * 语句;l 减少结果集中的列的数量;l 视图嵌套使用不能超过3层;l 不要使用没有意义的列作为聚集索引列,例如,加1自增列;l 防止隐式类型转换,例如字符型一定要用,数字型一定不要使用;l 查询语句一定要有围的限定,防止全表扫描操作;l 合理对大表进展分区;l 慎用DISTINCT关键字;l 慎用UNION关键字,可以用OR替代;l 使用top 1替count(*)来判断是否存在记录;1.8.2 索引创立原则
14、l 同一索引中的组成列最好不要超过3列。l 把经常一起出现的字段组合在一起,组成组合索引,组合索引的字段顺序与主键一样,也需要把最常用的字段放在前面,把重复率低的字段放在前面。l 根据使用频率决定哪些字段需要建立索引,选择经常作为连接条件、筛选条件、聚合查询、排序的字段作为索引的候选字段。l 根据数据量决定哪些表需要增加索引,数据量小的可以只有主键。l 假设*列中有大量的值是空值,可以建立索引。l 要对值分布较宽的列建立索引。l 假设表主要用来查询,则可按需要建立索引,假设对表操作主要是UPDATE,则尽可能少建索引。l 不要对值较窄的列建立索引,如性别l 不要索引较小的表如表缺乏1000行l
15、 假设*列的值大局部是a,少数是别的值如b,c,d,且经常以该列的其它值(如b,c,d)为查询条件,则可以将值a设为空值,并在此列上创立索引。1.8.3 充分利用索引1.8.3.1 函数、表达式使用在where语句中,尽量防止在运算符左边对列进展函数或者表达式操作,容易引起全表扫描,要尽可能将操作移至运算符右边。1.8.3.2 IN/OR子句使用IN、OR、NOT IN Sql Server2005数据库可以分析出应该根据索引查找。属于2005版本的新特性。1.8.3.3 !=或操作符子句使用!=或操作符可以用INDE* SEEK查找的,可以正常使用。1.8.3.4 不要对索引字段进展运算例如
16、:SELECT ID FROM T WHERE NUM/2=100应改为:SELECT ID FROM T WHERE NUM=100*2SELECT ID FROM T WHERE NUM/2=NUM1如果NUM有索引应改为:SELECT ID FROM T WHERE NUM=NUM1*2如果NUM1有索引则不应该改。1.8.3.5 不要对索引字段进展格式转换日期字段的例子:WHERE CONVERT(VARCHAR(10), 日期字段,120)=2008-08-15应该改为WHERE日期字段=2008-08-15 AND 日期字段2008-08-16ISNULL转换的例子:WHERE I
17、SNULL(字段,)应改为:WHERE字段WHERE ISNULL(字段,)=不应修改WHERE ISNULL(字段,F) =T应改为: WHERE字段=TWHERE ISNULL(字段,F)T不应修改1.8.3.6 不要对索引字段使用函数WHERE LEFT(NAME, 3)=ABC 或者WHERE SUBSTRING(NAME,1, 3)=ABC应改为: WHERE NAME LIKE ABC%日期查询的例子:WHERE DATEDIFF(DAY, 日期,2005-11-30)=0应改为:WHERE 日期 =2005-11-30 AND 日期 0应改为:WHERE 日期 =0应改为:WHE
18、RE 日期 2005-12-01WHERE DATEDIFF(DAY, 日期,2005-11-30)=2005-12-01WHERE DATEDIFF(DAY, 日期,2005-11-30)=2005-11-301.8.3.7 不要对索引字段进展多字段连接例如:WHERE FAME+ .+LNAME=H.Y 应改为: WHERE FNAME=H AND LNAME=Y1.8.3.8 Like的使用对索引列防止使用like %*, 应该使用like *%。设计数据构造时就应该考虑这个问题,不要出现必须要采用like %*才能满足业务需要的情形。1.9 设计1.9.1 数据库逻辑设计的规化第1规:
19、没有重复的组或多值的列,这是数据库设计的最低要求。 第2规:每个非关键字段必须依赖于主关键字,不能依赖于一个组合式主关键字的*些组成局部。消除局部依赖,大局部情况下,数据库设计都应该到达第二式。第3规: 一个非关键字段不能依赖于另一个非关键字段。消除传递依赖,到达第三式应该是系统局部表的要求,除非一些特殊作用的表。1.9.2 合理的冗余完全按照规化设计的系统几乎是不可能的,除非系统特别的小,在规化设计后,有方案地参加冗余是必要的。冗余可以是冗余数据库、冗余表或者冗余字段,不同粒度的冗余可以起到不同的作用。冗余可以是为了编程方便而增加,也可以是为了性能的提高而增加。从性能角度来说,冗余数据库可以
20、分散数据库压力,冗余表可以分散数据量大的表的并发压力,也可以加快特殊查询的速度,冗余字段可以有效减少数据库表的连接,提高效率。1.9.3 主键的设计主键是必要的,SQL SERVER的主键同时是一个唯一索引,而且在实际应用中,我们往往选择最小的键组合作为主键,所以主键往往适合作为表的聚集索引。聚集索引对查询的影响是比拟大的,这个在下面索引的表达。在有多个键的表,主键的选择也比拟重要,一般选择总的长度小的键,小的键的比拟速度快,同时小的键可以使主键的B树构造的层次更少。主键的选择还要注意组合主键的字段次序,对于组合主键来说,不同的字段次序的主键的性能差异可能会很大,一般应该选择重复率低、单独或者
21、组合查询可能性大的字段放在前面。1.9.4 外键的设计外键是最高效的一致性维护方法,数据库的一致性要求,依次可以用外键、CHECK约束、规则约束、触发器、客户端程序,一般认为,离数据越近的方法效率越高。慎重使用级联删除和级联更新,级联删除和级联更新作为SQL SERVER 2000当年的新功能,在2005作了保存,应该有其可用之处。因为级联删除和级联更新有些突破了传统的关于外键的定义,功能有点太过强大,使用前必须确定自己已经把握好其功能围,否则,级联删除和级联更新可能让你的数据莫名其妙的被修改或者丧失。从性能看级联删除和级联更新是比其他方法更高效的方法。1.9.5 字段的设计字段是数据库最根本
22、的单位,其设计对性能的影响是很大的。需要注意如下:A、数据类型尽量用数字型,数字型的比拟比字符型的快很多。B、 数据类型尽量小,这里的尽量小是指在满足可以预见的未来需求的前提下的。C、 尽量不要允许NULL,除非必要,可以用NOT NULL+DEFAULT代替。D、少用TE*T和IMAGE,二进制字段的读写是比拟慢的,而且,读取的方法也不多,大局部情况下最好不用。E、 自增字段要慎用,不利于数据迁移。1.9.6 索引的设计A、根据数据量决定哪些表需要增加索引,数据量小的可以只有主键。B、根据使用频率决定哪些字段需要建立索引,选择经常作为连接条件、筛选条件、聚合查询、排序的字段作为索引的候选字段
23、。C、把经常一起出现的字段组合在一起,组成组合索引,组合索引的字段顺序与主键一样,也需要把最常用的字段放在前面,把重复率低的字段放在前面。D、一个经常插入更新的表不要加太多索引,因为索引影响插入和更新的速度。E、一个多用于查询的表可以适量增加索引,保证查询效率,例如报表系统。1.10 编码阶段1.10.1 尽可能少的围数据A、横向来看,不要写SELECT *的语句,而是选择你需要的字段。B、 纵向来看,合理写WHERE子句,不要写没有WHERE的SQL语句。C、 注意SELECT INTO后的WHERE子句,因为SELECT INTO把数据插入到临时表,这个过程会锁定一些系统表,如果这个WHE
24、RE子句返回的数据过多或者速度太慢,会造成系统表长期锁定,诸塞其他进程。D、对于聚合查询,可以用HAVING子句进一步限定返回的行。1.10.2 尽可能少的重复操作A、控制同一语句的屡次执行,特别是一些根底数据的屡次执行是很多程序员很少注意的。B、减少屡次的数据转换,也许需要数据转换是设计的问题,但是减少次数是程序员可以做到的。C、杜绝不必要的子查询和连接表,子查询在执行方案一般解释成外连接,多余的连接表带来额外的开销。D、合并对同一表同一条件的屡次UPDATE,比方UPDATE EMPLOYEE SET FNAME=H WHERE EMP_ID= FUPDATE EMPLOYEE SET L
25、NAME=Y WHERE EMP_ID= F这两个语句应该合并成以下一个语句 UPDATEEMPLOYEE SET FNAME=H,LNAME=YWHERE EMP_ID= FE、UPDATE操作不要拆成DELETE操作+INSERT操作的形式,虽然功能一样,但是性能差异是很大的。 F、不要写一些没有意义的查询,比方SELECT * FROM EMPLOYEE WHERE 1=21.10.3 注意事务和锁事务是数据库应用中和重要的工具,它有原子性、一致性、隔离性、持久性这四个属性,很多操作我们都需要利用事务来保证数据的正确性。在使用事务中我们需要做到尽量防止死锁、尽量减少阻塞。具体以下方面需要
26、特别注意:A、事务操作过程要尽量小,能拆分的事务要拆分开来。B、 事务操作过程不应该有交互,因为交互等待的时候,事务并未完毕,可能锁定了很多资源。C、 事务操作过程要按同一顺序访问对象。D、提高事务中每个语句的效率,利用索引和其他方法提高每个语句的效率可以有效地减少整个事务的执行时间。E、 尽量不要指定锁类型和索引,SQL SERVER允许我们自己指定语句使用的锁类型和索引,但是一般情况下,SQL SERVER优化器选择的锁类型和索引是在当前数据量和查询条件下是最优的,我们指定的可能只是在目前情况下更有,但是数据量和数据分布在将来是会变化的。F、 查询时可以用较低的隔离级别,特别是报表查询的时
27、候,可以选择最低的隔离级别未提交读。1.10.4 注意临时表和表变量的用法在复杂系统中,临时表和表变量很难防止,关于临时表和表变量的用法,需要注意:A、如果语句很复杂,连接太多,可以考虑用临时表和表变量分步完成。B、 如果需要屡次用到一个大表的同一局部数据,考虑用临时表和表变量暂存这局部数据。C、 如果需要综合多个表的数据,形成一个结果,可以考虑用临时表和表变量分步汇总这多个表的数据。D、其他情况下,应该控制临时表和表变量的使用。E、 关于临时表和表变量的选择,很多说法是表变量在存,速度快,应该首选表变量,但是在实际使用中发现,这个选择主要考虑需要放在临时表的数据量,在数据量较多的情况下,临时
28、表的速度反而更快。F、 关于临时表产生使用SELECT INTO和CREATE TABLE + INSERT INTO的选择,我们做过测试,一般情况下,SELECT INTO会比CREATE TABLE + INSERT INTO的方法快很多,但是SELECT INTO会锁定TEMPDB的系统表SYSOBJECTS、SYSINDE*ES、SYSCOLUMNS,在多用户并发环境下,容易阻塞其他进程,所以我的建议是,在并发系统中,尽量使用CREATE TABLE + INSERT INTO,而大数据量的单个语句使用中,使用SELECT INTO。G、 注意排序规则,用CREATE TABLE建立的
29、临时表,如果不指定字段的排序规则,会选择TEMPDB的默认排序规则,而不是当前数据库的排序规则。如果当前数据库的排序规则和TEMPDB的排序规则不同,连接的时候就会出现排序规则的冲突错误。一般可以在CREATE TABLE建立临时表时指定字段的排序规则为DATABASE_DEFAULT来防止上述问题。1.10.5 注意子查询的用法子查询是一个 SELECT 查询,它嵌套在 SELECT、INSERT、UPDATE、DELETE 语句或其它子查询中。任何允许使用表达式的地方都可以使用子查询。子查询可以使我们的编程灵活多样,可以用来实现一些特殊的功能。但是在性能上,往往一个不适宜的子查询用法会形成
30、一个性能瓶颈。如果子查询的条件中使用了其外层的表的字段,这种子查询就叫作相关子查询。相关子查询可以用IN、NOT IN、E*ISTS、NOT E*ISTS引入。关于相关子查询,应该注意:A、NOT IN、NOT E*ISTS的相关子查询可以改用LEFT JOIN代替写法。比方: SELECT PUB_NAMEFROM PUBLISHERSWHERE PUB_ID NOT IN (SELECT PUB_ID FROM TITLES WHERE TYPE = BUSINESS) 可以改写成:SELECT A.PUB_NAMEFROM PUBLISHERS A LEFT JOIN TITLES BO
31、N B.TYPE = BUSINESS AND.PUB_ID=B. PUB_IDRE B.PUB_ID IS NULLSELECT TITLEROM TITLESHERE NOT E*ISTS (SELECT TITLE_ID FROM SALES WHERE TITLE_ID = TITLES.TITLE_ID)可以改写成: SELECT TITLEOM TITLES LEFT JOIN SALESN SALES.TITLE_ID = TITLES.TITLE_IDWHERE SALES.TITLE_ID IS NULLB、 如果保证子查询没有重复 ,IN、E*ISTS的相关子查询可以用IN
32、NER JOIN 代替。比方: SELECT PUB_NAMEOM PUBLISHERSWHERE PUB_ID IN (SELECT PUB_ID FROM TITLES WHERE TYPE = BUSINESS)可以改写成: SELECT DISTINCT A.PUB_NAMEFROM PUBLISHERS A INNER JOIN TITLES BON B.TYPE = BUSINESS ANDA.PUB_ID=B. PUB_IDC、不要用COUNT(*)的子查询判断是否存在记录,最好用LEFT JOIN或者E*ISTS,比方有人写这样的语句: SELECT JOB_DESC FROM
33、 JOBSWHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)=0应该改成: SELECT JOBS.JOB_DESC FROM JOBS LEFT JOIN EMPLOYEE ON EMPLOYEE.JOB_ID=JOBS.JOB_IDWHERE EMPLOYEE.EMP_ID IS NULLSELECT JOB_DESC FROM JOBSWHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)0应该改成: SELECT JOB_DESC FROM J
34、OBSWHERE E*ISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)1.10.6 注意连接条件的用法多表连接的连接条件对索引的选择有着重要的意义,所以我们在写连接条件的时候需要特别的注意。A、多表连接的时候,连接条件必须写全,宁可重复,不要缺漏。B、 连接条件尽量使用聚集索引C、 注意ON局部条件和WHERE局部条件的区别1.10.7 查看执行方案及本钱养成良好的编码习惯,每写完一个sql语句,就查看执行方案及本钱分析。在大表上尽可能防止全表扫描及聚集索引扫描。1.11 索引的使用及维护在良好的数据库设计根底上,能有效地使用索引是S
35、QL Server取得高性能的根底,SQL Server采用基于代价的优化模型,它对每一个提交的有关表的查询,决定是否使用索引或用哪一个索引。因为查询执行的大局部开销是磁盘I/O,使用索引提高性能的一个主要目标是防止全表扫描,因为全表扫描需要从磁盘上读表的每一个数据页,如果有索引指向数据值,则查询只需读几次磁盘就可以了。所以如果建立了合理的索引,优化器就能利用索引加速数据的查询过程。但是,索引并不总是提高系统的性能,在增、删、改操作中索引的存在会增加一定的工作量,因此,在适当的地方增加适当的索引并从不合理的地方删除次优的索引,将有助于优化那些性能较差的SQL Server应用。1.11.1 聚
36、簇索引(clustered inde*es)的使用聚簇索引是一种对磁盘上实际数据重新组织以按指定的一个或多个列的值排序。由于聚簇索引的索引页面指针指向数据页面,所以使用聚簇索引查找数据几乎总是比使用非聚簇索引快。每表只能建一个聚簇索引,并且建聚簇索引需要至少相当该表120%的附加空间,以存放该表的副本和索引中间页。建立聚簇索引的思想是: 1、大多数表都应该有聚簇索引或使用分区来降低对表尾页的竞争,在一个高事务的环境中,对最后一页的封锁严重影响系统的吞吐量。 2、在聚簇索引下,数据在物理上按顺序排在数据页上,重复值也排在一起,因而在那些包含围检查(between、=)或使用group by或or
37、der by的查询时,一旦找到具有围中第一个键值的行,具有后续索引值的行保证物理上毗连在一起而不必进一步搜索,防止了大围扫描,可以大大提高查询速度。 3、在一个频繁发生插入操作的表上建立聚簇索引时,不要建在具有单调上升值的列(如IDENTITY)上,否则会经常引起封锁冲突。 4、在聚簇索引中不要包含经常修改的列,因为码值修改后,数据行必须移动到新的位置。 5、选择聚簇索引应基于where子句和连接操作的类型。 聚簇索引的侯选列是: 1、主键列,该列在where子句中使用并且插入是随机的。 2、按围存取的列,如pri_order 100 and pri_order 200。 3、在group b
38、y或order by中使用的列。 4、不经常修改的列。 5、在连接操作中使用的列1.11.2 非聚簇索引(nonclustered inde*es)的使用SQL Server缺省情况下建立的索引是非聚簇索引,由于非聚簇索引不重新组织表中的数据,而是对每一行存储索引列值并用一个指针指向数据所在的页面。换句话说非聚簇索引具有在索引构造和数据本身之间的一个额外级。一个表如果没有聚簇索引时,可有250个非聚簇索引。每个非聚簇索引提供访问数据的不同排序顺序。在建立非聚簇索引时,要权衡索引对查询速度的加快与降低修改速度之间的利弊。另外,还要考虑这些问题: 1、索引需要使用多少空间。 2、适宜的列是否稳定。
39、 3、索引键是如何选择的,扫描效果是否更佳。 4、是否有许多重复值。 对更新频繁的表来说,表上的非聚簇索引比聚簇索引和根本没有索引需要更多的额外开销。对移到新页的每一行而言,指向该数据的每个非聚簇索引的页级行也必须更新,有时可能还需要索引页的分理。从一个页面删除数据的进程也会有类似的开销,另外,删除进程还必须把数据移到页面上部,以保证数据的连续性。所以,建立非聚簇索引要非常慎重。非聚簇索引常被用在以下情况: 1、*列常用于集合函数(如Sum,.)。 2、*列常用于join,order by,group by。 3、查寻出的数据不超过表中数据量的20%。1.11.3 覆盖索引(covering
40、inde*es)的使用覆盖索引是指那些索引项中包含查寻所需要的全部信息的非聚簇索引,这种索引之所以比拟快也正是因为索引页中包含了查寻所必须的数据,不需去访问数据页。如果非聚簇索引中包含结果数据,则它的查询速度将快于聚簇索引。 但是由于覆盖索引的索引项比拟多,要占用比拟大的空间。而且update操作会引起索引值改变。所以如果潜在的覆盖查询并不常用或不太关键,则覆盖索引的增加反而会降低性能。1.11.4 索引的选择技术索引的有无,建立方式的不同将会导致不同的查询效果,选择什么样的索引基于用户对数据的查询条件,这些条件表达于where从句和join表达式中。一般来说建立索引的思路是: (1)、主键时
41、常作为where子句的条件,应在表的主键列上建立聚簇索引,尤其当经常用它作为连接的时候。 (2)、有大量重复值且经常有围查询和排序、分组发生的列,或者非常频繁地被访问的列,可考虑建立聚簇索引。 (3)、经常同时存取多列,且每列都含有重复值可考虑建立复合索引来覆盖一个或一组查询,并把查询引用最频繁的列作为前导列,如果可能尽量使关键查询形成覆盖查询。 (4)、如果知道索引键的所有值都是唯一的,则确保把索引定义成唯一索引。 (5)、在一个经常做插入操作的表上建索引时,使用fillfactor(填充因子)来减少页分裂,同时提高并发度降低死锁的发生。如果在只读表上建索引,则可以把fillfactor置为
42、100。 (6)、在选择索引键时,设法选择那些采用小数据类型的列作为键以使每个索引页能够容纳尽可能多的索引键和指针,通过这种方式,可使一个查询必须遍历的索引页面降到最小。此外,尽可能地使用整数为键值,因为它能够提供比任何数据类型都快的访问速度。1.11.5 索引的维护*些不适宜的索引影响到SQL Server的性能,随着应用系统的运行,数据不断地发生变化,当数据变化到达*一个程度时将会影响到索引的使用。这时需要用户自己来维护索引。索引的维护包括: 1、重建索引 随着数据行的插入、删除和数据页的分裂,有些索引页可能只包含几页数据,另外应用在执行大块I/O的时候,重建非聚簇索引可以降低分片,维护大
43、块I/O的效率。重建索引实际上是重新组织B-树空间。在下面情况下需要重建索引: (1)、数据和使用模式大幅度变化。 (2)、排序的顺序发生改变。 (3)、要进展大量插入操作或已经完成。 (4)、使用大块I/O的查询的磁盘读次数比预料的要多。 (5)、由于大量数据修改,使得数据页和索引页没有充分使用而导致空间的使用超出估算。 (6)、dbcc检查出索引有问题。 当重建聚簇索引时,这表的所有非聚簇索引将被重建。 2、索引统计信息的更新 当在一个包含数据的表上创立索引的时候,SQL Server会创立分布数据页来存放有关索引的两种统计信息:分布表和密度表。优化器利用这个页来判断该索引对*个特定查询是否有用。但这个统计信息并不动态地重新计算。这意味着,当表的数据改变之后,统计信息有可能是过时的,从而影响优化器追求最有工作的目标。因此,在下面情况下应该运行update statistics命令: (1)、数据行的插入和删除修改了数据的分布。 (2)、对用truncate table删除数据的表上增加数据行。 (3)、修改索引列的值。
链接地址:https://www.desk33.com/p-21538.html