數據庫設計規範(五)

1.數據庫命名規範

1.1.命名規範

  • 命名對象包括文件、類、過程、函數、模塊、變量。
  • 儘可能使用英文。在英文很差表達其含義時,可以使用漢語拼音。
  • 名稱應能反映所表明對象的實際內容和做用。可以使用多個詞組合,但不要使用人名、項目組名。
  • 只可以使用字母、數字和連字符‘_’,但第一個字符必須是字母。
  • 多個詞組合較長時可以使用縮寫,但儘量使用標準的縮寫。在一個系統中要創建縮語表以規範縮寫的使用。
  • 命名時請考慮名字的惟一性和含義的準確性,不得使用很是相近的名字表示幾個不一樣含義的對象。
  • 名稱中字母的大小寫在實施細則中規定,在同一個項目中必須統一。

1.2.相關對象標識

與特定內容相關的一組數據庫對象,賦予一個指定的3字符的英文標識,便於識別和查找。如與客戶信息CustomerInfo相關的數據庫對象,則用mci標識;如與帳戶費用AccountExpense相關數據庫對象,則用eae標識。
 程序員

1.3.內容標識

與對象表示的內容相關的名稱。儘可能使用描述性的、完整的、可以描述每一個對象的用途的名字;若是單詞很長,可以使用縮寫。
用英文單詞或多個單詞組合(儘可能避免使用漢語拼音,拒絕使用漢字)命名,每單詞首字母大寫。
用縮寫時要使用標準的或通用的寫法,同時要創建縮寫詞典以便標準化。
對於專業詞彙,要創建詞彙詞典,以便統一和識別。
 算法

1.4.命名規則

數據庫對象 前綴 相關對象標識 內容標識 後綴
數據庫     <內容標識>  
數據表 t_ <相關對象標識>_ <內容標識> _[<後綴>]
字段     <內容標識>  
視圖 v_ <相關對象標識>_ <內容標識>  
函數 f[t]_ <相關對象標識>_ <內容標識>  
存儲過程 p_ <相關對象標識>_ <內容標識>  
觸發器 tr[i][d][u]_ <表名> <內容標識>  
索引 Ix_ <表名> <內容標識>  
主鍵 pk_ <表名> <內容標識>  
外鍵 fk_ <表名> <內容標識>  
注:
① 只在須要時使用,用以表示同名表間的差異。如主表_m,明細表_d,年度_2000/_2010。
②f:返回值的函數;ft:返回列表的函數。
③i:插入觸發;d:刪除觸發;u:更新觸發
④ 不要使用數據庫系統的保留詞。對於可能在多個表中出現的,或經常使用的名稱,要創建字段名詞典,統一數據類型和長度,以便標準化。
 

2.數據庫編碼規範

2.1.編碼規範總則

經過創建軟件編碼規範,造成代碼約定,提升程序的可讀性、一致性、可維護性,共享性和繼承性,保證程序質量和可靠性,延長程序的生命週期。
 sql

2.1.1.文件結構

(1).每一個程序文件由標題、主體內容和附加說明三部分組成。
(2).標題:文件最前面的註釋說明,其內容主要包括:程序名、做者、程序目的/功能、版本信息、版本號、生成日期、修改日誌、依賴性等。必要時應有更詳盡的說明。
(3).主體內容:爲文件源代碼部分基本上由預處理語句、類型定義、變量定義、實現等部分組成。
(4).附加說明:文件末尾的補充說明,如參考資料等,若內容很少也可放在標題部分的最後。
 數據庫

2.1.2.排版

(1). 要採用縮進風格編寫,縮進使用半角空格鍵,每級縮進的空格數爲4個。
(2).  每一個程序塊或語句塊的起止符(如C/C++語言的大括號「{」和「}」,SQL子查詢的「(」和「)」)應各獨佔一行而且與包含的語句有相同的縮進。
(3).  函數或過程的開始、結構的定義及循環、判斷等語句中的代碼都要採用縮進風格。
(4).  較長的語句要分紅多行書寫,通常每行爲120字符。長語句要在低優先級操做符處劃分新行,操做符放在新行之首。劃分出的新行相對首行要縮進。不得在單詞或詞組中間分行。
(5).  獨立的程序塊之間、變量說明以後、或是程序說明跟主體之間必須加空行。
(6).   一行只寫一條語句,不容許把多個短語句寫在一行中。
 編程

2.1.3.註釋

