官术网_书友最值得收藏!

2.2 數(shù)據(jù)庫相關(guān)知識

后端產(chǎn)品的很多功能都是圍繞數(shù)據(jù)的存儲(chǔ)、流轉(zhuǎn)和運(yùn)算等操作進(jìn)行的。因此,對于后端產(chǎn)品經(jīng)理而言,了解數(shù)據(jù)和數(shù)據(jù)庫知識是非常有必要的。

2.2.1 數(shù)據(jù)

1.數(shù)據(jù)的概念

數(shù)據(jù),就是能夠被智能設(shè)備(計(jì)算機(jī)、智能手機(jī)等)識別、存儲(chǔ)和加工處理的信息的載體。在計(jì)算機(jī)系統(tǒng)中,各種文本、數(shù)字、語音、圖形、圖像等,統(tǒng)稱為數(shù)據(jù)。數(shù)據(jù)經(jīng)過加工后就成為信息。數(shù)據(jù)是計(jì)算機(jī)世界的運(yùn)算對象,也是輸出產(chǎn)物。

2.數(shù)據(jù)類型

數(shù)據(jù)類型,就是一組性質(zhì)相同的值的集合,以及定義在這個(gè)值集合上的一組操作的總稱。我們也可以這樣理解:數(shù)據(jù)類型就是對具體數(shù)據(jù)或變量的約束和歸類。每一種數(shù)據(jù)都有唯一的一個(gè)數(shù)據(jù)類型(需注意,變量也可以被指定為缺省類型)。

數(shù)據(jù)類型的出現(xiàn),一方面是為了把數(shù)據(jù)分成所需內(nèi)存大小不同的種類(這樣在編程的時(shí)候,只有在使用大的數(shù)據(jù)時(shí)才申請大內(nèi)存,可以充分利用內(nèi)存),另一方面是確定數(shù)據(jù)的屬性(比如一個(gè)或一串字母可能代表不同的含義,需要對之加以定義,才可方便運(yùn)用)。

不同編程語言規(guī)定的數(shù)據(jù)類型不同,常見的數(shù)據(jù)類型有整型、字符串型、浮點(diǎn)型、布爾型等。

(1)整型

整型變量表示的是整數(shù)類型的數(shù)據(jù),其類型說明符一般為int。其常被分為長整型、短整型等。整形變量屬于數(shù)字,因此是可以進(jìn)行數(shù)學(xué)運(yùn)算的,如下所示。

在該例子中,z等于3。

(2)字符串型

字符串型可以理解為文本型。該類型的值不能直接做數(shù)學(xué)運(yùn)算,只能用于展示。字符串之間可以拼接。在Java語言中使用string表示字符串類型,在C語言中則使用char表示。字符串可以是任意內(nèi)容,比如“12”。

(3)浮點(diǎn)型

浮點(diǎn)型就是小數(shù)類型的數(shù)據(jù),一般用float或double表示浮點(diǎn)型。比如,1.2是浮點(diǎn)型數(shù)字,23e2是科學(xué)計(jì)數(shù)法形式的浮點(diǎn)型數(shù)字。

(4)布爾型

布爾型可以簡單地理解為判斷真假的類型,一般用bool或boolean表示。布爾型的值只有兩個(gè):false(假)和true(真)。

需要注意的是,在寫與數(shù)據(jù)相關(guān)的需求文檔的時(shí)候,產(chǎn)品經(jīng)理可以對數(shù)據(jù)庫中的數(shù)據(jù)類型進(jìn)行定義。如表2-3所示,在該需求文檔中對數(shù)據(jù)的定義就包括“字段類型”這一列。

表2-3 需求文檔中對數(shù)據(jù)的定義

不過,如果產(chǎn)品經(jīng)理在寫需求文檔時(shí)不確定相關(guān)數(shù)據(jù)的類型,或者不懂如何區(qū)分?jǐn)?shù)據(jù)類型,那就最好不要明確定義,以免出錯(cuò)。在這種情況下,我們可以以備注的形式加以說明,比如備注“該字段為整數(shù),范圍為[-100,10000]”,程序員也就明白了。

2.2.2 數(shù)據(jù)結(jié)構(gòu)

1.數(shù)據(jù)結(jié)構(gòu)概念

數(shù)據(jù)結(jié)構(gòu),顧名思義,就是數(shù)據(jù)之間的結(jié)構(gòu)關(guān)系。數(shù)據(jù)結(jié)構(gòu)是對數(shù)據(jù)存儲(chǔ)和組織方式的規(guī)范,是對現(xiàn)實(shí)中事件的運(yùn)行結(jié)構(gòu)或運(yùn)行方式的模型化。在通常情況下,精心選擇的數(shù)據(jù)結(jié)構(gòu)可以帶來更高的運(yùn)行或者存儲(chǔ)效率。比如,數(shù)據(jù)庫的存入和讀取就依賴數(shù)據(jù)結(jié)構(gòu)。

2.數(shù)據(jù)結(jié)構(gòu)的構(gòu)成

數(shù)據(jù)結(jié)構(gòu)包括三個(gè)方面的內(nèi)容:數(shù)據(jù)邏輯結(jié)構(gòu)、數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)、數(shù)據(jù)運(yùn)算,如圖2-7所示。

圖2-7 數(shù)據(jù)結(jié)構(gòu)的三方面內(nèi)容

(1)數(shù)據(jù)邏輯結(jié)構(gòu)

數(shù)據(jù)邏輯結(jié)構(gòu),反映的是數(shù)據(jù)元素之間的邏輯關(guān)系,與數(shù)據(jù)在計(jì)算機(jī)中的存儲(chǔ)位置無關(guān)。

數(shù)據(jù)邏輯結(jié)構(gòu),一般分為集合結(jié)構(gòu)、線性結(jié)構(gòu)、樹狀結(jié)構(gòu)和圖狀結(jié)構(gòu)四類。集合結(jié)構(gòu)中的任何兩個(gè)數(shù)據(jù)元素之間都沒有邏輯關(guān)系,組織形式松散;線性結(jié)構(gòu)中的結(jié)點(diǎn)按邏輯關(guān)系依次排列形成一個(gè)“鎖鏈”,線性結(jié)構(gòu)還可以劃分為表、數(shù)組、隊(duì)列、棧、串等結(jié)構(gòu);樹形結(jié)構(gòu)具有分支、層次特性,其形態(tài)有點(diǎn)類似于自然界中的樹;圖狀結(jié)構(gòu)中的結(jié)點(diǎn)按邏輯關(guān)系互相纏繞,任何兩個(gè)結(jié)點(diǎn)都可以彼此鄰接。

