sqlserver数据规范二: 数据库级代码规范

  • Post author:
  • Post category:其他


需求:翻译Pinal Dave pinal@sqlauthortiy.com大师的代码规范,借鉴并规范公司数据库开发。

1:  为sqlserver的数据库对象使用pascal 标准,表,视图 应该使用字母s结尾。

原因:表存的数据都是复数的原因,开发很多框架例如



entity framework

生成的表也带复数


例:

点击(

此处

)折叠或打开


  1. userdetails

  2. emails

2: 如果你的表设计项目很大,那么应该分组,分组方式加前缀。例:

点击(

此处

)折叠或打开


  1. page_userdetails

  2. page_emails

3: 使用下面的语法规则使得存储过程更加清晰易懂:

其中 action_type 为  get,delete,update,write,archive, insert ,,等等 例:

点击(

此处

)折叠或打开


  1. spapplicationname_getuserdetails

  2. spapplicationname_updateEmails

4: 触发器的命名规则:TR_XXX

点击(

此处

)折叠或打开


  1. TR_emails_logemailchanges

  2. TR_userdetails_updateusername

5:  索引命名规则:IX_XXX

点击(

此处

)折叠或打开


  1. ix_userdetails_userid

6: 主键命名规则 PK_XXX

点击(

此处

)折叠或打开


  1. PK_userdetails

  2. PK_emails

7:外键命名规则 FK__XXX

点击(

此处

)折叠或打开


  1. FK_userdetails_emails

8: 默认列命名规则 DF__XXX

点击(

此处

)折叠或打开


  1. DF_userdetails_username

9:使用第三方的数据库建模工具带来的规范格式

点击(

此处

)折叠或打开

  1. Q. What is Third Normal Form and what is its advantage?
  2. A. Third Normal Form (3NF) is most preferable normal form in RDBMS.
  3. Normalization is the process of designing a data model to efficiently store data in a database.
  4. The rules of 3NF are mentioned here
  5. Make a separate table for each set of related attributes, and give each table a primary key.
  6. If an attribute depends on only part of a multi-valued key, remove it to a separate table
  7. If attributes do not contribute to a description of the key, remove them to a separate table.
  8. Normalization is very close to concept of object oriented schema’s and it stores one data at
  9. only one place by removing all the redundant data. It also helps to draw the schema easier.
  10. Normalization comes at the cost of performance

10:避免 select *

点击(

此处

)折叠或打开



  1. select


    *


    from

    user_details

    ;



  2. select

    username

    ,


    password


    from

    userdetails

    ;

11: 避免使用临时表,因为由此产生过多的磁盘I/O,通常使用普通表CTE(common table exression)替代

但是要注意查询范围。要避免过多的子查询嵌套,替代方案为 WITH AS  语句。

Following Image of Execution Plan displays that the performance for both of them is same

with regard to each other in one batch. This MAY NOT be true when there is a complex query in issue.

For most of the time, it is will be same.

点击(

此处

)折叠或打开



  1. query1:Paging Method



    Using



    Derived



    Table



  2. USE AdventureWorks
  3. GO
  4. DECLARE

    @

    StartRow INT
  5. DECLARE

    @

    EndRow INT

  6. SET


    @

    StartRow

    =

    120

  7. SET


    @

    EndRow

    =

    140

  8. SELECT

    FirstName

    ,

    LastName

    ,

    EmailAddress

  9. FROM


    (


  10. SELECT

    PC

    .

    FirstName

    ,

    PC

    .

    LastName

    ,

    PC

    .

    EmailAddress

    ,

  11. ROW_NUMBER

    (


    )

    OVER

    (


  12. ORDER


    BY

    PC

    .

    FirstName

    ,

    PC

    .

    LastName

    ,

    PC

    .

    ContactID

    )


    AS

    RowNumber

  13. FROM

    Person

    .

    Contact PC

    )

    PersonContact

  14. WHERE

    RowNumber

    >


    @

    StartRow

  15. AND

    RowNumber

    <


    @

    EndRow

  16. ORDER


    BY

    FirstName

    ,

    LastName

    ,

    EmailAddress
  17. GO
  18. query2: Paging Method

    Using

    CTE
  19. USE AdventureWorks
  20. GO
  21. DECLARE

    @

    StartRow INT
  22. DECLARE

    @

    EndRow INT

  23. SET


    @

    StartRow

    =

    120

    ;


  24. SET


    @

    EndRow

    =

    140

    ;


  25. WITH

    PersonContact

    AS


  26. (


  27. SELECT

    PC

    .

    FirstName

    ,

    PC

    .

    LastName

    ,

    PC

    .

    EmailAddress

    ,

  28. ROW_NUMBER

    (


    )

    OVER

    (


  29. ORDER


    BY

    PC

    .

    FirstName

    ,

    PC

    .

    LastName

    ,

    PC

    .

    ContactID

    )


    AS

    RowNumber

  30. FROM

    Person

    .

    Contact PC

    )


  31. SELECT

    FirstName

    ,

    LastName

    ,

    EmailAddress

  32. FROM

    PersonContact

  33. WHERE

    RowNumber

    >


    @

    StartRow

  34. AND

    RowNumber

    <


    @

    EndRow

  35. ORDER


    BY

    FirstName

    ,

    LastName

    ,

    EmailAddress
  36. GO