爲何要使用註釋:
 數據結構

  • 方便代碼的閱讀和維護(修改),但不會增長可執行文件的大小和處理時間;
  • 咱們在維護代碼時,多數時間不是編寫或修改代碼,而是在理解原有代碼(有至關部分是本身編寫的)。而好的註釋能夠大大減小理解代碼的時間。

 
(1)註釋的原則是有助於對程序的閱讀理解,註釋不宜太多也不能太少,註釋語言必須易懂、簡潔、含義準確,防止註釋二義性。
(2).  函數或程序的頭部應進行註釋,列出:函數或程序名、功能說明、參數說明、做者、建立時間、修改人、修改日期。
(3).   邊寫代碼邊註釋,修改代碼同時修改相應的註釋,以保證註釋與代碼的一致性。沒有用的註釋要及時刪除。
(4).  避免在註釋中使用縮寫,特別是很是用縮寫。若是使用縮寫,應對縮寫進行必要的說明。
(5).  註釋應與其描述的代碼鄰近,可放在多行代碼的上方或單行代碼的行尾,不可放在下方;與被解釋的代碼之間不得有空行;如放於上方則需與其上面的代碼用空行隔開。
(6).  註釋與所描述內容使用相同的縮進。
(7).  避免在一行代碼或表達式的中間插入註釋。
(8).  當代碼段較長,特別是多重嵌套時,可在程序塊的結束行右方加註釋標記,以代表某程序塊的結束。
(9).  使用中文註釋。
 併發

2.2.SQL開發規範

規範sql的編寫格式,提升SQL語句的可讀性,共享性和執行效率。
大部分業務系統須要與數據庫進行交互,與數據庫交互的主要方式就是SQL語句,編寫規範的SQL語句不但利於閱讀,並且被數據庫重複使用的概率也較大,執行效率相對較高,編寫的好的SQL與編寫的差的SQL在執行性能上可能會差幾倍甚至幾千幾萬倍,所以養成好的SQL編寫規範對於提升項目質量及提升開發人員自身素質有着潛在的極大的影響。
 數據庫設計

2.2.1.書寫

SQL書寫遵照以下規範:
 ide

  • 在同一個項目中,爲了最大限度實現SQL的共享,要求書寫sql語句時大小寫要一致,爲了閱讀方便和統一塊兒見,全部SQL語句所有小寫(如SQL謂詞,字段名,表名等),常量除外,常量能夠按須要書寫。

舉例:下面兩個相同的語句除常量外都要統一塊兒來。
1)selectnamefromemp;
2)select'NAME' fromempwhereemp_no='QD001'?    
 函數

  • SQL語句儘量放在一行,若SQL太長放在一行中影響閱讀時可分多行,但要保持縮進一致,縮進可用TAB或者空格,但TAB數和空格數最好一致。

 
 

  • SQL語句中,各謂詞之間以空格分割的,儘可能保持空格數量一致,即若用一個空格分割,則所有都用一個空格分割,便於數據庫可以共享。

       
 

  • 能使用綁定變量的,儘可能使用綁定變量,尤爲是在前臺程序中.

 
 

  • 對下面列出的狀況,慎重使用綁定變量:

1)  列值傾斜嚴重,如:某一狀態列大部分值是‘1’,只有極少數值爲’2’,這種狀況不宜用綁定變量,而應該用常量,便於數據庫使用柱狀圖統計信息。
2)  日期時間列。
 
總之:書寫SQL的目標是若sql的用途是同樣的,則sql應該徹底一致,包括空格,大小寫。下面的語句因爲寫法不徹底相同,數據庫會理解爲4條不一樣的語句從而致使重複編譯,下降了性能。
1)selectnamefromempwhereemp_no='111'
2)SelectnameFromempWhereemp_no='111'
3)selectNamefromEMPwhereemp_no='111'
4)selectnamefromempwhereEMP_NO='111'
 
下面的語句,因爲語句規範,能夠只編譯一次。
1)selectnamefromempwhereemp_no='111'
2)selectnamefromempwhereemp_no='222'
3)selectnamefromempwhereemp_no='333'
4)selectnamefromempwhereemp_no=:b1
 

2.2.2.     註釋

(1).開頭註釋
全部的過程、函數、觸發器、包都應該在開頭有註釋,
註釋中要列出對象名稱;完成功能簡述;調用模塊,調用時機;
建立日期;做者信息;歷次修改日期;歷次修改人;歷次修改緣由和其它做者認爲重要的內容,在每次修改的註釋之間建一空行。
 