(2)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)

當(dāng)我們處理數(shù)據(jù)之后,就需要存儲(chǔ)數(shù)據(jù),這涉及數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),即物理結(jié)構(gòu)。數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)有順序、鏈接、索引、散列等多種。

(3)數(shù)據(jù)運(yùn)算

數(shù)據(jù)運(yùn)算就是基于數(shù)據(jù)結(jié)構(gòu)進(jìn)行的運(yùn)算,其具體實(shí)現(xiàn)依賴于數(shù)據(jù)的存儲(chǔ)結(jié)構(gòu)。數(shù)據(jù)運(yùn)算可以簡單理解為,對已經(jīng)存儲(chǔ)好的數(shù)據(jù)進(jìn)行增加、查找、編輯、刪除等操作。數(shù)據(jù)運(yùn)算是數(shù)據(jù)結(jié)構(gòu)的一個(gè)重要方面。

(4)三者之間的關(guān)系

一種數(shù)據(jù)邏輯結(jié)構(gòu)在計(jì)算機(jī)里可以用不同的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn),數(shù)據(jù)運(yùn)算是基于數(shù)據(jù)邏輯結(jié)構(gòu)和存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn)的,三者相輔相成。

3.常見的數(shù)據(jù)結(jié)構(gòu)舉例

(1)數(shù)組

所謂數(shù)組,就是有序的元素序列,即有限數(shù)量的類型相同的變量的集合。按數(shù)組元素的類型不同,數(shù)組又可分為數(shù)值數(shù)組、字符數(shù)組、指針數(shù)組等。

比如 char CHB[]={"1","2","3"}的結(jié)構(gòu),就是數(shù)組的表示方式,其含義就是定義CHB為字符串的一維數(shù)組,包含的值是字符串形式的“1”“2”“3”。這樣就通過一個(gè)簡單的組合形式,表達(dá)了一組有共性的數(shù)據(jù)。

二維數(shù)組是一種簡單的數(shù)據(jù)結(jié)構(gòu),如圖2-8所示。

圖2-8 二維數(shù)組示例

這個(gè)二維數(shù)組的結(jié)構(gòu)與一張有行有列的表很像:每一行代表一個(gè)對象,每一列代表對象的一個(gè)屬性。盡管二維數(shù)組很適合存儲(chǔ)表數(shù)據(jù),但是當(dāng)你需要根據(jù)某個(gè)條件從數(shù)組中查詢數(shù)據(jù)時(shí),就要遍歷每一行數(shù)據(jù),而當(dāng)數(shù)據(jù)量大的時(shí)候,這將花費(fèi)許多時(shí)間,服務(wù)器性能就會(huì)變差。這時(shí)候就需要考慮使用其他數(shù)據(jù)結(jié)構(gòu)。

(2)樹結(jié)構(gòu)

樹結(jié)構(gòu)是另一種重要的非線性數(shù)據(jù)結(jié)構(gòu)。直觀地看,它是數(shù)據(jù)元素(在樹中被稱為結(jié)點(diǎn))按分支關(guān)系組織起來的結(jié)構(gòu)。一切具有層次關(guān)系的問題都可用樹結(jié)構(gòu)來描述,比如家庭成員關(guān)系、頁面各級菜單關(guān)系等。

數(shù)據(jù)庫索引是樹結(jié)構(gòu)的一個(gè)重要應(yīng)用,索引可以提高數(shù)據(jù)庫查詢速度。常見的關(guān)系型數(shù)據(jù)庫的索引使用的數(shù)據(jù)結(jié)構(gòu),多是 B+Tree 或者 B-Tree(二者都是樹結(jié)構(gòu)的一種),例如MySQL的索引使用的是B+Tree,Oracle和Sysbase的索引使用的是B-Tree。

我們來了解一下為什么索引要使用樹結(jié)構(gòu)的存儲(chǔ)方式來實(shí)現(xiàn)。

我們都知道,數(shù)據(jù)庫文件是存儲(chǔ)在硬盤上的,每次讀取數(shù)據(jù)庫都需要在硬盤上搜索,而 B+Tree 數(shù)據(jù)結(jié)構(gòu)的查詢方式不是遍歷,而是從樹根部對比著向下遞推做二分查找,查詢次數(shù)不會(huì)高于樹的層數(shù),所以查詢速度更快。

如圖2-9所示,該樹結(jié)構(gòu)有15個(gè)節(jié)點(diǎn)。

圖2-9 樹結(jié)構(gòu)示意圖

如果在該樹結(jié)構(gòu)中查找“208”節(jié)點(diǎn),那么該數(shù)據(jù)的查找過程是按照如下方式進(jìn)行的。

①從根節(jié)點(diǎn)(也就是“136”節(jié)點(diǎn))開始查找。

②判斷出 136<208,所以在“136”節(jié)點(diǎn)的右子樹中查找,找到“398”節(jié)點(diǎn)。

③判斷出398>208,所以在“398”節(jié)點(diǎn)的左子樹中繼續(xù)查找,找到“250”節(jié)點(diǎn)。

④判斷出250>208,所以在“250”節(jié)點(diǎn)的左子樹中繼續(xù)查找,找到“200”節(jié)點(diǎn)。

⑤判斷出200<208,所以在“200”節(jié)點(diǎn)的右子樹中繼續(xù)查找,然而“200”節(jié)點(diǎn)沒有右子樹,因此不可能找到“208”節(jié)點(diǎn)(如果其存在的話,一定在“200”節(jié)點(diǎn)的右子樹上)。

結(jié)論就是:查找完畢,不存在“208”節(jié)點(diǎn)。

那么,如何從圖2-9中查找“40”節(jié)點(diǎn)呢?查找過程如下。

①從根節(jié)點(diǎn)“136”節(jié)點(diǎn)開始查找。

②判斷出136>40,所以在“136”節(jié)點(diǎn)的左子樹中查找,找到“80”節(jié)點(diǎn)。