12:使用缩进排版编写sql语句,突出关键字。

13:使用大写字母突出sql关键字

点击(

此处

)折叠或打开



  1. SELECT


    ,


    UPDATE


    ,


    INSERT


    ,


    WHERE


    ,

    INNER JOIN

    ,


    AND


    ,


    OR


    .


    .


    .

14:每个表必须有主键,没有主键列需使用identifiy 自动设定。

15:数据建模表关联设计

15:数据建模表关联设计

如果 一个表(table1) 和 另一个表(table2) 的 关联 ,那么关联字段应该遵循:

table2 —>table1id

16:默认值字段不能为空

17:在做update,delete等dml 的时候,最好是要加上 主键的where 条件,能避免失误。

18:写存储过程,尽量使用同一个库的表,这能减少网络消耗。

19:表之间数据拷贝,尽量少用loop 插入方式。使用select 插入方法

如: insert into ..select ..from

select into from where

20: 数据库对象命名不能有空格:

例子:[order details]

21: 切记不要使用保留字来命名数据库对象。这会导致一些无法预测的情况。

22:养成注释的习惯。不管是存储过程。触发器和sql,它不会降低你的性能

23:不要使用过长的like 字符查询 一个走了索引执行计划的sql 语句

24: select * 和select 1 判定子查询性能对比:

测试结果,其实区别不大,推荐select 1

点击(

此处

)折叠或打开


  1. DBCC DROPCLEANBUFFERS

  2. DBCC FREEPROCCACHE
  3. use tpcc
  4. go

  5. SET

    STATISTICS TIME

    ON


  6. SET

    STATISTICS IO

    ON


  7. IF


    EXISTS


    (


  8. SELECT


    *


  9. FROM

    dbo

    .

    order_line

  10. WHERE

    ol_i_id

    =

    151078

    )


  11. SELECT


    ‘SELECT *’

  12. GO
  13. DBCC DROPCLEANBUFFERS
  14. DBCC FREEPROCCACHE

  15. SET

    STATISTICS TIME

    ON


  16. SET

    STATISTICS IO

    ON

  17. USE tpcc
  18. GO

  19. IF


    EXISTS


    (


  20. SELECT

    1

  21. FROM

    dbo

    .

    order_line

  22. WHERE

    ol_i_id

    =

    151078

    )


  23. SELECT


    ‘SELECT 1’

  24. GO

25: 默认约束须在字段级定义,其他约束须在表级定义

比如:

字段级定义约束:

点击(

此处

)折叠或打开


  1. USE AdventureWorks2008

  2. GO

  3. CREATE


    TABLE

    Products

  4. (

  5. ProductID INT

    CONSTRAINT

    pk_products_pid

    PRIMARY


    KEY


    ,

  6. ProductName

    VARCHAR


    (

    25

    )


  7. )


    ;

  8. GO
  9. USE AdventureWorks2008
  10. GO

  11. CREATE


    TABLE

    ProductSales

  12. (

  13. SalesID INT

    CONSTRAINT

    pk_productSales_sid

    PRIMARY


    KEY


    ,

  14. ProductID INT

    CONSTRAINT

    fk_productSales_pid

    FOREIGN


    KEY


    REFERENCES

    Products

    (

    ProductID

    )


    ,

  15. SalesPerson

    VARCHAR


    (

    25

    )


  16. )


    ;

  17. GO

表级定义约束

点击(

此处

)折叠或打开



  1. CREATE


    TABLE

    Products


  2. (

  3. ProductID INT

    ,

  4. ProductName

    VARCHAR


    (

    25

    )


  5. CONSTRAINT

    pk_products_pid

    PRIMARY


    KEY


    (

    ProductID

    )


  6. )


    ;


  7. ALTER


    TABLE

    Products

  8. ADD


    CONSTRAINT

    pk_products_pid

    PRIMARY


    KEY


    (

    ProductID

    )

  9. go

  10. ALTER


    TABLE

    Products

  11. DROP


    CONSTRAINT

    pk_products_pid

    ;

  12. GO

  13. CREATE


    TABLE

    ProductSales

  14. (

  15. SalesID INT

    ,

  16. ProductID INT

    ,

  17. SalesPerson

    VARCHAR


    (

    25

    )


  18. CONSTRAINT

    pk_productSales_sid

    PRIMARY


    KEY


    (

    SalesID

    )


    ,


  19. CONSTRAINT

    fk_productSales_pid

    FOREIGN


    KEY


    (

    ProductID

    )


    REFERENCES

    Products

    (

    ProductID

    )


  20. )


    ;

  21. GO

26:  不要希望于数据库规范能替代约束。

27: 尽量不要使用recompile命令对存储过程重新编译。这样会降低性能

原因是Compile Blocking的问题

解释:

由于编译存储过程导致被锁定,在master.sys.sysprocesses视图中或sp_lock存储过程中观察到的等待资源字段中的内容是“COMPILE”,