舉例以下:
/*************************************************************
名稱:PRO_WO_MULTI_REPAIR_JOB
功能:屢次維修斷定程序
調用:自動統計月結前,後臺調用
做者:xxx
時間:2009-02-20
 
修改人:xxx
修改時間:2009-03-08
修改內容:重寫部分SQL優化性能
 
修改人:xxx
修改日期:2010-03-23
修改內容:增長判斷條件
 
*************************************************************/
 
(2).塊註釋
對於複雜的語句塊,必須提供塊註釋,清晰描述該語句塊的功能邏輯、數據結構以及算法;塊註釋應該和它們所描述的代碼具備同樣的縮進格式;塊註釋之首應該有一個空行,用於把塊註釋和代碼分割開來;塊註釋結構以下所示:
/*
    計算配送能力系數:
    派工係數=a*b+c*d+e*f
    a:考評成績,取xx的考評成績
    c:承擔度度,根據當前遺留量和總服務能力計算所得,
    c=當前遺留配送量/總配送能力
     ...
*/
 
(3).行註釋
對於複雜的SQL語句,必須提供行註釋,清晰描述該SQL語句功能以及目的;行註釋結構以下所示:
--計算動態能力得分,當負荷率超高時,可能出現負值,注意處理。
 
添加註釋時要注意:註釋中包含GO 命令時會生成一個錯誤消息。
 

2.2.3.     存儲過程和函數

(1).命名規範
存儲過程/函數的命名(代碼)使用如下方式:
存儲過程名=  p_ + 模塊代碼+ 存儲過程代碼
函數名=  f_ + 模塊代碼+ 函數代碼
存儲過程以表現其功能的簡潔語言進行命名,定義好後,放置於每個Diagram的特定區域(通常置於右邊部分的上邊)。
 
(2).存儲過程/函數頭定義規範
包括過程/函數名稱定義、參數定義、註釋說明、變量定義四部分。
 

  • 參數定義

全部的參數必須顯示指出變量類型,對於返回參數,必須指出其方向;
參數變量定義格式爲:「a「+參數類型簡寫+「_」+參數名稱,其中a是單詞argument(參數)的第一個字母,參數類型以下:
文本型:s
日期時間型:d
數字型:n
×××:i
布爾型:b
舉例:as_name 表示文本型
      ad_birthdate 表示日期時間型
      an_age   表示數字型
 
 

  • 註釋說明

見前面描述。
 
(3).變量定義規範
1).變量的命名
除遊標變量之外,全部的變量命名採用此方式:
變量名= 「v_」+ 變量名稱
遊標變量採用:
變量名= 「cur」+ 變量名(第一個字母大寫)。
其中變量名稱由表明變量確切含意的單詞代碼組合而成,每個單詞的首字母根據閱讀的方便性決定是否須要大寫。
舉例:
變量名:v_EmpName
遊標名:curNetlist
 
2).變量類型
定義變量的類型時,儘可能採用顯示定義的方式。儘可能將變量的定義分開來,並進行格式化,以便程序代碼的閱讀。例如:
v_UserName   CHAR(10)
v_SEX        CHAR(1)
 
(4).變量註釋
原則上要求對於通常變量定義時必須加上註釋,如變量有特定的值範圍,則必須顯示描述各確切值及其含意說明;
 
(5).存儲過程/函數體定義規範
在過程/函數的定義中,最重要的是過程代碼的嚴謹性和可讀性,主要包括如下的注意事項:
1).如無特殊須要,SQL中涉及的全部內容都要小寫。
2).原則上要求全部的SQL語句必須在其前面加上註釋,對於IF/CASE等流程控制語句,必須在語句前/後說明控制處理和可能的流程方向;
3).全部的賦值語句要求變量與運算符之間要有空格。如:v_Count := v_Count + 1,並保持適當的對齊;
4).儘可能避免複雜SQL,尤爲是關聯多個大表的SQL,對於須要關聯多個大表的SQL最好分解成小的SQL分步處理,避免出現性能問題,對於複雜的語句塊之間,要求中間加入空行;
5).全部可能的返回結果,必須在過程體中顯示定義和說明,並在註釋中說明。在其它的過程、代碼中調用本過程/函數時,必須在其代碼中處理全部的各類可能的返回結果;
6).鎖定數據時,儘量只鎖定要操做的數據行,避免鎖定整個表,限制使用local table等DDL語句,若要對數據表、數據行加鎖時,須要考慮由此致使的併發操做失敗的處理;
7).全部的過程/函數代碼在編寫以前,必需要有設計原型及其說明;
 
(6).  存儲過程/函數錯誤定義
 