③判斷出80>40,所以在“80”節(jié)點(diǎn)的左子樹中查找,找到“40”節(jié)點(diǎn)。

④判斷出40=40,所以該節(jié)點(diǎn)找到了!

提取“40”節(jié)點(diǎn)中存儲(chǔ)對象的對應(yīng)數(shù)組行號索引。有了這個(gè)行號索引,想獲得這行數(shù)據(jù)就能立即拿到(具體實(shí)現(xiàn)的方式此處不做討論)。

需要注意的是,樹結(jié)構(gòu)還有很多變種,比如“堆”結(jié)構(gòu)就是一種特殊的樹形數(shù)據(jù)結(jié)構(gòu)。

(3)棧

棧也是一種重要的數(shù)據(jù)結(jié)構(gòu)。它最大的特點(diǎn)是只能在某一端插入和刪除。它按照先進(jìn)后出的原則存儲(chǔ)數(shù)據(jù),先進(jìn)入的數(shù)據(jù)被壓入棧底,最后進(jìn)入的數(shù)據(jù)在棧頂,需要讀數(shù)據(jù)的時(shí)候從棧頂開始讀數(shù)據(jù)(即最后一個(gè)數(shù)據(jù)被第一個(gè)讀出來),出棧的順序與入棧的順序相反。這就像是一摞蒸籠,一層一層放入小籠包,而當(dāng)把小籠包拿出來的時(shí)候只能從上往下進(jìn)行。因此凡是遇到有這樣邏輯需求的數(shù)據(jù),就可以套用該數(shù)據(jù)類型。棧結(jié)構(gòu)如圖2-10所示。

圖2-10 棧結(jié)構(gòu)示意圖

(4)隊(duì)列

隊(duì)列也是一種特殊的線性表。隊(duì)列與棧相反,是按照“先進(jìn)先出”和“后進(jìn)后出”的原則組織數(shù)據(jù)的。當(dāng)隊(duì)列中沒有元素時(shí),被稱為空隊(duì)列。隊(duì)列的結(jié)構(gòu)如圖2-11所示。

圖2-11 隊(duì)列結(jié)構(gòu)示意圖

(5)其他數(shù)據(jù)結(jié)構(gòu)

其他數(shù)據(jù)結(jié)構(gòu)如散列表、圖形結(jié)構(gòu)等都是很重要的數(shù)據(jù)結(jié)構(gòu)。單純按照查詢速度來看,在這幾種數(shù)據(jù)結(jié)構(gòu)中,數(shù)組和鏈表結(jié)構(gòu)最慢,樹結(jié)構(gòu)較快,散列表最快。關(guān)于其他數(shù)據(jù)結(jié)構(gòu),本書不再具體介紹。

2.2.3 數(shù)據(jù)模型

1.數(shù)據(jù)模型的概念

數(shù)據(jù)模型,是為了更好地描述一組數(shù)據(jù)的概念和定義,而對現(xiàn)實(shí)世界數(shù)據(jù)特征進(jìn)行的抽象和模擬。在數(shù)據(jù)庫中數(shù)據(jù)的存儲(chǔ)方式依賴于數(shù)據(jù)模型。要想更有序、安全地把數(shù)據(jù)保存到數(shù)據(jù)庫,并從數(shù)據(jù)庫中高效讀取,必然要?jiǎng)?chuàng)建成熟有效的數(shù)據(jù)模型。因此,數(shù)據(jù)模型是數(shù)據(jù)庫系統(tǒng)的理論核心和基礎(chǔ)。數(shù)據(jù)模型所描述的內(nèi)容包括三個(gè)部分:數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)操作、數(shù)據(jù)約束。

(1)數(shù)據(jù)結(jié)構(gòu)

數(shù)據(jù)結(jié)構(gòu)的有關(guān)概念筆者在前面講解過了。理論上數(shù)據(jù)模型可以使用任意的數(shù)據(jù)結(jié)構(gòu),但考慮到性能問題,就要做出不同選擇。比如使用數(shù)組結(jié)構(gòu),在進(jìn)行遍歷操作時(shí)速度會(huì)相當(dāng)快,但是在進(jìn)行新增與刪除操作時(shí)速度就稍差了。相比之下,如果使用鏈表數(shù)據(jù)結(jié)構(gòu),在進(jìn)行新增與刪除操作時(shí),速度就快很多。

(2)數(shù)據(jù)操作

數(shù)據(jù)操作主要定義了在相應(yīng)的數(shù)據(jù)結(jié)構(gòu)上的操作類型和操作方式。常見的數(shù)據(jù)操作是對數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行增加、刪除、修改、查找等操作。刪除和修改操作都是建立在查找操作的基礎(chǔ)上的,所以完美的數(shù)據(jù)模型應(yīng)該是具有較高的插入效率和查找效率的。

(3)數(shù)據(jù)約束

數(shù)據(jù)約束主要用來描述數(shù)據(jù)庫中數(shù)據(jù)結(jié)構(gòu)之間的語法、詞義聯(lián)系以及彼此之間的相互約束和制約關(guān)系(比如MySQL使用外鍵保證數(shù)據(jù)之間的數(shù)據(jù)完整性)。

2.數(shù)據(jù)模型的種類

按不同的應(yīng)用層次,數(shù)據(jù)模型分成三種:概念數(shù)據(jù)模型、邏輯數(shù)據(jù)模型、物理數(shù)據(jù)模型。

(1)概念數(shù)據(jù)模型

概念數(shù)據(jù)模型(CDM)的抽象性最高,關(guān)注現(xiàn)實(shí)世界與數(shù)據(jù)世界的關(guān)系,不關(guān)注數(shù)據(jù)的底層細(xì)節(jié),為構(gòu)建邏輯數(shù)據(jù)模型奠定基礎(chǔ)。概念數(shù)據(jù)模型必須換成邏輯數(shù)據(jù)模型,才能在數(shù)據(jù)庫管理系統(tǒng)中實(shí)現(xiàn)。