或者使用SQL PROFILER 录制过程中出现大量的“SP:REComplie”事件。由于重新编译需要耗费CPU资源,所以,此种锁定是在一长串的被锁定连接中,

单一锁定者锁定时间不长,但整个链接各点都有一点耗时,所以在链接尾端的被锁定者需要等待较长时间。同时会出现CPU的使用率比较高。

当存储过程中使用了缓存数据表,而该缓存数据表还需要设置结构,如需要要设置主键或者利用缓存数据表开打开游标,则每次调用该存储过程进,

都会要求重新编译。或这个存储过程是当应用程序执行时,常常会被调用的热门存储过程,就会出现Compile Blocking的状况出现。

但存储过程第一次使用时,也会需要编译,所以不要一看到是在等待编译,就以为是COMPILE Blocking现象。

28:存储过程declare 必须开头,这样使得执行计划能重用

29: set 关键字在存储过程中的位置?

点击(

此处

)折叠或打开



  1. CREATE


    FUNCTION

    ExtractInteger

    (


    @

    String

    VARCHAR


    (

    2000

    )


    )


  2. RETURNS

    VARCHAR


    (

    1000

    )


  3. AS


  4. BEGIN

  5. DECLARE

    @


    Count

    INT
  6. DECLARE

    @

    IntNumbers

    VARCHAR


    (

    1000

    )


  7. SET


    @


    Count


    =

    0

  8. SET


    @

    IntNumbers

    =




  9. WHILE

    @


    Count


    <


    =

    LEN

    (


    @

    String

    )


  10. BEGIN


  11. IF

    SUBSTRING

    (


    @

    String

    ,


    @


    Count


    ,

    1

    )


    >


    =


    ‘0’


  12. AND

    SUBSTRING

    (


    @

    String

    ,


    @


    Count


    ,

    1

    )


    <


    =


    ‘9’


  13. BEGIN


  14. SET


    @

    IntNumbers

    =


    @

    IntNumbers

    +

    SUBSTRING

    (


    @

    String

    ,


    @


    Count


    ,

    1

    )


  15. END


  16. SET


    @


    Count


    =


    @


    Count


    +

    1

  17. END


  18. RETURN


    @

    IntNumbers

  19. END

  20. GO

30:begin…end 是存储过程的标志

点击(

此处

)折叠或打开



  1. CREATE

    PROCEDURE usp_SelectRecord


  2. AS


  3. BEGIN


  4. SELECT


    *


  5. FROM


    TABLE


  6. END

  7. GO

31:使用括号增强sql的可读性

点击(

此处

)折叠或打开



  1. if


    (


    (


    select

    1

    from

    tablename

    where

    1

    =

    2

    )


  2. isnull

    )

32: 注释规范   单行注释使用 —  程序块级别注释用 /* */

33: 尽可能少使用cross join

34: 不需要反馈结果的,那就别返回

点击(

此处

)折叠或打开


  1. 比如:


  2. if


    exists


    (


    select

    1

    from

    userdetails

    where

    userid

    =

    50

    )

  3. 比下面代码好:

  4. if


    exists


    (


    select


    count


    (

    userid

    )


    from

    userdetails

    where

    userid

    =

    50

    )

35: index seek 比 index scan,table scan 好: 原因

索引是一颗B树,

index seek是查找从B树的根节点开始,一级一级找到目标行。

index scan则是从左到右,把整个B树遍历一遍。

假设唯一的目标行位于索引树最右的叶节点上(假设是非聚集索引,树深度2,叶节点占用k页物理存储)。

index seek引起的IO是4,而index scan引起的IO是K,性能差别巨大。

seek:从B树根到叶节点的过程,

scan:当SEEK完成后,在叶节点执行范围或全部扫描(按查询的选择性会有不同)

36:  使用 nvarchar,varchar,varbinary 替代 ntext,text, image 数据类型。

37:不要使用二进制,图片数据类型存入数据库,替代的是 外部文件的链接存储到数据库。

38:避免使用动态sql,而应该使用静态sql,每次只需的时候,动态sql都需要重新生成执行计划?

39:尽可能减少null值 字段的使用,因为这很可能增加查询复杂度,lsnull和coales 函数对处理null值

有很大帮助。

40:unicode 字符类型会占用更多的空间,没必要的话尽量使用 不带n的字符类型

41:使用except,not exist 替代  left join 或 not in 能等到更好的性能

点击(

此处

)折叠或打开



  1. select

    empno

    ,

    empname

    from

    employeerecord


  2. where

    sarary

    >

    1000

    and

    salary

    not


    in


  3. (


    select

    salary

    from

    emplpyeerecord

  4. where

    salary

    >

    2000

    )


    ;

  5. 改成:

  6. select

    empno

    ,

    empname

    from

    employeerecord

    where

    salary

    >

    1000
  7. execpt

  8. select

    empno

    ,

    empname

    from

    employeerecord

    where

    salary

    >

    2000

  9. order


    by

    empname

    ;

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30182853/viewspace-2137680/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30182853/viewspace-2137680/