對於設計和建立數據庫徹底是個新手?不要緊,Joe Celko, 世界上讀者數量最多的SQL做者之一,會告訴你這些基礎。和往常同樣,即便是最專業的數據庫老手,也會給他們帶來驚喜。Joe是DMBS雜誌是多年來最受 讀者喜好的做者。他在美國、英國,北歐,南美及非洲傳授SQL知識。他在ANSI / ISO SQL標準委員會工做了10年,爲SQL-89和SQL-92標準作出了傑出貢獻。程序員
介紹完表,Joe Celko會談下如何把它們放一塊兒做爲數據庫,還有什麼是實體關係和視圖。sql
在第一篇,咱們因它們是什麼並區分它們命名數據元。在第二篇,咱們用SQL裏給咱們的數據類型和簡單的行或列約束來模型化數據元。在第三篇,咱們把這些行放入表成爲實體,關係和輔助數據。數據庫
如今咱們有了基表,是時候把它們放一塊兒做爲數據庫,增長其它的架構對象混合一塊兒。這須要咱們從比一次一個表或多個表更高的層級來看。對這個一個有用的工具是實體關係圖(E-R (Entity-Relationship) diagram)。很差的消息是有不少風格的實體關係圖,其中一些變得很是複雜。這個工具的第一個版本應歸於Peter Chen在他1976年的論文裏,它仍是一個很好開始的地方。每一個系統認同實體表表現爲一個在它裏面有表名的矩形。但一些系統會放入全部列名,對於主鍵標上特殊符號做爲不一樣等等。
安全
Chen最早使用方塊牌(diamond)做爲關係表。這是個很好的主意,在它裏面很容易畫n元關係,你能夠快速看到交替的模式框和方塊牌。若是一個表同時使用,會有一些結論。例如,婚姻是丈夫和妻子之間的關係,但也有婚姻日期的數據,登記號,證婚人(presiding official)等等。架構
接下來的系統放棄了方塊牌,把關係表放入矩形,並使用只能顯示二元關係的線,但線的末端有可選或必選成員關係的標誌,0,1或更多成員關係級別,給它一些權利。這三個圖形是條形做爲1,圓形做爲0,「雞爪」做爲多個。這個百聞不如一見。工具
咱們能夠認爲講師(lecturer)傳授(teaches)課程(courses),所以課程是被講師傳授。sqlserver
這很好理解,但咱們應該表示更多的規則。例如,若是咱們有一個策略,每一個講師必須恰好只傳授一個課程?咱們能夠添加用最大1的條行標誌和第二個執行中間線的條行來表示傳授關係。這個邏輯適用於關係裏涉及的課程。性能
如今,讓咱們放寬一些規則。咱們認爲保持一個講師工做,即便他此次沒傳授任何東西,但換取這份工做安全,咱們想讓他有時候能夠傳授一個或更多的課程。圓形指向線中心,雞爪在課程框旁。學習
這一切都很好,直到咱們以爲多對多的關係,這會看起來像這樣:測試
咱們須要有一個明確的關係表,稱它「教學任務(Teaching Assignments)」,在講師和課程之間。實體關係圖更容易看懂,不須要看不少的SQL DDL語句。還有其它突出的模式,例如扇形。
我不能把部門和人員正確匹配咱們。假設常見的組織架構,這應該2個1:n分部(Divisions)的關係模型。
你能夠用多個工具從SQL DDL裏得到實體關係圖,在更高級查看其它問題模式。這裏我不會給ER模型和圖的詳細說明;如今我只想讓你知道它們。接下來,你能夠本身學習使用它們。
一旦你的表設計已經肯定,就能夠考慮數據訪問了。這一般意味着你會加索引到表。有兩類索引:主和從。主索引必須在表上執行惟一性約束,像PRIMARY KEY和UNIQUE約束,從索引添加是爲了性能提高。
SQL引擎會自動爲你建立主索引,但這個假設並不對你有好處。在SQL Server裏,在一個表上你只能有一個彙集索引,所以當心用它。例如,不用匯集索引在customer_id列做爲客戶表的主鍵,你會使用它保持物理文件按部門編號排序,由於這是你的報表分組和彙總的樣子。同時使用非彙集索引做爲查找客戶就能夠了。
索引的樹結構由在CREATE INDEX語句裏的列順序決定。這就是說:
1 CREATE INDEX Foobar ON Customers (state_code, city_name);
和
1 CREATE INDEX Barfoo ON Customers (city_name, state_code);
邏輯上是同樣的,但功能不一樣。
選擇從索引是個非徹底多項式(NP-Complete)問題,所以你不能用常規方法建立它們。最好你能夠遵循一些簡單的啓發式。第一個啓發式不要重疊索引(over-index)。初學者喜歡增長不少索引讓它們的產尋更快。這並不都是對的:查詢優化器會忽略用不到的索引,所以事實上它們變成了「無用代碼」。但當基表修改的時候,每一個插入,更新和刪除語句會修改這些無用的索引。這會是很大的負擔。
第二個啓發式若是一列從不在查詢條件裏使用(意思是說在WHERE、ON或HAVING子句裏),那它不該該在索引裏出現。
第三個啓發式你不該該有常見列前綴列表的索引。
這就是說若是你有個像這樣的索引:
1 CREATE INDEX Floob ON ExampleTable (a, b, c, d);
那實際上,下列這些索引是贈送的:
1 CREATE INDEX Floob_3 ON ExampleTable (a, b, c); 2 CREATE INDEX Floob_2 ON ExampleTable (a, b); 3 CREATE INDEX Floob_1 ON ExampleTable (a);
直接建立隱含的索引是多餘的。
下一個你常常會用的添加到架構的東西是視圖。不少程序員認爲視圖能夠幫助用戶減小重複代碼的編寫。那是對的,但視圖的最大優勢是它每次用一樣的方式作一樣的事,對每一個人。人總不會一致的。不抱怨的話,相比另外一個程序員,程序員不會實現不一樣的業務規則。Fred讀到的規格是(shipping_qty > 100))和Sam讀到的規格(shipping_qty >= 100);若是他們使用視圖的話,業務規則適用一個且只有一個方式。
一般來說,視同扮演2個方式。或者他們是本地的語句(一般一個SELECT)和擴展爲內嵌的文本,它們的定義保持在架構裏。另外一個作法是從它們的定義以物理表實現它們的定義。通常而言,當多個會話同時使用它們的時候,一個好的SQL引擎會實現視圖,這樣的話虛擬表能夠在主存裏共享,一個會話能夠屢次使用一樣的視圖。在SQL Server,你能夠在視圖上建立索引提升性能。
即便有經驗的SQL人員也不知道視圖的另外一部分; WITH CHECK OPTION子句。若是指定了WITH CHECK OPTION,視圖表必須可更新。這個作法是阻止經過WHERE子句的違反。咱們用例子解釋下:
1 CREATE VIEW NYC_Personnel 2 AS 3 SELECT * 4 FROM Personnel 5 WHERE city_name = 'New York';
如今咱們用下列語句UPDATE:
1 UPDATE NYC_Personnel 2 SET city_name = 'Birmingham'; –- everyone moved!!
UPDATE會執行,沒有任何問題,但咱們再次使用NYC_Personnel時,剛纔看到的記錄如今都消失了。這已再也不符合WHERE子句的條件!一樣,一個有(col1 = 'B')的INSERT INTO語句沒有問題,但在這個視圖裏從不會看到。
WITH CHECK OPTION會讓系統會在INSERT或UPDATE上檢查WHERE子句。若是新的或修改的行測試失敗,修改會被拒絕,視圖仍是同樣。那麼,剛纔的UPDATE語句會收到錯誤信息,你不能在特定方式裏修改特定列。
WITH CHECK OPTION能夠做爲架構級別的CHECK()子句。例如,假設有規則的酒店預約,你不能添加客人到另外一個客人已或會佔用的房間。不用直接寫約束,像這樣:
1 CREATE TABLE Hotel 2 (room_nbr INTEGER NOT NULL, 3 arrival_date DATE NOT NULL, 4 departure_date DATE NOT NULL, 5 guest_name CHAR(30) NOT NULL, 6 CONSTRAINT schedule_right 7 CHECK (H1.arrival_date <= H1.departure_date), 8 –- valid Standard SQL, but going to to work!! 9 CONSTRAINT no_overlaps 10 CHECK (NOT EXISTS 11 (SELECT * 12 FROM Hotel AS H1, Hotel AS H2 13 WHERE H1.room_nbr = H2.room_nbr 14 AND H2.arrival_date < H1.arrival_date 15 AND H1.arrival_date < H2.departure_date)));
schedule_right約束沒有問題,由於它沒有子查詢,但不少產品會檢查overlaps約束。咱們能夠不用表上的no_overlaps約束,咱們能夠在Hotel表上全部行列上構建一個視圖,並增長執行WITH CHECK OPTION的WHERE子句。
1 CREATE VIEW Valid_Hotel_Stays (room_nbr, arrival_date, departure_date, guest_name) 2 AS 3 SELECT H1.room_nbr, H1.arrival_date, H1.departure_date, H1.guest_name 4 FROM Hotel AS H1 5 WHERE NOT EXISTS 6 (SELECT * 7 FROM Hotel AS H2 8 WHERE H1.room_nbr = H2.room_nbr 9 AND H2.arrival_date < H1.arrival_date 10 AND H1.arrival_date < H2.departure_date) 11 AND H1.arrival_date <= H1.departure_date 12 WITH CHECK OPTION;
例如:
1 INSERT INTO Valid_Hotel_Stays 2 VALUES (1, '2011-01-01', '2011-01-03', 'Ron Coe');
隨後:
1 INSERT INTO Valid_Hotel_Stays 2 VALUES (1, '2011-01-03', '2011-01-05', 'John Doe');
在第2個INSERT INTO語句上,會給咱們想要的違反了WITH CHECK OPTION子句。
真正的好處是,這讓約束在聲明代碼(declarative code)裏了,且查詢優化器可使用。
視圖能夠經過隔離讓用戶看不到未受權或不須要的數據。理想地,你想爲每一個用戶建立一系列的視圖,讓他們以爲數據庫就像專門爲它們設計的同樣。這會花點時間,你須要知道如何使用SQL的第三(最被忽略的)子語言——數據控制語言(the DCL (Data Control Language))。
DCL不是個安全系統;它是SQL數據庫的簡單的控制工具。它讓數據不在安全級別外暴露。
在一個安全的系統裏,在最小的安全級別,咱們被告知超人是來自外星球的奇怪訪客,有常人不及的能力和技能。但咱們須要更高的級別來知道他是假裝的Clark Kent,偉大都市報紙的溫順記者~~~
http://www.sqlservercentral.com/articles/Database+Design/Building+a+Database+Schema/70793/