在概念數(shù)據(jù)模型中,最常見的是E-R模型、擴(kuò)充的E-R模型、面向?qū)ο竽P?,以及謂詞模型。其中E-R模型圖就是實(shí)體聯(lián)系模型(Entity Relationship Diagram),如圖2-12所示,是用矩形框表示實(shí)體(比如“產(chǎn)品”是一個(gè)實(shí)體),用橢圓圖框表示實(shí)體的屬性(比如“產(chǎn)品名稱”是產(chǎn)品的一個(gè)屬性),用實(shí)心線段將屬性與相應(yīng)關(guān)系的實(shí)體連接起來,用菱形框表示實(shí)體之間的聯(lián)系成因,在菱形框內(nèi)寫明聯(lián)系名(比如“上架”是連接產(chǎn)品與銷售網(wǎng)站的成因),并用實(shí)心線段分別與有關(guān)實(shí)體連接起來,同時(shí)在實(shí)心線段旁標(biāo)上聯(lián)系的類型。

圖2-12 E-R模型示例圖

(2)邏輯數(shù)據(jù)模型

邏輯數(shù)據(jù)模型(LDM)是直接面向數(shù)據(jù)庫的邏輯結(jié)構(gòu),涉及計(jì)算機(jī)系統(tǒng)和數(shù)據(jù)庫管理系統(tǒng)。這種數(shù)據(jù)模型架起了用戶和系統(tǒng)之間的橋梁。

在邏輯數(shù)據(jù)模型中,較常見的是層次模型、網(wǎng)狀模型、關(guān)系模型,其中最常見的是關(guān)系模型,其對應(yīng)的數(shù)據(jù)庫被稱為關(guān)系型數(shù)據(jù)庫,如MySQL、DB2、Oracle等。

(3)物理數(shù)據(jù)模型

物理數(shù)據(jù)模型(PDM)是在邏輯數(shù)據(jù)模型的基礎(chǔ)上,考慮各種具體的技術(shù)實(shí)現(xiàn)因素及硬件因素,進(jìn)行數(shù)據(jù)庫體系結(jié)構(gòu)設(shè)計(jì),真正實(shí)現(xiàn)數(shù)據(jù)在數(shù)據(jù)庫中的存儲(chǔ)。

因此物理數(shù)據(jù)模型的設(shè)計(jì)內(nèi)容較為詳細(xì),包括數(shù)據(jù)庫的存儲(chǔ)過程、操作、觸發(fā)、視圖和索引表等。

2.2.4 數(shù)據(jù)庫

1.數(shù)據(jù)庫的概念

數(shù)據(jù)庫是存儲(chǔ)在計(jì)算機(jī)系統(tǒng)內(nèi)的,結(jié)構(gòu)化的、集成的、相關(guān)的、共享的、可控制的數(shù)據(jù)集合。數(shù)據(jù)庫就是儲(chǔ)存數(shù)據(jù)的倉庫,只不過這個(gè)倉庫的數(shù)據(jù)必須按照一定的格式存放,因?yàn)閿?shù)據(jù)的存放必須便于數(shù)據(jù)的查找??梢赃@樣理解:將數(shù)據(jù)按照一定的規(guī)則,結(jié)構(gòu)化地儲(chǔ)存在一個(gè)相當(dāng)于磁盤的地方,這個(gè)地方就是數(shù)據(jù)庫。

數(shù)據(jù)庫由數(shù)據(jù)庫管理系統(tǒng)管理。數(shù)據(jù)庫管理系統(tǒng)是一種操縱和管理數(shù)據(jù)庫的大型軟件,用于建立、使用和維護(hù)數(shù)據(jù)庫,簡稱DBMS。數(shù)據(jù)庫管理系統(tǒng)具有存儲(chǔ)、截取、安全保障、備份等基礎(chǔ)功能。

在諸多數(shù)據(jù)庫中,最常見的是關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫。

2.關(guān)系型數(shù)據(jù)庫

(1)關(guān)系型數(shù)據(jù)庫的概念

關(guān)系型數(shù)據(jù)庫,是一種基于實(shí)體聯(lián)系模型(如E-R模型)的數(shù)據(jù)庫。世間萬物都是通過實(shí)體與屬性、實(shí)體與實(shí)體之間的關(guān)系折射出的關(guān)系模型。關(guān)系型數(shù)據(jù)庫定義的就是實(shí)體與屬性的集合。比如人有年齡、姓名等屬性。

關(guān)系型數(shù)據(jù)庫有MySQL、Oracle、SQL Server、DB2、Informix等,其中最常見的是MySQL。由于MySQL使用類似二維表格的存儲(chǔ)形式,因此其和頁面報(bào)表的組合比較完美,搭配PHP和Apache可以組成良好的開發(fā)環(huán)境。

此外,比較常見的關(guān)系型數(shù)據(jù)庫還有Oracle,在數(shù)據(jù)量很大的時(shí)候,其非常有用。比如擁有千萬量級以上數(shù)據(jù)的數(shù)據(jù)庫,通常會(huì)使用Oracle。

(2)范式

提到關(guān)系型數(shù)據(jù)庫,就不得不說范式。范式是數(shù)據(jù)庫設(shè)計(jì)規(guī)范方面的一個(gè)概念,是圍繞著關(guān)系型數(shù)據(jù)庫而形成的規(guī)則和約束。范式有很多條,前三條范式是關(guān)系型數(shù)據(jù)庫創(chuàng)建的基礎(chǔ)。

①第一范式:每一列不能有重復(fù)的屬性值

第一范式(1NF)是指數(shù)據(jù)表中的每一列不能有多個(gè)值,換言之,每一列的屬性的值都必須是不可再分的。如果實(shí)體中的某個(gè)屬性有多個(gè)值,必須將之拆分為不同的屬性。不滿足第一范式的數(shù)據(jù)表示例,如表2-4所示。

表2-4 不滿足第一范式的數(shù)據(jù)表示例

一個(gè)人的電話號碼可能同時(shí)有座機(jī)號碼和手機(jī)號碼兩種形式,因此應(yīng)該將“電話號碼”屬性分為“座機(jī)號碼”和“手機(jī)號碼”兩個(gè)屬性才能滿足第一范式,如表 2-5所示。

表2-5 滿足第一范式的數(shù)據(jù)表示例

②第二范式:每個(gè)行的數(shù)據(jù)不重復(fù)