1).全部的DML語句必須考慮死鎖、併發、主關鍵字不惟一等的出錯異常處理,應該對全部可能出現的異常進行捕獲、編碼處理,並註明異常的內容;
2).異常處理有兩種須要考慮的問題,一是事務的完整性;二是錯誤的出錯日誌及返回處理。全部異常的根據其類型和等級進行如下的處理:

類型 內容 處理  
系統級 數據庫級發出的底層的異常,如主關鍵字不惟一衝突等; 返回定義錯誤代碼爲其它錯誤,徹底回退事務,登陸異常日誌;  
應用級 應用系統定義併發出的異常,如指定記錄不存在; 定義應用級錯誤代碼,根據實際狀況處理事務;  
 
(7).  存儲過程/函數使用原則
1).存儲過程功能儘可能保持獨立、複用,但儘可能避免嵌套調用,充分考慮其性能體現;
2).使用前臺代碼調用存儲過程時,必須考慮返回傳入參數的有效性、代碼的處理及展現、事務完整性處理;
3).直接使用參數做爲變量處理,不要在存儲過程當中定義參數一樣含義的變量使用,避免因爲值的不一樣致使性能問題。
 

2.2.4.觸發器

(1).命名規範
觸發器不一樣類型的命名結構以下

操做 時機 命名結構
Insert After ai_表名
Update After au_表名
Delete After ad_表名
 
(2).觸發器編寫規範
請參見存儲過程/函數編寫規範。
 
(3).異常
全部過程和函數處理必須考慮可能出現的錯誤,一是數據庫或操做系統底層錯誤;二是因爲業務邏輯形成的錯誤;三是無反應或超時;四是輸入參數不在指定範圍內。
設計全部的過程時,必須考慮出錯後的恢復。
 

2.3.優化

2.3.1.SQL語句原則

  • Where子句儘可能避免使用函數;
  • 避免在ORDER BY子句中使用表達式;
  • 限制在GROUP BY子句中使用表達式;
  • 慎用遊標;
  • 大小寫規範統一,變量綁定統一,避免重複編譯;
  • 儘量少的返回結果集行的數量
  • 避免使用select * 語句;
  • 減小結果集中的列的數量;
  • 視圖嵌套使用不能超過3層;
  • 不要使用沒有意義的列做爲彙集索引列,例如,加1自增列;
  • 避免隱式類型轉換,例如字符型必定要用’’,數字型必定不要使用’’;
  • 查詢語句必定要有範圍的限定,避免全表掃描操做;
  • 合理對大表進行分區;
  • 慎用DISTINCT關鍵字;
  • 慎用UNION關鍵字,能夠用OR替代;
  • 使用top 1替count(*)來判斷是否存在記錄;

2.3.2.索引建立原則

  • 同一索引中的組成列最好不要超過3列。
  • 把常常一塊兒出現的字段組合在一塊兒,組成組合索引,組合索引的字段順序與主鍵同樣,也須要把最經常使用的字段放在前面,把重複率低的字段放在前面。
  • 根據使用頻率決定哪些字段須要創建索引,選擇常常做爲鏈接條件、篩選條件、聚合查詢、排序的字段做爲索引的候選字段。
  • 根據數據量決定哪些表須要增長索引,數據量小的能夠只有主鍵。
  • 若某列中有大量的值是空值,能夠創建索引。
  • 要對值分佈較寬的列創建索引。
  • 若表主要用來查詢,則可按須要創建索引,若對錶操做主要是UPDATE,則儘量少建索引。
  • 不要對值較窄的列創建索引,如性別
  • 不要索引較小的表(如表不足1000行)
  • 若某列的值大部分是a,少數是別的值(如b,c,d…),且常常以該列的其它值(如b,c,d…)爲查詢條件,則能夠將值a設爲空值,並在此列上建立索引。

2.3.3.充分利用索引

(1).函數、表達式使用
在where語句中,儘可能避免在運算符左邊對列進行函數或者表達式操做,容易引發全表掃描,要儘量將操做移至運算符右邊。
 
(2).IN/OR子句使用
IN、OR、NOT IN Sql Server2005數據庫能夠分析出應該根據索引查找。屬於2005版本的新特性。
 
(3). !=或<>操做符子句使用
!=或<>操做符能夠用INDEXSEEK查找的,能夠正常使用。
 
(4). 不要對索引字段進行運算
例如:
SELECTIDFROMTWHERENUM/2=100
應改成:
SELECTIDFROMTWHERENUM=100*2
 
