1. 程式人生 > >(4.9)SQL Server 數據庫規範

(4.9)SQL Server 數據庫規範

null 定期 訪問表 phone nag 不能 服務器 沒有 空行

SQL Server 數據庫規範

一、 命名規範

常用對象命名規範,使用帕斯卡命名法(Pascal,單詞首字母大寫),統一使用英文。

1. 表。英文單數名詞,盡量寫完整單詞名稱一般不超過3個英文單詞都可表達出表的意思。使用帕斯卡命名法。

如:User,UserRole,Role,Group,Family,SalesOrderDetail

錯誤例子:Users,UserTable

註意:特殊意義的表

自定義的元數據表,使用前綴Sys開頭:SysDictionary,SysParameter,SysModel,SysRegion

業務同類表:WeChatCompany,WeChatUser,WeChatMember,SMSSend,SMSReceive

縮寫表,普遍認知的縮寫: US_User,EN_User,CN_User,WTO_Member,WTO_ Country

單詞過多的表:User_ ZGYH(中國銀行中文縮寫),User_ GSYH(工商銀行中文縮寫)

2. 字段。與表命名雷同。

對於主鍵字段,統一為:ID

外鍵引用的字段,統一為:外鍵表名+ID

如 UserID,UserRoleID,SalesOrderDetailID,SysDictionaryID

3. 視圖(不要使用)。

與表命名雷同。大寫“V_”作為前綴,格式:V_視圖名稱

如:V_User,V_SysDictionary

4. 存儲過程(業務處理不要使用,報表可用)。獲取或執行數據的過程。

要求動名詞組合。大寫“USP_”作為前綴,格式:USP_存儲過程名稱

如:P_GetUser,P_UpdateUserByUsername,P_CleanDeletedUser,P_GetMyRecord

5. 標量函數(查詢到表的不要使用)。返回單個值。

要求動名詞組合,大寫“FN_”作為前綴,格式:FN_函數名稱

如: FN_GetUserName,FN_GetUserNameByUserID

6. 表值函數(查詢到表的不要使用)。返回表。

要求動名詞組合,寫“TF_”作為前綴,格式:TF_函數名稱

如:TF_ SplitChar,TF_ SplitCharByComma,TF_GetUserByCity

7. 觸發器(不要使用)。

大寫“TR_”作為前綴,觸發操作為後綴,格式:TR_表/視圖名稱_Insert/Delete/Update

如:TR_User_Insert,TR_User_Update,TR_User_Delete

8. 索引。盡量寫完涉及的字段

大寫“IX_”作為前綴,格式:IX_表名稱_字段名稱_字段名稱_……

如:IX_User_ID,IX_User_UserName_Mobile

唯一索引: UIX_表名稱_字段名稱

包含列索引:IX_表名稱_字段名稱_Include

篩選索引:IX_表名稱_字段名稱_Where

9. 約束。

主鍵約束:PK_表名稱_字段名稱

外鍵約束:FK_表名稱_字段名_主表名稱_主表字段(禁用外鍵約束!)

唯一約束:UIX_表名稱_字段名稱(唯一約束默認是創建唯一索引來約束)

默認值約束:DF_表名稱_字段名稱

Check約束:CK_表名稱_字段名稱

10. 臨時對象。大小寫不要求,其他與表名稱規範相同。聲明使用會話級別。

臨時表:#user (不要使用 ##user)

(表)變量:@name (不要使用@@name)

二、 設計規範

對象級規範:

? 數據庫表設計必須滿足第三範式(特殊情況再討論)

? 業務表都設置自增主鍵ID!(主鍵不一定是聚集索引)

? 禁止使用外鍵約束!(操作數據慢;維護數據困難)

? 禁止使用觸發器!(程序中控制操作)

? 禁止使用視圖!(維護不便,多表關聯可能有字段沒用。報表可用)

? 禁止使用函數訪問表、視圖等數據(函數只作為輔助計算工具,不參與訪問數據!)

? 禁止使用存儲過程處理業務邏輯(先在程序計算好再去讀寫數據庫!)

? 禁止使用遊標!(少用遍歷,用集合概念來操作)

? 禁止使用臨時表!(業務操作頻繁會不可控)

? 禁止使用同義詞!(維護易被忽略)

? (報表可用存儲過程、視圖、臨時表,視圖中的結果集不要有排序)

? (若必要使用,視圖、存儲過程、函數、觸發器、遊標等不要多層調用2 次以上!)

? 不要使用數據庫關鍵字作為表名、字段名等(尤其系統對象名稱,如:getdate、sum 等)