第二范式(2NF)和第三范式是容易混淆的。第二范式是在滿足第一范式的前提下提出的,主要包含兩點(diǎn):其一,一個(gè)數(shù)據(jù)表必須有一個(gè)主鍵(主鍵是由一個(gè)或多個(gè)字段組成的,區(qū)分?jǐn)?shù)據(jù)的唯一性,主鍵的概念會(huì)在下文繼續(xù)講到);其二,沒有包含在主鍵中的列必須完全依賴于主鍵,而不能只依賴于主鍵的一部分。如果不滿足第二范式,容易產(chǎn)生冗余數(shù)據(jù),如表2-6所示。

表2-6 不符合第二范式的數(shù)據(jù)表示例

一個(gè)訂單中可以包括多種商品,所以在表2-6中,“訂單編號”和“商品編號”才是主鍵,“折扣”“商品購買數(shù)量”等屬性完全依賴于主鍵(即當(dāng)主鍵確定下來時(shí),這些屬性就是明確的),但是“商品單價(jià)”“商品名稱”等屬性與“訂單編號”沒必然關(guān)系,它們只依賴于“商品編號”,所以該表不符合第二范式。這種情況造成的最直觀的問題就是,如果有 50 萬個(gè)訂單都買了鼠標(biāo),那么鼠標(biāo)的單價(jià)和名稱就要在表中出現(xiàn)50萬次,這就造成了數(shù)據(jù)冗余,因此應(yīng)將“商品單價(jià)”“商品名稱”從原表拆分出去,從而將一個(gè)表變?yōu)閮蓚€(gè)表,如表2-7、表2-8所示。

表2-7 將商品信息拆分出一個(gè)表

表2-8 修改后的訂單詳情表

③第三范式:即直接性,數(shù)據(jù)表的每一列都要和主鍵直接相關(guān),而不能間接相關(guān)。

第三范式(3NF)要求數(shù)據(jù)表中不能存在“非主鍵列 A 依賴于非主鍵列 B,而非主鍵列 B 依賴于主鍵”的情況。比如,有一個(gè)“爸爸信息表”,里面的屬性有:爸爸、兒子、女兒、女兒的小熊、女兒的氣球,這就不符合第三范式,因?yàn)椤鞍职帧迸c“女兒的小熊”“女兒的氣球”都不是直接的相關(guān)。在這種情況下,需要將其改成兩個(gè)表。其一是“爸爸信息表”,包含屬性:爸爸、兒子、女兒;其二是“女兒信息表”,包含屬性:女兒、女兒的小熊、女兒的氣球。該案例的修改前后示意圖如圖2-13所示。

圖2-13 “爸爸信息表”修改前后示意圖

3.非關(guān)系型數(shù)據(jù)庫

對于大量的半結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù),人們針對其存儲(chǔ)、并發(fā)以及擴(kuò)展能力而設(shè)計(jì)出了非關(guān)系型數(shù)據(jù)庫,像Google的Bigtable、Amazon的Dynamo,以及Apache的Hbase等。

非關(guān)系型數(shù)據(jù)庫是松散的、無嚴(yán)格結(jié)構(gòu)規(guī)范的,被稱為 NoSQL,是傳統(tǒng)關(guān)系型數(shù)據(jù)庫的有效補(bǔ)充,用于對存儲(chǔ)要求高、并發(fā)處理較多的場合。常見的非關(guān)系型數(shù)據(jù)庫有MongoDB、HBase等,它們以鍵值對(key-value)的形式存儲(chǔ),是類似JSON的格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類型。非關(guān)系型數(shù)據(jù)庫的存儲(chǔ)形式如下。

在非關(guān)系型數(shù)據(jù)庫中,MongoDB 是最著名的,其功能非常豐富,最大的特點(diǎn)是其支持的查詢語言非常強(qiáng)大,有點(diǎn)類似于面向?qū)ο蟮牟樵冋Z言,幾乎可以實(shí)現(xiàn)類似關(guān)系數(shù)據(jù)庫單表查詢的絕大部分功能,而且還支持對數(shù)據(jù)建立索引。

非關(guān)系型數(shù)據(jù)庫都是針對某些特定的應(yīng)用場景而設(shè)計(jì)的,因此該類數(shù)據(jù)庫往往具有極高的選擇性和強(qiáng)大的性能。

4.為什么要了解數(shù)據(jù)庫

后端產(chǎn)品經(jīng)理的很多工作都是圍繞數(shù)據(jù)進(jìn)行的。一方面,基礎(chǔ)數(shù)據(jù)的維護(hù)和用戶行為數(shù)據(jù)的采集本身就是后端產(chǎn)品的工作范疇;另一方面,后端產(chǎn)品的多數(shù)功能設(shè)計(jì)都是圍繞數(shù)據(jù)的存取、運(yùn)算、獲取、推送等進(jìn)行的。隨著業(yè)務(wù)不斷發(fā)展,數(shù)據(jù)庫在擴(kuò)大、數(shù)據(jù)量在增加,數(shù)據(jù)需求的調(diào)研和分析越來越復(fù)雜,如果后端產(chǎn)品經(jīng)理不了解數(shù)據(jù)庫,就會(huì)讓自己的工作難以進(jìn)展。比如,當(dāng)后端產(chǎn)品經(jīng)理要拉取數(shù)據(jù)做驗(yàn)證的時(shí)候,因?yàn)閿?shù)據(jù)存儲(chǔ)在不同的數(shù)據(jù)表中,就需要反復(fù)進(jìn)行聯(lián)表查詢,在這種情況下,很難有程序員能夠隨時(shí)協(xié)助,如果后端產(chǎn)品經(jīng)理自己掌握了數(shù)據(jù)的查詢和分析方法,就可以更高效地開展工作。

那么,作為后端產(chǎn)品經(jīng)理,要對數(shù)據(jù)庫了解到什么程度呢?筆者認(rèn)為達(dá)到以下兩點(diǎn)即可。

(1)理解數(shù)據(jù)庫的作用原理,以便更好地與開發(fā)人員互動(dòng)溝通,理解開發(fā)人員的思路。

(2)會(huì)用基礎(chǔ)的 SQL 查詢,懂得數(shù)據(jù)表的創(chuàng)建、數(shù)據(jù)去重規(guī)則等知識,就可以更好地參與到數(shù)據(jù)問題的分析和數(shù)據(jù)方案的設(shè)計(jì)中。