SELECTIDFROMTWHERENUM/2=NUM1
若是NUM有索引應改成:
SELECTIDFROMTWHERENUM=NUM1*2
若是NUM1有索引則不該該改。
 
 
 
(5). 不要對索引字段進行格式轉換
日期字段的例子:
WHERECONVERT(VARCHAR(10),日期字段,120)='2008-08-15'
應該改成
WHERE日期字段〉='2008-08-15'  AND日期字段<'2008-08-16'
 
ISNULL轉換的例子:
WHEREISNULL(字段,'')<>''應改成:WHERE字段<>''
WHEREISNULL(字段,'')=''不該修改
WHEREISNULL(字段,'F')='T'應改成:WHERE字段='T'
WHEREISNULL(字段,'F')<>'T'不該修改
 
(6).不要對索引字段使用函數
WHERELEFT(NAME,3)='ABC'或者WHERESUBSTRING(NAME,1,3)='ABC'
應改成:
WHERENAMELIKE'ABC%'
 
日期查詢的例子:
WHEREDATEDIFF(DAY,日期,'2005-11-30')=0
應改成:WHERE日期>='2005-11-30'AND日期<'2005-12-1'
 
WHEREDATEDIFF(DAY,日期,'2005-11-30')>0
應改成:WHERE日期<'2005-11-30'
 
WHEREDATEDIFF(DAY,日期,'2005-11-30')>=0
應改成:WHERE日期<'2005-12-01'
 
WHEREDATEDIFF(DAY,日期,'2005-11-30')<0
應改成:WHERE日期>='2005-12-01'
 
WHEREDATEDIFF(DAY,日期,'2005-11-30')<=0
應改成:WHERE日期>='2005-11-30'
 
(7).不要對索引字段進行多字段鏈接
例如:
WHEREFAME+'.'+LNAME='H.Y'
應改成:
WHEREFNAME='H'ANDLNAME='Y'
 

2.3.4.Like的使用

對索引列避免使用like ‘%xx’, 應該使用like ‘xx%’。設計數據結構時就應該考慮這個問題,不要出現必需要採用like ‘%xx’才能知足業務須要的情形。
 

2.4.編碼階段

2.4.1.儘量少的範圍數據

A、 橫向來看,不要寫SELECT *的語句,而是選擇你須要的字段。
B、 縱向來看,合理寫WHERE子句,不要寫沒有WHERE的SQL語句。
C、 注意SELECT INTO後的WHERE子句,由於SELECT INTO把數據插入到臨時表,這個過程會鎖定一些系統表,若是這個WHERE子句返回的數據過多或者速度太慢,會形成系統表長期鎖定,諸塞其餘進程。
D、對於聚合查詢,能夠用HAVING子句進一步限定返回的行。
 

2.4.2.儘量少的重複操做

A、控制同一語句的屢次執行,特別是一些基礎數據的屢次執行是不少程序員不多注意的。
B、減小屢次的數據轉換,也許須要數據轉換是設計的問題,可是減小次數是程序員能夠作到的。
C、杜毫不必要的子查詢和鏈接表,子查詢在執行計劃通常解釋成外鏈接,多餘的鏈接錶帶來額外的開銷。
D、合併對同一表同一條件的屢次UPDATE,好比
UPDATEEMPLOYEESETFNAME='H'WHEREEMP_ID=' F'
UPDATEEMPLOYEESETLNAME='Y'WHEREEMP_ID=' F'
這兩個語句應該合併成如下一個語句
UPDATEEMPLOYEESETFNAME='H',LNAME='Y'WHEREEMP_ID=' F'
 
E、UPDATE操做不要拆成DELETE操做+INSERT操做的形式,雖然功能相同,可是性能差異是很大的。
F、不要寫一些沒有意義的查詢,好比
SELECT*FROMEMPLOYEEWHERE1=2
 

2.4.3.注意事務和鎖

事務是數據庫應用中和重要的工具,它有原子性、一致性、隔離性、持久性這四個屬性,不少操做咱們都須要利用事務來保證數據的正確性。在使用事務中咱們須要作到儘可能避免死鎖、儘可能減小阻塞。具體如下方面須要特別注意:
A、事務操做過程要儘可能小,能拆分的事務要拆分開來。
B、 事務操做過程不該該有交互,由於交互等待的時候,事務並未結束,可能鎖定了不少資源。
C、 事務操做過程要按同一順序訪問對象。
D、提升事務中每一個語句的效率,利用索引和其餘方法提升每一個語句的效率能夠有效地減小整個事務的執行時間。
E、 儘可能不要指定鎖類型和索引,SQL SERVER容許咱們本身指定語句使用的鎖類型和索引,可是通常狀況下,SQL SERVER優化器選擇的鎖類型和索引是在當前數據量和查詢條件下是最優的,咱們指定的可能只是在目前狀況下更有,可是數據量和數據分佈在未來是會變化的。
 

