標籤:儲存 意義 未命名 tle 自動產生 name 暫存資料表 檢查 情況
原文:SQL Server中有關約束(constraint)的一些細節
本文出處:http://www.cnblogs.com/wy123/p/7350265.html
(保留出處並非什麼原創作品權利,本人拙作還遠遠達不到,僅僅是為了連結到原文,因為後續對可能存在的一些錯誤進行修正或補充,無他)
SQL Server 資料庫中的約束(Constrint)是作用是為了保證資料庫的完整性和一致性,可以建表的時候指定某個欄位要符合某種約束(或者對已有表的欄位添加約束),比如唯一性(或者主鍵)約束,非空約束,預設值約束等
對於具體的約束,可以分為主鍵(唯一鍵)約束,預設值約束,檢查約束,外鍵約束等幾類。
約束的建立方式
1,建表的時候指定
如下,可以在建表的時候指定某些欄位滿足某種約束。
2,以建立約束的方式指定
也即在建表的時候沒有指定任何約束,在建表之後,以alter table的方式指定某些欄位上的約束
對於Check或者Default約束,也可以事先定義出來規則(Rule),然後將規則綁定到對應表的欄位
如下分別定義了一個check約束和預設值約束,然後將表的欄位綁定到對應的約束,這樣做的好處是對於某些複雜的約束,定義好約束之後就可以重用了
需要注意的是,對於Rule來說,NULL值是不與任何規則衝突的,
舉個例子,如下,雖然把TestConstrint.Sex欄位指定了規則Rule_Sex,如果Sex定義的是int,該欄位寫入資料的時候只能是0或者1,寫入2是失敗的,
但是往該欄位寫入null值是可以的,因為null與規則指定的(0,1)相比沒有任何意義(或者沒有任何結果)
約束的一些特點
對於建表的時候指定的未命名的約束,SQL Server會自動產生尾碼隨機的預設的約束名字,為了增加規範性,正常情況下是不允許這麼寫的,因為我們不希望看到資料庫中一堆亂七八髒的命名。
如果是指定約束的名字,看起來就規範多了。
如果是通過定義規則,然後綁定到表的欄位的情況下,通過SSMS的圖形介面,是看不到約束展開之後的內容的(雖然這個約束是生效的)
資料庫約束中那些不容易被注意的坑
約束看起來非常簡單,不管是在建表的時候直接指定,或者是通過alter 表的方式增加約束,看起來都沒有任何問題,條條大道通羅馬,不過裡面還是有一些小坑的。
一個資料庫中的約束不允許重名。
也就是意味著,不同的表之間,或者表上與自訂約束之間,都不能存在同名的情況,包括主鍵約束(不能同名),檢查約束(check),預設值約束等,都不能同名
約束的道理跟表一樣,一個庫的一個schema下中不能定義同名的表一個道理,一個庫的一個schema下不能定義同名的約束一樣。
現在也不難理解,為什麼sqlserver預設產生的約束的名字,後面是一串隨機字元了吧?
1,表與表之間的約束不能同名
2,表與自訂約束名之間不能同名。
當然有人會說,這有什麼,定義的時候報錯就知道了,還有更大的坑。
這裡涉及到約束的另一種定義方法,建表的過程中指定命名的主鍵約束。
比如如下的定義暫存資料表的指令碼,看起來沒有任何問題,也確實沒有任何問題,
實際中遇到的一個開發人員的問題,編寫的預存程序中定義了暫存資料表,定義暫存資料表的時候指定了命名的主鍵約束(可能是抄的物理表的定義方式),測試通過並發布到生產環境中,一切看起來非常正常。
發布之後測試了兩把,也表現為正常,等到系統真正被使用者使用的時候,部分使用者反饋系統(涉及到這個功能的地方)偶爾會報錯,時而正常,時而不正常(其實這種問題最難診斷的了)。
監控應用程式會發現,某個時間段之內,發現這個預存程序會連續地報錯一種錯誤,錯誤原因就是“無法建立索引或者約束”
開發人員也很委屈,提交完代碼之後,明明是測試通過了的,更可惡的是,偶爾會報錯,大部分時間是正常的。
通過觀察其代碼,然後冷靜下來想一想,也不難理解,資料庫中的約束是不能同名的,當然暫存資料表生存的臨時庫也不例外,
暫存資料表用完就會自動銷毀沒有錯,意味著如果所有的Session都是串列執行,這個完全沒有問題。
但是一旦出現並發調用的情況,不同的Session會同時調用這個預存程序,
一旦並發調用這個預存程序,不同的Session會建立同一個名字的約束,鐵定只有一個會成功,這麼看,單線程測試正常,並發上來之後報錯也就不難理解了。
總結:
為了保證資料庫的完整性和一致性(外鍵,本文未涉及),可以使用約束來達到這個目的,但是約束本身有自己的某些規則和特點,它跟其他資料庫物件並沒有不同的,都不允許同一個schema下存在同名的對象。
如果沒有按照其自身的某些規則來使用,就有可能造成某些潛在的問題。
為了規範約束的命名,在定義約束名字的時候,要嚴格遵循簡寫首碼+schema+tableName+columnName的方式來定義,如果是暫存資料表,禁止定義命名約束。
SQL Server中有關約束(constraint)的一些細節