? 創建約束、索引等,手動設置名稱,不用系統自動生成!

? 索引盡量不超過5個,尤其那些頻繁更改和插入的表!

? 表和字段在數據庫中須添加詳細註釋!(參考:sp_addextendedproperty)

? 視圖、存儲過程、函數、觸發器等,須填寫創建信息及每個操作的描述!

? 禁止在數據庫中存儲文件。

? 插入字符數據時,須去掉左右空格!

? 插入表時所有字段必須全部列出!(如: insert into tab(name,phone) select name, mobile from user)

? 存儲過程、函數等,模塊語句加上 BEGIN……END;去掉多余的空行和空格。

? 程序操作表的權限只允許select、insert、update、delete!

? 對於可能刪除的業務數據,數據庫不實際刪除數據,增加字段 IsDeleted 來判斷是否刪除!

? 操作日誌、系統日誌等表,只允許插入,不能再修改!

? 對約束較強的枚舉選項,程序應設置選項而不要用戶手動隨意填寫!

? 業務表都添加一個時間字段:addTime datetime not null constraint DF_表名稱_datetime default(getdate())

字段規範:

? 盡量設置使用 “not null”約束,數值默認0,字符默認為空’’。否則查詢時 null 是不參與比較的!

? 禁用 ntext、text 和 image,用nvarchar(max)、varchar(max)和 varbinary(max)替代,盡量不用max!

? 非英文重要數據使用unicode類型保存,如nvarchar ,nchar,其他可以varchar;

? 日期時間字段統一用 datetime,精確到毫秒;

? 金額、小數類型使用 decimal,不用int、float、double(int可存儲21億,float、double精度不準)

? 狀態字段統一用State(可枚舉的),不用status

? 不允許明文存儲密碼!

三、 查詢規範

u 定義的參數、變量類型要參考與字段類型和長度相同。

Declare @name varchar(50) --類型要與 User(Name)相同

Select * from User where Name = @name

u 少用遊標遍歷,用集合概念來處理數據。

u 操作使用 IN 內的常量不要過百,盡量少!應用其他方式改為表連接。

錯誤示例:select * from [User] whereName in(‘AA‘,‘BB‘,‘CC‘,‘DD‘,‘EE‘,‘FF‘,………)

u 若須用“IN”,嵌套子查詢不要超過3個。

Select * from User

where Name in(

select Name

from Manager

where Sex in(Select Sex from User where Name=‘kk‘)

)

u 子查詢“IN”都改為“innerjoin”方式,註意是否有一對多或多對多情況,有則先連接鍵分組再連接。

上面的 IN 查詢可改為如下:

Select distinct t1.*

from User t1

inner join Manager t2 on t1.Name=t2.Name

inner join User t3 on t2.Sex=t3.Sex

where t3.Name=‘kk‘

u 能用“EXISTS ”就不用“IN”,exists 可以避免可能的錯誤。

--表 TestRole 不存在字段 Mobile,但是查詢不會報錯!

select * from User where name in(select Mobile fromTestRole)

select * from User where name not in(select Mobile from TestRole)

改為:

select * from User a where exists(select 1 fromTestRole b where a.name=b.RoleName)

--表 TestRole 字段 RoleName 只要存在一個 Null ,查詢則沒有結果

select * from User where name not in(select RoleName from TestRole)

改為:

select * from User where name not in(select RoleName from TestRole whereRoleName is notnull)

select * from User a where not exists(select 1 from TestRole b wherea.name=b.name)

u 存儲過程中首行添加:set nocount on ,主要是將執行結果顯示的打印信息不返回客戶端,減少網絡IO。

CREATE PROC dbo.TestPro

AS

BEGIN

SET NOCOUNT ON --此處添加

…………

END

GO

u 存儲過程內不要打印(print)信息,理由同上。

u 查詢不用星號,哪怕字段再多也寫完整,並非所有字段都用的上的。且星號不能建立合適的索引。

u Where篩選中,不要在字段上使用函數,否則整表都掃描來進行函數處理。

Select * from User where left(Name) = ‘黃‘

改為:

Select * from User where Name like ‘黃%‘

Select * from User where convert(varchar(10),AddTime,120)=‘2018-01-01‘

改為:

Select * from User where AddTime>=‘2018-01-01‘ andAddTime<‘2018-01-02‘

u 模糊匹配like不用講 % 放在首位。(同上)

u 時間比較註意,不必手寫那麽詳細

Select * from User where addTime<=‘2017-12-31 23:59:59‘

改為:

Select * from User where addTime<‘2018-01-01‘

u 一致性不強或需要粗略統計的大表數據或報表,可以加上Nolock 允許臟讀。