2.4.4.注意臨時表和表變量的用法

在複雜系統中,臨時表和表變量很難避免,關於臨時表和表變量的用法,須要注意:
A、若是語句很複雜,鏈接太多,能夠考慮用臨時表和表變量分步完成。
B、若是須要屢次用到一個大表的同一部分數據,考慮用臨時表和表變量暫存這部分數據。
C、若是須要綜合多個表的數據,造成一個結果,能夠考慮用臨時表和表變量分步彙總這多個表的數據。
D、其餘狀況下,應該控制臨時表和表變量的使用。
E、關於臨時表和表變量的選擇,不少說法是表變量在內存,速度快,應該首選表變量,可是在實際使用中發現,這個選擇主要考慮須要放在臨時表的數據量,在數據量較多的狀況下,臨時表的速度反而更快。
F、關於臨時表產生使用SELECTINTO和CREATETABLE+INSERTINTO的選擇,咱們作過測試,通常狀況下,SELECTINTO會比CREATETABLE+INSERTINTO的方法快不少,可是SELECTINTO會鎖定TEMPDB的系統表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用戶併發環境下,容易阻塞其餘進程,因此個人建議是,在併發系統中,儘可能使用CREATETABLE+INSERTINTO,而大數據量的單個語句使用中,使用SELECTINTO。
G、注意排序規則,用CREATETABLE創建的臨時表,若是不指定字段的排序規則,會選擇TEMPDB的默認排序規則,而不是當前數據庫的排序規則。若是當前數據庫的排序規則和TEMPDB的排序規則不一樣,鏈接的時候就會出現排序規則的衝突錯誤。通常能夠在CREATETABLE創建臨時表時指定字段的排序規則爲DATABASE_DEFAULT來避免上述問題。
 

2.4.5.注意子查詢的用法

子查詢是一個 SELECT查詢,它嵌套在 SELECT、INSERT、UPDATE、DELETE語句或其它子查詢中。任何容許使用表達式的地方均可以使用子查詢。
子查詢可使咱們的編程靈活多樣,能夠用來實現一些特殊的功能。可是在性能上,每每一個不合適的子查詢用法會造成一個性能瓶頸。
若是子查詢的條件中使用了其外層的表的字段,這種子查詢就叫做相關子查詢。相關子查詢能夠用IN、NOTIN、EXISTS、NOTEXISTS引入。
 
關於相關子查詢,應該注意:
A、NOTIN、NOTEXISTS的相關子查詢能夠改用LEFTJOIN代替寫法。好比:
 SELECTPUB_NAME  FROM  PUBLISHERS WHEREPUB_IDNOTIN
   (SELECTPUB_IDFROMTITLES  WHERETYPE='BUSINESS')
 能夠改寫成:
SELECTA.PUB_NAME  FROMPUBLISHERSA
LEFTJOINTITLESBON  B.TYPE='BUSINESS'AND  A.PUB_ID=B.PUB_ID
 
SELECTTITLEFROMTITLES
WHERENOTEXISTS(SELECTTITLE_IDFROMSALESWHERETITLE_ID=TITLES.TITLE_ID)
能夠改寫成:
SELECTTITLE 
FROMTITLESLEFTJOINSALESNSALES.TITLE_ID=TITLES.TITLE_ID
WHERESALES.TITLE_IDISNULL
 
B、若是保證子查詢沒有重複,IN、EXISTS的相關子查詢能夠用INNERJOIN代替。好比:
SELECTPUB_NAMEFROMPUBLISHERS  WHEREPUB_IDIN(SELECTPUB_IDFROMTITLESWHERETYPE='BUSINESS')
能夠改寫成:
SELECTDISTINCTA.PUB_NAME  
FROMPUBLISHERSA
INNERJOINTITLESBON  B.TYPE='BUSINESS'ANDA.PUB_ID=B.PUB_ID
 
C、不要用COUNT(*)的子查詢判斷是否存在記錄,最好用LEFTJOIN或者EXISTS,好比有人寫這樣的語句:
SELECTJOB_DESCFROMJOBS
WHERE (SELECTCOUNT(*)FROMEMPLOYEEWHEREJOB_ID=JOBS.JOB_ID)=0
應該改爲:
SELECTJOBS.JOB_DESCFROMJOBS
LEFTJOINEMPLOYEEONEMPLOYEE.JOB_ID=JOBS.JOB_ID
WHEREEMPLOYEE.EMP_IDISNULL
 
