T-SQL脚本规范

[TOC]

必须使用:

  1. 如无特殊情况,为提高系统并发性能,所有查询必须有WITH(NOLOCK)
  2. 涉及数据变更的事务,必须有异常捕获处理机制,并且要设置LOCK_TIMEOUT,避免长时间资源锁定;

    建议15毫秒:SET LOCK_TIMEOUT 15

  3. 变量 / 参数 / 多表关联字段类型,必须与数据表字段类型一致,避免类型转换而造成额外的CPU及扫描;
  4. 多表连接时,必须使用表的别名来引用列,即:表名.字段名;

    请使用表的别名并把别名前缀于每个Column上,以指明字段是属于哪个表,否则未来表结构变更后,有可能因Column歧义而引起语法错误;

  5. 时效性数据,必须包括<最近更新日期>字段;
  6. 数据表、数据字段必须加入中文注释;

    解读:N年后谁tm知道这个r1,r2,r3字段是干嘛的

禁止使用:

  1. 禁止在数据库做复杂运算,建议放到程序端处理,因为程序端扩容方便,数据库扩容能力有限;
  2. 禁止使用select *,只返回需要的列;

    a)读取不需要的列会增加CPU、IO、Memory、NET消耗;
    b)索引不能覆盖查询所需的列,就会造成键值查找或RID查找;
    c)表结构变化时容易引起查询出错;

  3. 禁止使用INSERT INTO tbl VALUES(xxx,yyy,zzz),必须显示指定字段清单;

    解读:容易在增加或者删除字段后出现程序BUG;

  4. 禁止全表更新/删除,即 UPDATE / DELETE 必须带 WHERE 或 ON;
  5. 禁止使用drop / truncate(特殊情况请与DBA确认);
  6. 禁止使用LinkedServers(效率过低) / 游标(性能不好) / 触发器(对应用不透明)

    解读:使用LinkedServer存在安全风险,也不便于追踪排障,而且网络拉取或推送的效率过低,数据量多了会有性能问题;
    游标遍历效率太低;
    触发器对应用不透明,效率也不高,增加迁移及维护风险;

  7. 禁止使用存储过程、计划任务;

    a)数据库(单台瓶颈)擅长存储与索引,涉及CPU计算请交给应用服务器(易扩展);
    b)调用关系复杂不利于表下线或迁移,也不利于排障;
    c)执行存储过程的时候,不便于备份数据;

  8. 禁止使用外键,一切外键概念必须在应用层解决;
  9. 禁止跨库查询,尽量不做跨表查询;
  10. 禁止大表使用JOIN查询,禁止大表使用子查询;

    解读:大表子查询会产生临时表,消耗较多内存与CPU,极大影响数据库性能,且一个列的标签同时在主查询和where子句中的查询中出现,那么很可能当主查询中的列值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,请在子查询中过滤掉尽可能多的行。

  11. 禁止JOIN个数超过5个

    a)过多的JOIN会导致查询分析器走错执行计划;
    b)过多JOIN在编译执行计划时消耗很大;

  12. 禁止IN子句中条件个数超过100个,单次查询返回过多数据会降低数据库的并发能力;
  13. 禁止在程序端大批量更新/删除数据,批量操作请与dba协商操作;
  14. 禁止大批量的查询数据结果,如果需要返回大量数据,请使用TOP或分页的方式;
  15. 禁止高并发业务(每秒访问超过5次)单次查询超过100条,比如select top(N)其中N必须<100;
  16. 禁止使用xml、text、image、blob、varchar(max)等大数据类型;

    a)存储大字段会浪费更多的磁盘和内存空间;
    b)非必要的大字段查询会淘汰掉热数据,导致内存命中率急剧降低,影响数据库性能;

  17. 禁止存放大文件或者照片;

    解读:为何要让数据库做它不擅长的事情?大文件和照片存储在文件系统,数据库里存URL多好;

  18. 禁止新加的表为NULL;

    a)允许NULL值,会增加应用程序的复杂性,必须得增加特定的逻辑代码,以防止出现各种意外的bug;
    b)在where子句中对字段进行isnull值判断(本无必要),将导致引擎放弃使用索引而进行全表扫描,可能会引起性能瓶颈;
    c)新加的表,所有字段禁止NULL,建议用0、特殊值或空串代替NULL值;
    d)旧表新加字段,先允许为NULL+默认值(避免全表更新,长期持锁导致阻塞),再分批更新值;
    e)三值(TRUE、FALSE、UNKNOWN)逻辑,所有等号(“=”)的查询都必须增加ISNULL的判断;

  19. 禁止在JOIN ON或WHERE语句中使用IS NULL 或 IS NOT NULL;
  20. 禁止使用属性隐式转换;

    解读:WHERE phone=13812345678 会导致全表扫描,而不能命中phone索引;

  21. 禁止在索引列上使用函数或计算;

    a)解读:WHERE CONVERT(VARCHAR(10),InsertTime,121) > '2017-02-15' 会导致全表扫描;
    b)假设在字段col1上建有一个索引,下列场景将可以使用到索引:
    col1 = 100
    col1 > 100
    col1 BETWEEN 0 AND 99
    col1 LIKE 'abc%'
    col1 IN (4,5,6)

  22. 禁止非SARG查询,以及%开头的模糊查询;

    a)非SARG查询:NOT、<>、NOT EXISTS、NOT IN、NOT LIKE和内部标量函数,会导致扫描;
    b)LIKE子句应尽量前端匹配,避免通配符在前端,因为%开头的模糊查询,会导致索引扫描;
    name like 'abc%' --index seek
    name like '%abc%' --index scan
    name like '%abc' --index scan

  23. 禁止把table或sp创建在master、tempdb等系统数据库下;
  24. 禁止在代码中使用HINT索引提示with(index=xxx)或with(forceseek);

    a)随着数据的变化查询语句指定的索引性能可能并不最佳;
    b)索引对应用应是透明的,如指定的索引被删除将会导致查询报错,不利于排障;
    c)新建的索引无法被应用立即使用,必须通过发布代码才能生效;

  25. 禁止使用ip直连数据库,建议使用内网域名;

    解读:不只是数据库,缓存(memcache、redis)的连接,服务(service)的连接都必须使用内网域名,机器迁移/平滑升级/运维管理…太多太多的好处。

建议使用:

  1. 建议避免使用IN或OR运算符;

    对于IN或OR运算符,通常会使用全表扫描,考虑分解成多个查询用UNION/UNION ALL来实现,这里要确认查询能走到索引并返回较少的结果集。

  2. 建议NOT EXISTS替代NOT IN;
  3. 建议UNION ALL替代UNION;

    因为UNION会对SQL结果集去重排序,增加CPU、内存等消耗;

  4. 建议关闭(默认开启)影响的行计数信息返回;

    在SQL语句中显示设置set nocount on,可取消影响的行计数信息返回,减少网络流量

  5. 建议定义游标时不要使用order by;
  6. 建议只读游标定义时不要指定FAST_FORWARD子句;
  7. 建议将长而复杂的SQL拆分成小段SQL运算;
  8. 建议不要使用holdlock子句;
  9. 建议使用count(1) 来代替count(*);
  10. 建议不要使用GUID做聚集索引,基于碎片考虑;
Copyright © www.sqlfans.cn 2023 All Right Reserved更新时间: 2022-01-14 17:30:09

results matching ""

    No results matching ""