close
文章出處

對于設計和創建數據庫完全是個新手?沒關系,Joe Celko, 世界上讀者數量最多的SQL作者之一,會告訴你這些基礎。和往常一樣,即使是最專業的數據庫老手,也會給他們帶來驚喜。Joe是DMBS雜志是多年來最受 讀者喜愛的作者。他在美國、英國,北歐,南美及非洲傳授SQL知識。他在ANSI / ISO SQL標準委員會工作了10年,為SQL-89和SQL-92標準做出了杰出貢獻。


 介紹完表,Joe Celko會談下如何把它們放一起作為數據庫,還有什么是實體關系和視圖。

在第一篇,我們因它們是什么并區分它們命名數據元。在第二篇,我們用SQL里給我們的數據類型和簡單的行或列約束來模型化數據元。在第三篇,我們把這些行放入表成為實體,關系和輔助數據。

現在我們有了基表,是時候把它們放一起作為數據庫,增加其它的架構對象混合一起。這需要我們從比一次一個表或多個表更高的層級來看。對這個一個有用的工具是實體關系圖(E-R (Entity-Relationship) diagram)。不好的消息是有很多風格的實體關系圖,其中一些變得非常復雜。這個工具的第一個版本應歸于Peter Chen在他1976年的論文里,它還是一個很好開始的地方。每個系統認同實體表表現為一個在它里面有表名的矩形。但一些系統會放入所有列名,對于主鍵標上特殊符號作為不同等等。

Chen最先使用方塊牌(diamond)作為關系表。這是個很好的主意,在它里面很容易畫n元關系,你可以快速看到交替的模式框和方塊牌。如果一個表同時使用,會有一些結論。例如,婚姻是丈夫和妻子之間的關系,但也有婚姻日期的數據,登記號,證婚人(presiding official)等等。

接下來的系統放棄了方塊牌,把關系表放入矩形,并使用只能顯示二元關系的線,但線的末端有可選或必選成員關系的標志,0,1或更多成員關系級別,給它一些權利。這三個圖形是條形作為1,圓形作為0,“雞爪”作為多個。這個百聞不如一見。

我們可以認為講師(lecturer)傳授(teaches)課程(courses),因此課程是被講師傳授。

這很好理解,但我們應該表示更多的規則。例如,如果我們有一個策略,每個講師必須剛好只傳授一個課程?我們可以添加用最大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/


不含病毒。www.avast.com
arrow
arrow
    全站熱搜

    AutoPoster 發表在 痞客邦 留言(0) 人氣()