常見的欄位型別選擇
約束與索引
每張表必須有主鍵
•每張表必須有主鍵,用於強制實體完整性
•單表只能有一個主鍵(不允許為空及重複資料)
•儘量使用單欄位主鍵
不允許使用外來鍵
NULL屬性
(新表為什麼不允許NULL?
你想來找查詢除了name等於aa的所有資料,然後你就不經意間用了
1 |
SELECT * FROM NULLTEST WHERE NAME<>’aa’ |
結果發現與預期不一樣,事實上它只查出了name=bb而沒有查詢出name=NULL的資料記錄
那我們如何查詢除了name等於aa的所有資料,只能用ISNULL函式了
1 |
SELECT * FROM NULLTEST WHERE ISNULL(NAME,1)<>’aa’ |
索引設計準則
不要給選擇性低的欄位建立單列索引
充分利用唯一索引
唯一索引給SQL Server提供了確保某一列絕對沒有重複值的資訊,當查詢分析器通過唯一索引查詢到一條記錄則會立刻退出,不會繼續查詢索引
表索引數不超過6個
表索引數不超過6個(這個規則只是攜程DBA經過試驗之後制定的。。。)
SQL查詢
禁止在資料庫做複雜運算
禁止使用SELECT *
禁止在索引列上使用函式或計算
禁止在索引列上使用函式或計算
在where子句中,如果索引是函式的一部分,優化器將不再使用索引而使用全表掃描
假設在欄位Col1上建有一個索引,則下列場景將無法使用到索引:
1 2 3 |
ABS[Col1]=1 [Col1]+1>9 |
再舉例說明一下
像上面這樣的查詢,將無法用到O_OrderProcess表上的PrintTime索引,所以我們應用使用如下所示的查詢SQL
禁止在索引列上使用函式或計算
假設在欄位Col1上建有一個索引,則下列場景將可以使用到索引:
[Col1]=3.14
[Col1]>100
[Col1] BETWEEN 0 AND 99
[Col1] LIKE ‘abc%’
[Col1] IN(2,3,5,7)
LIKE查詢的索引問題
禁止使用遊標
禁止使用觸發器
觸發器對應用不透明(應用層面都不知道會什麼時候觸發觸發器,發生也也不知道,感覺莫名……)
禁止在查詢裡指定索引
With(index=XXX)( 在查詢裡我們指定索引一般都用With(index=XXX) )
變數/引數/關聯欄位型別必須與欄位型別一致(這是我之前不太關注的)
避免型別轉換額外消耗的CPU,引起的大表scan尤為嚴重
看了上面這兩個圖,我想我不用解釋說明,大家都應該已經清楚了吧。
如果資料庫欄位型別為VARCHAR,在應用裡面最好型別指定為AnsiString並明確指定其長度
如果資料庫欄位型別為CHAR,在應用裡面最好型別指定為AnsiStringFixedLength並明確指定其長度
如果資料庫欄位型別為NVARCHAR,在應用裡面最好型別指定為String並明確指定其長度
引數化查詢
以下方式可以對查詢SQL進行引數化:
限制JOIN個數
限制IN子句中條件個數
儘量避免大事務操作
關閉影響的行計數資訊返回
在SQL語句中顯示設定Set Nocount On,取消影響的行計數資訊返回,減少網路流量
除非必要SELECT語句都必須加上NOLOCK
除非必要,儘量讓所有的select語句都必須加上NOLOCK
指定允許髒讀。不釋出共享鎖來阻止其他事務修改當前事務讀取的資料,其他事務設 置的排他鎖不會阻礙當前事務讀取鎖定資料。允許髒讀可能產生較多的併發操作,但其代價是讀取以後會被其他事務回滾的資料修改。這可能會使您的事務出錯,向使用者顯示從未提交過的資料,或者導致使用者兩次看到記錄(或根本看不到記錄)
使用UNION ALL替換UNION
使用UNION ALL替換UNION
UNION會對SQL結果集去重排序,增加CPU、記憶體等消耗
查詢大量資料使用分頁或TOP
合理限制記錄返回數,避免IO、網路頻寬出現瓶頸
遞迴查詢層次限制
使用 MAXRECURSION 來防止不合理的遞迴 CTE 進入無限迴圈
臨時表與表變數
使用本地變數選擇中庸執行計劃
在儲存過程或查詢中,訪問了一張資料分佈很不平均的表格,這樣往往會讓儲存過程或查詢使用了次優甚至於較差的執行計劃上,造成High CPU及大量IO Read等問題,使用本地變數防止走錯執行計劃。
採用本地變數的方式,SQL在編譯的時候是不知道這個本地變數的值,這時候SQL會根據表格裡資料的一般分佈,“猜測”一個返回值。不管使用者在呼叫儲存過程或語句的時候代入的變數值是多少,生成的計劃都是一樣的。這樣的計劃一般會比較中庸一些,不一定是最優的計劃,但一般也不會是最差的計劃
Estimated Rows =(Total Rows * 30)/100
Estimated Rows = Density * Total Rows
儘量避免使用OR運算子
對於OR運算子,通常會使用全表掃描,考慮分解成多個查詢用UNION/UNION ALL來實現,這裡要確認查詢能走到索引並返回較少的結果集
增加事務異常處理機制
輸出列使用二段式命名格式
二段式命名格式:表名.欄位名
有JOIN關係的TSQL,欄位必須指明欄位是屬於哪個表的,否則未來表結構變更後,有可能發生Ambiguous column name的程式相容錯誤
架構設計
讀寫分離
Schema解耦
禁止跨庫JOIN
資料生命週期
根據資料的使用頻繁度,對大表定期分庫歸檔
主庫/歸檔庫物理分離
日誌型別的表應分割槽或分表
對於大的表格要進行分割槽,分割槽操作將表和索引分在多個分割槽,通過分割槽切換能夠快速實現新舊分割槽替換,加快資料清理速度,大幅減少IO資源消耗
頻繁寫入的表,需要分割槽或分表
自增長與Latch Lock
閂鎖是sql Server自己內部申請和控制,使用者沒有辦法來干預,用來保證記憶體裡面資料結構的一致性,鎖級別是頁級鎖。