SELECTJOB_DESCFROMJOBS
WHERE (SELECTCOUNT(*)FROMEMPLOYEEWHEREJOB_ID=JOBS.JOB_ID)<>0
應該改爲:
SELECTJOB_DESCFROMJOBS
WHEREEXISTS(SELECT1 FROMEMPLOYEEWHEREJOB_ID=JOBS.JOB_ID)
 

2.4.6.注意鏈接條件的用法

多表鏈接的鏈接條件對索引的選擇有着重要的意義,因此咱們在寫鏈接條件的時候須要特別的注意。
A、多表鏈接的時候,鏈接條件必須寫全,寧肯重複,不要缺漏。
B、 鏈接條件儘可能使用匯集索引
C、 注意ON部分條件和WHERE部分條件的區別
 

2.4.7.查看執行計劃及成本

養成良好的編碼習慣,每寫完一個sql語句,就查看執行計劃及成本分析。在大表上儘量避免全表掃描及彙集索引掃描。
 

2.4.8.索引的使用及維護

在良好的數據庫設計基礎上,能有效地使用索引是SQL Server取得高性能的基礎,SQL Server採用基於代價的優化模型,它對每個提交的有關表的查詢,決定是否使用索引或用哪個索引。由於查詢執行的大部分開銷是磁盤I/O,使用索引提升性能的一個主要目標是避免全表掃描,由於全表掃描須要從磁盤上讀表的每個數據頁,若是有索引指向數據值,則查詢只需讀幾回磁盤就能夠了。因此若是創建了合理的索引,優化器就能利用索引加速數據的查詢過程。可是,索引並不老是提升系統的性能,在增、刪、改操做中索引的存在會增長必定的工做量,所以,在適當的地方增長適當的索引並從不合理的地方刪除次優的索引,將有助於優化那些性能較差的SQL Server應用。
 
(1). 聚簇索引(clustered indexes)的使用
聚簇索引是一種對磁盤上實際數據從新組織以按指定的一個或多個列的值排序。因爲聚簇索引的索引頁面指針指向數據頁面,因此使用聚簇索引查找數據幾乎老是比使用非聚簇索引快。每張表只能建一個聚簇索引,而且建聚簇索引須要至少至關該表120%的附加空間,以存放該表的副本和索引中間頁。創建聚簇索引的思想是:
一、大多數表都應該有聚簇索引或使用分區來下降對錶尾頁的競爭,在一個高事務的環境中,對最後一頁的封鎖嚴重影響系統的吞吐量。
二、在聚簇索引下,數據在物理上按順序排在數據頁上,重複值也排在一塊兒,於是在那些包含範圍檢查(between、<、<=、>、>=)或使用group by或order by的查詢時,一旦找到具備範圍中第一個鍵值的行,具備後續索引值的行保證物理上毗連在一塊兒而沒必要進一步搜索,避免了大範圍掃描,能夠大大提升查詢速度。
三、在一個頻繁發生插入操做的表上創建聚簇索引時,不要建在具備單調上升值的列(如IDENTITY)上,不然會常常引發封鎖衝突。
四、在聚簇索引中不要包含常常修改的列,由於碼值修改後,數據行必須移動到新的位置。
五、選擇聚簇索引應基於where子句和鏈接操做的類型。
 
聚簇索引的侯選列是:
一、主鍵列,該列在where子句中使用而且插入是隨機的。
二、按範圍存取的列,如pri_order > 100 and pri_order < 200。
三、在groupby或orderby中使用的列。
四、不常常修改的列。
五、在鏈接操做中使用的列
 
(2). 非聚簇索引(nonclustered indexes)的使用
SQL Server缺省狀況下創建的索引是非聚簇索引,因爲非聚簇索引不從新組織表中的數據,而是對每一行存儲索引列值並用一個指針指向數據所在的頁面。換句話說非聚簇索引具備在索引結構和數據自己之間的一個額外級。一個表若是沒有聚簇索引時,可有250個非聚簇索引。每一個非聚簇索引提供訪問數據的不一樣排序順序。在創建非聚簇索引時,要權衡索引對查詢速度的加快與下降修改速度之間的利弊。另外,還要考慮這些問題:
一、索引須要使用多少空間。
二、合適的列是否穩定。
三、索引鍵是如何選擇的,掃描效果是否更佳。
四、是否有許多重複值。
對更新頻繁的表來講,表上的非聚簇索引比聚簇索引和根本沒有索引須要更多的額外開銷。對移到新頁的每一行而言,指向該數據的每一個非聚簇索引的頁級行也必須更新,有時可能還須要索引頁的分理。從一個頁面刪除數據的進程也會有相似的開銷,另外,刪除進程還必須把數據移到頁面上部,以保證數據的連續性。因此,創建非聚簇索引要很是慎重。非聚簇索引常被用在如下狀況:
一、某列經常使用於集合函數(如Sum,....)。
二、某列經常使用於join,order by,group by。
三、查尋出的數據不超過表中數據量的20%。
 
