- SQL學習指南(第3版)
- (美)艾倫·博利厄
- 2732字
- 2022-04-13 16:19:52
1.1 數據庫簡介
數據庫就是一組相關信息。例如,電話簿就是一個數據庫,其中包含了生活在某一地區內所有人的姓名、電話號碼和地址。盡管電話簿肯定是最為普及且常用的數據庫,但它也存在以下問題。
●查找電話號碼的時候費時間,尤其是電話簿里包含大量聯系人的時候。
●電話簿僅使用姓/名作為索引,所以要想查找居住在特定地址的聯系人時就不實用了,盡管理論上是可行的。
●從電話簿被印刷好的那一刻起,隨著地區居民的流動、個人電話號碼的更改、住址的更換,電話簿中的信息會變得越來越不準確。
電話簿的種種缺點同樣體現在所有的手工數據存儲系統上,比如存儲在文件柜中的患者記錄。由于紙質數據庫使用不便,一些早先開發的計算機應用程序就是數據庫系統,采用了計算機化的數據存儲和檢索機制。由于數據庫系統使用電子化代替紙張存儲數據,因此能夠更快地檢索數據、以多種方式編制索引,并為用戶群提供即時信息。
早期的數據庫系統用磁帶存儲被管理的數據。磁帶的數量通常遠多于磁帶機,因此在請求特定數據時,需要由技術人員手動裝卸磁帶。由于那個時代的計算機內存很小,對同一數據的多次請求往往需要多次讀取磁帶。盡管這些數據庫系統比起紙質數據庫有了很大的改進,但與如今的數據庫技術相差甚遠(現代數據庫系統能夠管理PB級的數據,利用服務器集群進行訪問,每個服務器在高速內存中緩存的數據可達數十GB,不過我講的可能有點超前了)。
1.1.1 非關系型數據庫系統
本節介紹了關系型數據庫出現之前的一些背景信息,如果讀者急于學習SQL,可以直接跳到下一節。
在計算機化數據庫系統發展的最初幾十年里,數據以各種形式存儲并展現給用戶。例如,在層次數據庫系統中,以一個或多個樹形結構來表示數據。圖1-1展示了以樹形結構表示的George Blake和Sue Smith的銀行賬戶數據。

圖1-1 賬戶數據的層次化視圖
George和Sue的數據樹都包含了各自的賬戶以及交易信息。層次數據庫系統提供了定位特定客戶信息樹的工具,并能夠遍歷該樹找到所需的賬戶和/或交易。樹中的每個節點都具有0個或1個父節點,以及0個、1個或多個子節點。這種配置稱為單根層次結構。
另一種數據管理方式是網狀數據庫系統,它表現為多個記錄以及定義不同記錄之間關系的多個鏈接。圖1-2展示了George和Sue的賬戶在此系統中的視圖。

圖1-2 賬戶數據的網狀視圖
為了查找Sue的MoneyMkt賬戶交易信息,需要執行以下步驟:
1.查找Sue Smith的客戶記錄;
2.沿著Sue Smith的客戶記錄鏈接找到其賬戶列表;
3.遍歷賬戶列表直至找到MoneyMkt賬戶;
4.沿著MoneyMkt賬戶記錄鏈接找到其交易列表。
網狀數據庫系統的一個值得注意的特性是圖1-2最右側的一組product記錄。注意,每個product記錄(Checking、Savings等)都指向一個account記錄列表,以指定這些賬戶記錄的產品類型。因此account記錄可以通過多個入口(customer記錄或product記錄)進行訪問,這使得網狀數據庫具有多根層次的特點。
層次數據庫和網狀數據庫依然活躍在今天,不過通常只能在大型機世界中找到。另外,層次數據庫已在目錄服務領域中重獲新生,比如Microsoft的Active Directory和開源的Apache Directory Server。然而,在20世紀70年代初,一種表示數據的全新方式開始生根,這種方式更為嚴謹,且易于理解和實現。
1.1.2 關系模型
1970年,IBM研究院的E.F.Codd博士發表了一篇題為“A Relational Model of Data for Large Shared Data Banks”(大型共享數據銀行的數據關系模型)的論文,提出使用數據表集合來表示數據,但相關實體之間并不是用指針來導航的,而是借助冗余數據來鏈接不同表中的記錄。圖1-3展示了George和Sue在關系模型中的賬戶信息。