2.2.5 常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng):MySQL

1.MySQL的簡介

(1)MySQL的特點(diǎn)

MySQL 是最流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一,其將數(shù)據(jù)保存在不同的表中,而不是將所有數(shù)據(jù)放在一個(gè)大倉庫內(nèi),這樣就增加了查詢速度并提高了靈活性。MySQL 數(shù)據(jù)庫的存在,使得變量的增加、刪除、修改、查找操作只需在數(shù)據(jù)庫層面完成即可,不用到代碼層面處理,既安全又高效。

由于其體積小、速度快、總體擁有成本低,尤其是其開放源碼,使得一般中小型網(wǎng)站的開發(fā),都使用MySQL作為數(shù)據(jù)庫管理系統(tǒng)。初學(xué)者學(xué)習(xí)數(shù)據(jù)庫往往都是從學(xué)習(xí)MySQL開始的。

(2)MySQL的安裝

MySQL的安裝界面如圖2-14所示。

圖2-14 MySQL的安裝界面

首先要在PC端安裝MySQL服務(wù)器,然后通過公司的數(shù)據(jù)庫地址、密碼連接上數(shù)據(jù)庫(具體可以找開發(fā)人員協(xié)助完成)。這樣你就可以進(jìn)入到數(shù)據(jù)庫管理系統(tǒng)中,查看其中的數(shù)據(jù)庫、數(shù)據(jù)庫中的各個(gè)表,以及表里的數(shù)據(jù)。

2.MySQL的數(shù)據(jù)庫、數(shù)據(jù)表、應(yīng)用程序等之間的關(guān)系

(1)MySQL的結(jié)構(gòu)關(guān)系

MySQL 數(shù)據(jù)庫管理系統(tǒng)可以管理多個(gè)數(shù)據(jù)庫,每個(gè)數(shù)據(jù)庫可以創(chuàng)建很多個(gè)表,每個(gè)表描述一種實(shí)體與多個(gè)屬性的關(guān)系,每個(gè)屬性就是一個(gè)字段,每個(gè)字段有不同的取值。數(shù)據(jù)庫管理系統(tǒng)、數(shù)據(jù)庫、表、字段、值之間的關(guān)系如圖2-15所示。

圖2-15 數(shù)據(jù)庫管理系統(tǒng)、數(shù)據(jù)庫、表、字段、值之間的關(guān)系

(2)數(shù)據(jù)庫與應(yīng)用程序之間的關(guān)系

數(shù)據(jù)庫與數(shù)據(jù)庫之間可以交換信息,數(shù)據(jù)庫與應(yīng)用程序之間也可以交換信息。數(shù)據(jù)庫與應(yīng)用程序的對應(yīng)關(guān)系如圖2-16所示。

圖2-16 數(shù)據(jù)庫與應(yīng)用程序信息交換對應(yīng)關(guān)系示意圖

3.MySQL拆表存儲(chǔ)

理論上,每個(gè)實(shí)體至少對應(yīng)一個(gè)數(shù)據(jù)表,表中的字段就是實(shí)體的屬性或衍生屬性,但是實(shí)際上一個(gè)實(shí)體的屬性往往被拆分到多個(gè)數(shù)據(jù)表中存儲(chǔ)。在這種情況下,一旦需要查詢,就要通過聯(lián)表才能完成。既然聯(lián)表很麻煩,那么為什么非要拆表存儲(chǔ)呢?其實(shí)這和前面提到的范式有很大關(guān)系。

在實(shí)際情況中,一個(gè)實(shí)體所具有的屬性會(huì)有很多,如果將所有屬性放入一個(gè)表中,那么其產(chǎn)生的數(shù)據(jù)表往往也就包含很多信息。當(dāng)這個(gè)數(shù)據(jù)表中的數(shù)據(jù)量很大的時(shí)候,其缺陷就非常明顯:首先是數(shù)據(jù)冗余,其次是維護(hù)(比如編輯)困難。因此龐大的數(shù)據(jù)表要分表存儲(chǔ),該理念和第二范式的思想是一致的。

例如有一個(gè)描述用戶發(fā)布消息的表,每當(dāng)用戶發(fā)表一條消息,就需要把他的昵稱、性別、姓名、消息等數(shù)據(jù)都插入到表中,這樣一條一條數(shù)據(jù)累積下去,如果在未來的某一天里,用戶突然修改自己的昵稱,那么我們要遍歷整張表,去更新他的每條數(shù)據(jù)中的昵稱。在這種情況下,修改是不現(xiàn)實(shí)的,所以就需要把原來的表中的用戶信息和消息信息分別存儲(chǔ)。

拆表之后,通過姓名就可以查到用戶的個(gè)人信息,又可以通過用戶的 ID 查到他發(fā)出的所有消息。

4.數(shù)據(jù)表

(1)數(shù)據(jù)表的基本信息

數(shù)據(jù)存儲(chǔ)于數(shù)據(jù)表中,數(shù)據(jù)表中每一條基本的數(shù)據(jù)都由數(shù)據(jù)類型、字段(也叫變量或者參數(shù))、字段值等組成。以下面的數(shù)據(jù)表結(jié)構(gòu)信息(局部)為例。

該部分內(nèi)容表達(dá)的主要信息如下。

①表名是“s_rule”。

②各個(gè)字段都有默認(rèn)值,比如“rule_type_id”的默認(rèn)值為“0”。

③各個(gè)字段都不允許為空值。

④規(guī)定了各個(gè)字段的數(shù)據(jù)類型,比如“rule_id”的數(shù)據(jù)類型為11位整數(shù)。

⑤各字段帶有注釋,比如“rule_id”的注釋為“主鍵ID”。

(2)數(shù)據(jù)表的主鍵和外鍵

①主鍵

MySQL的每張表只能有一個(gè)主鍵(前面談范式的時(shí)候提到過)。主鍵即主關(guān)鍵字,可以由一個(gè)或多個(gè)字段組成,并且主關(guān)鍵字的列不能包含空值。一般使用該表的 ID做主鍵。主鍵的最大特征是其具有唯一性,即由主鍵標(biāo)示的各行數(shù)據(jù)不重復(fù)。

