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

SQL Server 數據庫規範

聚集 rom 空格 重復讀取 cpu role sys 結果集 選項

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

---------------------

本文來自 Huang-ZC 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/kk185800961/article/details/78866259?utm_source=copy

SQL Server 數據庫規範