圖1-3 賬戶數據的關系視圖
圖1-3中包含了4個數據表:Customer、Product、Account、Transaction。首先查看圖中頂部的Customer表,該表共有3列:cust_id(客戶的ID號)、fname(客戶的名字)、lname(客戶的姓氏)。Customer表共有2行,分別為George Blake 和Sue Smith 的數據。數據表的列數視不同的數據庫服務器而異,但數量通常足夠大,無須為此擔心(比如Microsoft SQL Server允許最多1,024列的數據表)。至于數據表的行數,相較于受數據庫服務器的限制,更多是受限于物理設備(比如,可用的磁盤空間大小)和可維護性(比如,多大的數據表才不會造成管理方面的麻煩)。
關系型數據庫中每個數據表都包含能夠唯一標識某一行的信息[稱為主鍵(primary key)],以及完整描述實體所需的額外信息。再來看Customer表,每位客戶的cust_id列都保存著不同的數字;比如,George Blake可由客戶ID #1來唯一標識。其他客戶都不能夠獲得這個標識符,在Customer表中,不再需要其他信息來定位George Blake的數據。
每種數據庫服務器都提供了相應的機制來生成用作主鍵的唯一數字,所以你不用操心跟蹤已分配的數字。
盡管也可以選擇使用fname列和lname列共同作為主鍵(由兩個或多于兩個列組成的主鍵稱為復合主鍵),但在銀行賬戶中出現兩個或多個人同名的情況是很常見的事。因此,我選擇cust_id列作為Customer表的主鍵。
在本例中,選擇fname/lname作為主鍵,稱之為自然鍵(natural key),選擇cust_id作為主鍵,則稱之為代理鍵(surrogate key)。使用哪一種鍵取決于數據庫設計人員,但在本例中,該怎么選擇是顯而易見的,因為人的姓氏(last name)可能會改變(比如有的人結婚后使用其配偶的姓氏),而主鍵列在被賦值后是絕不允許被修改的。
一些數據表中還包含了導航到其他數據表的信息,這就是之前提到的“冗余數據”。例如,Account表中的cust_id列包含了已開設過賬戶的客戶的唯一標識,product_cd列則包含了該賬戶所關聯產品的唯一標識。這些列稱為外鍵(foreign key),其作用與層次化和網狀的賬戶信息形式中不同實體之間的連線一樣。如果要查找特定賬戶記錄,想知道開戶人的詳細信息,可以獲取cust_id列的值,用該值在Customer表中查詢相應的行(用關系型數據庫的專業術語來說,該過程稱為連接,我們會在第3章對其進行介紹,在第5章和第10章展開深入討論)。
同樣的數據存儲多次,看起來似乎是一種浪費,但是對于該存儲什么樣的冗余數據,關系模型十分清晰。例如,在Account表中加入一列,用于已開設賬戶的客戶的唯一標識符,這種做法沒有問題,但如果在表中再增加客戶的名字和姓氏,就不合適了。如果客戶改名了,需要確保數據庫中僅有一處保存了客戶的姓名;否則,可能出現數據在一處更改了,而在另一處沒有更改,造成數據庫中數據不可靠。適合保存姓名的是Customer表,只有cust_id的值應該來自其他表。在一列中包含多種信息,比如在name列中包含姓氏和名字,或是在address列中包含街道、城市、州和郵政編碼信息,同樣不合適。改進數據庫設計以確保獨立信息僅出現在一處(外鍵除外)的過程稱為規范化(normalization)。
回到圖1-3中的4個數據表,你也許想知道如何使用這些表來查找George Blake的支票賬戶(checking account)交易。首先,在Customer表中找到George Blake的唯一標識符。然后,在Account表中找到滿足以下條件的行:cust_id列包含George的唯一標識符,product_cd列與Product表中name列等于"Checking"的行匹配。最后,定位到Transaction表中account_id列與Account表中唯一標識符匹配的行。這個過程看起來挺復雜,其實使用SQL語言的話,一個命令就能搞定,很快你就會看到。
1.1.3 術語
前幾節介紹了一些新術語,是時候給出正式的定義了。表1-1中列出了本書后續要用到的術語及其定義。
表1-1 術語及其定義

- Kubernetes實戰
- 騰訊iOS測試實踐
- Microsoft Dynamics 365 Extensions Cookbook
- Mastering Concurrency in Go
- Web交互界面設計與制作(微課版)
- HTML5+CSS3基礎開發教程(第2版)
- Visual Basic程序設計教程
- Python編程與幾何圖形
- Learning AngularJS for .NET Developers
- 速學Python:程序設計從入門到進階
- Vue.js應用測試
- Clojure for Java Developers
- 零基礎學Python編程(少兒趣味版)
- OpenCV 3計算機視覺:Python語言實現(原書第2版)
- SwiftUI極簡開發