主鍵主要用于和其他表進(jìn)行外鍵關(guān)聯(lián),以及對本表的修改與刪除。當(dāng)兩個(gè)表需要進(jìn)行關(guān)聯(lián)時(shí),主關(guān)鍵字用于在一個(gè)表中引用來自另一個(gè)表中的特定記錄。

②外鍵

如果表A的主關(guān)鍵字也是表B中的字段,則該字段稱為表B的外鍵。表A稱為主表,表B稱為從表。外鍵可以保持?jǐn)?shù)據(jù)一致性、完整性,使兩張表形成關(guān)聯(lián)。關(guān)于主鍵、外鍵的例子如圖2-17所示。

圖2-17 關(guān)于主鍵、外鍵的例子

(3)數(shù)據(jù)表的索引

①索引的概念

在講解數(shù)據(jù)結(jié)構(gòu)的樹結(jié)構(gòu)時(shí),筆者曾提到過索引。索引是由開發(fā)人員用代碼創(chuàng)建的,對數(shù)據(jù)庫表中的一個(gè)或多個(gè)字段值進(jìn)行排序的一種結(jié)構(gòu)。數(shù)據(jù)庫索引好比是一本書的目錄,能提升數(shù)據(jù)庫的查詢速度。例子如下所示。

如果“id”沒有做索引,這個(gè)查詢操作就必須遍歷整個(gè)表,直到找到“id”等于“44”的這一行為止;如果“id”做了索引,則直接在索引表里找出“id”等于“44”,就可以直接得知這一行的位置,更快找到這一行。

②索引不能太多

索引有助于提高查詢速度,但不是越多越好,原因如下。

第一,創(chuàng)建和維護(hù)索引需要開發(fā)人員寫代碼,其耗費(fèi)的時(shí)間隨著數(shù)據(jù)量的增加而增加。

第二,當(dāng)對表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時(shí)候,索引也要進(jìn)行動(dòng)態(tài)的維護(hù),這樣就增加了維護(hù)的成本。

第三,索引需要占用物理存儲(chǔ)空間。

因此,一個(gè)數(shù)據(jù)表的索引不宜過多,建議最多5個(gè)。索引不可能滿足所有的場景,但是可以滿足絕大部分的場景。

5.數(shù)據(jù)庫相關(guān)需求方案的注意事項(xiàng)

后端產(chǎn)品的很多產(chǎn)品需求方案都會(huì)涉及數(shù)據(jù)表的創(chuàng)建、聯(lián)表查詢等,因此在需求方案設(shè)計(jì)的過程中要注意如下一些細(xì)節(jié)。

(1)建表的時(shí)候可以增加預(yù)留字段。因?yàn)楫?dāng)數(shù)據(jù)量大的時(shí)候很難再增加新字段,所以數(shù)據(jù)增長較快的表一定要預(yù)留幾個(gè)字段的空位,便于日后數(shù)據(jù)表的擴(kuò)展。

(2)當(dāng)一個(gè)表無法再加字段的時(shí)候,可以增加擴(kuò)展表。一般以原表的表名加上后綴“_ext”作為擴(kuò)展表的表名,兩個(gè)表通過原表 ID 進(jìn)行關(guān)聯(lián)。比如原表的表名為“order_goods_shipping”,其擴(kuò)展表的表名就可以用“order_goods_shipping_ext”。

(3)對數(shù)據(jù)表新增字段的時(shí)候,要考慮該表已有數(shù)據(jù)的初始化處理。比如,將歷史數(shù)據(jù)對應(yīng)該新字段的值,全部初始化為空字符串或某一個(gè)默認(rèn)值。

(4)統(tǒng)一規(guī)范數(shù)據(jù)表的表名前綴,舉例如表2-9所示。

表2-9 數(shù)據(jù)表名前綴舉例

(5)命名要規(guī)范,具體的規(guī)范舉例如下。

①庫名、表名、字段名、索引名,統(tǒng)一使用小寫字母、數(shù)字,必要的時(shí)候,以下畫線連接,比如“訂單商品數(shù)據(jù)表”可以命名為“order_goods_table”。

②庫名、表名、字段名加起來不要超過30個(gè)字符。

③庫名、表名、字段名不要單獨(dú)使用數(shù)據(jù)庫的常用關(guān)鍵字,像“l(fā)ock”“time”“date”“return”“user”等,可以加前、后綴,比如“sale_date”。

④命名不能使用特殊字符,如“%”“-”等。

(6)產(chǎn)品經(jīng)理在了解數(shù)據(jù)庫之后,設(shè)計(jì)方案的思路會(huì)清晰許多,但是最終的方案還是由開發(fā)人員綜合評定的。如果產(chǎn)品經(jīng)理將一些字段、表名等內(nèi)容寫進(jìn)方案的話,要謹(jǐn)慎核實(shí),并和開發(fā)人員做好溝通。

2.2.6 使用基本的SQL語言進(jìn)行數(shù)據(jù)庫查詢

1.數(shù)據(jù)庫查詢介紹

SQL是結(jié)構(gòu)化查詢語言(Structured Query Language)的縮寫,是一種數(shù)據(jù)庫查詢和程序設(shè)計(jì)語言,用于存取數(shù)據(jù)以及查詢、更新和管理關(guān)系型數(shù)據(jù)庫系統(tǒng),同時(shí)也是數(shù)據(jù)庫腳本文件的擴(kuò)展名。

SQL 是數(shù)據(jù)庫通用的操作語言(不同版本存在著細(xì)微差異),語句很簡單,運(yùn)算速度很快,是最重要的關(guān)系型數(shù)據(jù)庫操作語言,并且它的影響已經(jīng)超出數(shù)據(jù)庫領(lǐng)域,在其他領(lǐng)域(比如人工智能領(lǐng)域的數(shù)據(jù)檢索)也受到重視和采用。

2.基礎(chǔ)SQL語句舉例

(1)數(shù)據(jù)查詢語句

①基礎(chǔ)的查詢語句

對產(chǎn)品經(jīng)理來說,數(shù)據(jù)查詢語句是比較簡單的,也是使用次數(shù)最多的。最基本的查詢語句是“SELECT+目標(biāo)字段+FROM+表名”,表示從表中查詢數(shù)據(jù)的目標(biāo)字段。例子如下。