(3).  覆蓋索引(covering indexes)的使用
覆蓋索引是指那些索引項中包含查尋所須要的所有信息的非聚簇索引,這種索引之因此比較快也正是由於索引頁中包含了查尋所必須的數據,不需去訪問數據頁。若是非聚簇索引中包含結果數據,那麼它的查詢速度將快於聚簇索引。 可是因爲覆蓋索引的索引項比較多,要佔用比較大的空間。並且update操做會引發索引值改變。因此若是潛在的覆蓋查詢並不經常使用或不太關鍵,則覆蓋索引的增長反而會下降性能。
 

2.4.9.索引的選擇技術

索引的有無,創建方式的不一樣將會致使不一樣的查詢效果,選擇什麼樣的索引基於用戶對數據的查詢條件,這些條件體現於where從句和join表達式中。通常來講創建索引的思路是:
 (1)、主鍵時常做爲where子句的條件,應在表的主鍵列上創建聚簇索引,尤爲當常常用它做爲鏈接的時候。
 (2)、有大量重複值且常常有範圍查詢和排序、分組發生的列,或者很是頻繁地被訪問的列,可考慮創建聚簇索引。
 (3)、常常同時存取多列,且每列都含有重複值可考慮創建複合索引來覆蓋一個或一組查詢,並把查詢引用最頻繁的列做爲前導列,若是可能儘可能使關鍵查詢造成覆蓋查詢。
 (4)、若是知道索引鍵的全部值都是惟一的,那麼確保把索引定義成惟一索引。
 (5)、在一個常常作插入操做的表上建索引時,使用fillfactor(填充因子)來減小頁分裂,同時提升併發度下降死鎖的發生。若是在只讀表上建索引,則能夠把fillfactor置爲100。
 (6)、在選擇索引鍵時,設法選擇那些採用小數據類型的列做爲鍵以使每一個索引頁可以容納儘量多的索引鍵和指針,經過這種方式,可以使一個查詢必須遍歷的索引頁面降到最小。此外,儘量地使用整數爲鍵值,由於它可以提供比任何數據類型都快的訪問速度。
 

2.4.10.索引的維護

某些不合適的索引影響到SQL Server的性能,隨着應用系統的運行,數據不斷地發生變化,當數據變化達到某一個程度時將會影響到索引的使用。這時須要用戶本身來維護索引。索引的維護包括:
一、重建索引
隨着數據行的插入、刪除和數據頁的分裂,有些索引頁可能只包含幾頁數據,另外應用在執行大塊I/O的時候,重建非聚簇索引能夠下降分片,維護大塊I/O的效率。重建索引其實是從新組織B-樹空間。在下面狀況下須要重建索引:
 (1)、數據和使用模式大幅度變化。
 (2)、排序的順序發生改變。
 (3)、要進行大量插入操做或已經完成。
 (4)、使用大塊I/O的查詢的磁盤讀次數比預料的要多。
 (5)、因爲大量數據修改,使得數據頁和索引頁沒有充分使用而致使空間的使用超出估算。
 (6)、dbcc檢查出索引有問題。
當重建聚簇索引時,這張表的全部非聚簇索引將被重建。
二、索引統計信息的更新
當在一個包含數據的表上建立索引的時候,SQL Server會建立分佈數據頁來存放有關索引的兩種統計信息:分佈表和密度表。優化器利用這個頁來判斷該索引對某個特定查詢是否有用。但這個統計信息並不動態地從新計算。這意味着,當表的數據改變以後,統計信息有多是過期的,從而影響優化器追求最有工做的目標。所以,在下面狀況下應該運行update statistics命令:
 (1)、數據行的插入和刪除修改了數據的分佈。
 (2)、對用truncate table刪除數據的表上增長數據行。
 (3)、修改索引列的值。
 

相關文章
相關標籤/搜索