Select * from User with(nolock)

Select * from User as U with(nolock)

u Count 是不統計null 的。計數使用 count(*),MSSQL中count(*) 默認走索引長度最小的來統計。

COUNT(*) = COUNT(1) = COUNT(‘A‘)

Select COUNT(*) from User --統計表總行數

Select COUNT(Mobile) from User --統計手機不為NULL的總行數

u SQL Server 中,默認 null 加上任何字符都為null,所以註意!

SELECT ‘A‘+NULL --結果為 NULL

SELECT 100+NULL --結果為 NULL

—正常寫法,如果字段有 NULL 值,使用 ISNULL 判斷更改。

Select Name + ISNULL(Mobile,‘‘) from User

註意:集合函數 sum、avg、max、min 是忽略 NULL 的。

u 除了數據需要大量導出,任何查詢一定要使用分頁查詢。

u 一個事務中不用頻繁重復讀取表數據或操作數據

u 查詢盡量參數化,即先聲明參數,後賦值,再把參數帶入執行腳本(如: where name = @name)

Select Name,Mobile from User where Name =‘AA‘

Select Name,Mobile from User where Name =‘BB‘

改為:

Declare @name varchar(50)

Set @name = ‘AA‘

Select Name,Mobile from User where Name =@name

go

Declare @name varchar(50)

Set @name = ‘BB‘

Select Name,Mobile from User where Name =@name

go

u 多表關聯情況且結果集在滿足情況下,盡量使用左連接(left join)而不使用內連接( inner join)

Select t1.Name

from User t1

inner join Manager t2 on t1.ManagerID=t2.ID

where t1.Mobile=‘13000000000‘

改為:

Select t1.Name

from User t1

left join Manager t2 on t1.ManagerID=t2.ID

where t1.Mobile=‘13000000000‘

因為 Mobile 唯一,第二種情況只查詢 User 表。所以當條件不確定的時候、且不影響結果,使用第二種。

u 按添加時間排序時,性能不好可以用主鍵聚集索引ID排序,因為ID也是遞增的。

Select top(10) Name,Mobile from User order by AddTime desc

改為:

Select top(10) Name,Mobile from User order by ID desc

u 多表連接查詢,使用簡短別名,字段都加上別名且別名要統一!

Select t1.Name from User t1 inner join Manager t2on t1.ManagerID=t2.ID

Select a.Name from User a inner join Manager b on a.ManagerID=b.ID

Select u.Name from User u inner join Manager m on u.ManagerID=m.ID

u 編寫腳本不要寫在一行上面,註意縮進,每行長度盡量不超過120個字符。

u 腳本中的系統關鍵字保持統一,可全部大寫或全部小寫或首字母大寫。

u 不在數據庫中使用鏈接服務器來跨服務器查詢,程序中應從一節點讀取數據後再傳遞到另一節點操作。

u 多表連接中,“on”後面若有 “or”,則改為 union 取連接:

Select a.name,b.name From User a Inner Join Manager b On a.ManagerID=b.ID or a.Mobile=b.Mobile

改為:

Select a.name,b.name From User a Inner Join Manager b On a.ManagerID=b.ID

Union

Select a.name,b.name From User a Inner Join Manager b On a.Mobile=b.Mobile

u 不要在生產庫查詢大量數據,占用有效數據的IO和內存。若須查詢則加 nolock。

Select * from User with(nolock)

Select * from User as U with(nolock)

u 對於復雜分頁查詢,可以先按照條件找出主表ID(在非聚集索引中找出ID),通過ID再關聯找出分頁全部數據(通過聚集索引找出所有數據)

四、 維護規範

生產庫使用完整模式,測試、開發庫可用簡單模式

操作日誌表,ID通常只做主鍵,沒什麽用。可將字段“AddTime”作為聚集索引字段和分區字段。

每次修改函數、存儲過程等,備份舊的副本,記錄修改信息。

數據庫級別的變動,先備份數據庫

大量更新、刪除數據時,先備份事務日誌

刪除、更新數據時,把需要操作的數據存儲到另一個專門的數據庫中作臨時備份。

刪除、更新數據時,小批量操作。建議每次不超過5000行,減少了事務的粒度,也防止鎖升級為表鎖。

定期分批重建索引,不要一次性全部重建。

其他: Disk IO、CPU、Memery、NetWork IO、遷移、擴展等性能問題,找DBA!~

SQL Server 的最大容量規範:https://msdn.microsoft.com/zh-cn/library/ms143432(v=sql.100).aspx

(4.9)SQL Server 數據庫規範