如果同時(shí)查詢多個(gè)字段,則目標(biāo)字段之間用“,”隔開。例子如下。

如果查詢?nèi)孔侄?,則用“*”代替具體的字段。

②配合函數(shù)查詢

SELECT語句配合函數(shù)可以滿足更多需求。常用的函數(shù)包括但不限于如下。

COUNT():統(tǒng)計(jì)記錄數(shù)。例子如下。

AVG():計(jì)算字段值的平均值。例子如下。

SUM():計(jì)算字段值的總和。例子如下。

MAX():查詢字段的最大值;MIN():查詢字段的最小值。例子如下。

③配合篩選條件查詢

基本的篩選條件用“WHERE”連接,句式為“SELECT+目標(biāo)字段+FROM+表名+WHERE+條件”。例如,我們要從“學(xué)生表”中查詢年齡為14歲的學(xué)生的姓名,代碼如下。

④對查出的結(jié)果排序

基本的排序用“ORDER BY”表示,句式為“SELECT+目標(biāo)字段+FROM+表名+ORDER BY+排序字段+DESC/ASC”。例如,我們要從“學(xué)生表”中查詢學(xué)生的全部信息,并按照年齡降序排列,代碼如下。

⑤對結(jié)果分組

用“GROUP BY”語句進(jìn)行分組,例子如下。

⑥字段拼接輸出

用“CONCAT”可以拼接多個(gè)字符串。例如,我們要將employee_tbl表中的用戶年齡、姓名、工作日等連接在一起,代碼如下。

⑦聯(lián)表查詢

聯(lián)表查詢的句式為“左表+JOIN+右表+ON+關(guān)系字段”。在具體應(yīng)用中,JOIN往往與前綴結(jié)合,比如“INNER JOIN”表示內(nèi)聯(lián)接,即查找兩張表共同擁有的字段;“LEFT JOIN”叫左聯(lián)接,以左表(“JOIN”前的那張表)為主,如果右表有共同字段,則一并返回,如果沒有,則為空;另外還有“FULL JOIN”“RIGHT JOIN”等。例子如下。

注意,在該例句中,“order_table a”意為:用“a”來代表“order_table”。

⑧其他常用的SQL查詢語句,如表2-10所示。

表2-10 其他常用的SQL查詢語句

(2)數(shù)據(jù)表的更改

產(chǎn)品經(jīng)理一般不會(huì)更改正式數(shù)據(jù)庫的數(shù)據(jù),但是可以了解相關(guān)的知識點(diǎn)。數(shù)據(jù)的更改主要包括插入(新增)、刪除、更新、創(chuàng)建等。

①插入記錄

句式為“INSERT INTO+表+VALUES”,用于在表中插入記錄,例如我們要在表中添加一行張三的記錄,代碼如下。

②新增一列

用“ALTER ADD”來增加表的列(即字段)。例如,我們要在“student_table”表中添加一列“title(職位)”,代碼如下。

注意:“varchar(10)”是對插入的字段“title”的數(shù)據(jù)類型的定義。

③更新數(shù)據(jù)

句式“UPDATE+表+SET”用于更新表的數(shù)據(jù)。例如,我們要讓table1表中的所有人的工資都增長20%,代碼如下。

④數(shù)據(jù)表的創(chuàng)建、回收

創(chuàng)建表的句式:“CREATE TABLE+表名”。例子如下。

回收表的句式:“DROP TABLE+表名”。注意,執(zhí)行“DROP TABLE”語句后,表被放在回收站中,并不是被直接刪除。如果想要直接刪除表(不進(jìn)回收站),則使用句式“DROP TABLE+表名+PURGE”。

3.SQL使用注意事項(xiàng)

(1)提升查詢速度

①查詢時(shí),盡量只列出需要查詢的字段,不建議查詢?nèi)?,以避免影響查詢速度。例如下面的代碼,會(huì)影響查詢速度。

建議將其優(yōu)化為如下代碼。

②盡量避免進(jìn)行全表掃描。如果我們只需要返回一條結(jié)果,可以使用“LIMIT 1”指令,能夠提高效率。

(2)在某些情況下索引無法被使用

①SQL 中的“OR”指令表示并列關(guān)系,比如“WHERE customer_id='250'or amount=3.96”。

用“OR”分割開的條件,若其前面的條件有索引,后面的條件沒有索引,那么前面的索引也不會(huì)被用到,該查詢?nèi)允且M(jìn)行全表掃描的。

②負(fù)向查詢不會(huì)使用索引,比如“NOT”“NOT IN”“NOT LIKE”“<>”“!=”“!=”“!<”等。例如,下面的代碼不會(huì)使用索引。

(3)MySQL中的NULL和空字符串

在SQL語句中,NULL通常指的是不適用的、無意義的、無效的、不存在或之后將要加入的數(shù)據(jù),而空字符串('')表示該字符串的值就是空(注意空字符串的單引號之間是沒有空格的)。比如,電話號碼字段是NULL的時(shí)候,可理解為“該人員是否有電話號碼是未知的”;而用空字符串表示的話,就可理解為“該人員沒有電話號碼”。

在SQL語句中,判斷NULL的SQL語句應(yīng)該使用is NULL或者is not NULL,但判斷空字符串則應(yīng)使用“=”或者“<>”。比如一條數(shù)據(jù)的A字段值為NULL,此時(shí)使用關(guān)鍵查詢條件“A is NULL”,是可以查出該條數(shù)據(jù)的;但是關(guān)鍵查詢條件使用“A='NULL'”,就查不到該數(shù)據(jù)。

主站蜘蛛池模板: 遵化市| 贺州市| 天全县| 吴旗县| 墨玉县| 延长县| 鹤壁市| 颍上县| 西乌珠穆沁旗| 乃东县| 南乐县| 广昌县| 高雄市| 青川县| 南昌县| 安新县| 什邡市| 康平县| 陕西省| 苍梧县| 盘锦市| 桂阳县| 合作市| 彭州市| 普洱| 兴义市| 辛集市| 溧水县| 徐闻县| 鹤庆县| 申扎县| 鲜城| 信阳市| 息烽县| 孟村| 东丰县| 隆回县| 墨竹工卡县| 平顺县| 大同市| 墨脱县|