常見的字段類型選擇
約束與索引
每張表必須有主鍵
?每張表必須有主鍵,用于強制實體完整性
?
?單表只能有一個主鍵(不允許為空及重復數據)
?盡量使用單字段主鍵
?
不允許使用外鍵
NULL屬性

SELECT * FROM NULLTEST WHERE NAME<>’aa’
結果發現與預期不一樣,事實上它只查出了name=bb而沒有查找出name=NULL的數據記錄
那我們如何查找除了name等于aa的所有數據,只能用ISNULL函數了
SELECT * FROM NULLTEST WHERE ISNULL(NAME,1)<>’aa’
索引設計準則
不要給選擇性低的字段創建單列索引
充分利用唯一索引
唯一索引給SQL Server提供了確保某一列絕對沒有重復值的信息,當查詢分析器通過唯一索引查找到一條記錄則會立刻退出,不會繼續查找索引
表索引數不超過6個
表索引數不超過6個(這個規則只是攜程DBA經過試驗之后制定的。。。)
SQL查詢
?
禁止在數據庫做復雜運算
禁止使用SELECT *
禁止在索引列上使用函數或計算
禁止在索引列上使用函數或計算
在where子句中,如果索引是函數的一部分,優化器將不再使用索引而使用全表掃描?
假設在字段Col1上建有一個索引,則下列場景將無法使用到索引:
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自己內部申請和控制,用戶沒有辦法來干預,用來保證內存里面數據結構的一致性,鎖級別是頁級鎖