進度條

「不是工程師」後端服務的根基,淺談SQL關連式資料庫 RDBMS

你知道資料庫是什麼嗎?什麼又是SQL語法呢?會用ORM系統了還要學習SQL嗎?

作者: 進度條編輯群 更新日期:

「等等,讓我下個SQL去資料庫裡面看一下」

 

相信這句話一定最可以代表後端工程師的一句心聲,也是每天最常面對的例行公事之一。一般常見的「後端工程師 Backend Developer」,除了API接口的開發之外,最重要的就是資料庫的開發與營運維護。

 

 

但究竟資料庫是什麼,什麼又是SQL語法呢?


 

 

這要稍微往一般人使用電腦的邏輯去想,基本上我們使用電腦幾乎一定會有一個儲存的動作,無論是你在寫報告使用Word,或是你在玩遊戲儲存記錄或是虛擬人物資訊裝備等。以遊戲來說,同時上線人數1萬人,如果每個玩家的資料都用Word檔去存在硬碟,當需要使用資料的時候應該是不太容易找到,而且硬碟的讀寫速度其實並不是那麼快,所以一般作業系統會使用讀寫速度比較快的RAM(快閃記憶體)來處理。簡單的說,作業系統會先把資料從硬碟完整的搬到RAM,再讓CPU使用RAM來執行程式。當執行完了以後再回寫進硬碟。
 

 

那這樣會有什麼問題呢?就目前來講,「個人級」頂規的電腦的RAM也大概才配到32GB,但是硬碟卻有可能是3TB,幾乎是100倍。即使是伺服器主機,其實也差不多(Linode 1 CPU, 2GB RAM, 50 GB SSD 租金 10美金/月,AWS只會更貴而已)。因此你不太可能把所有的內容放進去RAM以後才開始執行。

 

延伸閱讀:學習VPS的重要性與各大Linux VPS 比較(Linode, DigitalOcean, Vultr, AWS Lightsail)


 


比較容易理解的解決方案是當某位玩家上線的時候,才把他的資料讀進RAM,當他下線以後,我們再回存。但其實這也有很多問題,比方說打到一半電腦跳電,那資料就不見了。或是這個玩家玩了10年,資料量超大,但是其實他已經玩膩了只是開上來聊天的,很多他的資料其實用不著在一開始的時候讀取,不然一堆老玩家一起上線,RAM就被吃光了。所以程式邏輯其實會相當複雜,有讀取策略、回寫硬碟策略等。到現在發展起來,連資料存法都有很多種不同的架構。

 

通常事情複雜就會需要解決,而「資料庫概念」就是一種解決方案。讓一個獨立的程式去管理你的資料,他在管理資料的時候會考量到ACID

基元性(atomicity)

一致性(consistency)

隔離性(isolation)

持續性(durability)

 


因為這是淺談,所以就不解釋這四個名詞,不過簡單來說就是保證資料的正確性,當然這中間包含了大量的程式邏輯。不過以使用者來說,只要正確使用資料庫的話就可以保證非常高程度的資料正確,尤其是同步處理大量使用者的情況。因此寫任何型態的應用程式邏輯上是不一定需要資料庫的,但是說實在的,自己撰寫處理資料幾乎可以說100%不會比使用資料庫來的好(全世界大量的使用者、2~30年以上的驗證)。所以只要跟資料有關的運用,多半都會建議使用資料庫。

 

 

不過雖然上面說的好像很複雜,但是因為已經標準化了很久。所以「資料庫」對一般後端開發者來說,就是把資料存在資料庫(Database,簡稱DB)當中,以及讀取或修改。

 

一般來說資料庫最基本的功能就是提供「新增 Create」、「查詢 Read」、「更新 Update」、「刪除 Delete」等資料維護,可以簡稱為 CRUD。資料庫你可以想成是一個大型檔案夾,每當有CRUD時,系統就必須不厭其煩地拉開抽屜,取出資料夾並作出上述的動作,來確保Data有被寫入DB中。


 

adult-back-view-data-1181345.jpg



舉例而言,像電商服務的訂單成立,或是社群網站的動態發布等等,每一個輸入的值就是對DB進行寫入或讀取的動作,當然連常見的CMS (Content Management System)後台系統 ( 例如WordPress ),其實也是以資料庫為根基衍生出的服務。

 

 

而現今主流的「資料庫類型」可分為兩種,一種是關聯式資料庫(Relational Database Management System,縮寫為RDBMS),另外一種就是NoSQL (Not only SQL)資料庫,而今天會先針對關連式資料庫做介紹。
 

 

close-up-coding-contemporary-1342460.jpg

 


資料庫本身,雖然前面以Word舉例,但是其實他比較像一個巨大的Excel表格,裡面記錄著洋洋灑灑的各種資料,但倘若一個Excel沒有辦法有效的把資訊做出有效率的統整,那不僅會降低查詢的效率,在使用上也會很不方便。所以關聯式資料庫主要就是由資料表(Table)、紀錄(Record)、欄位(Field)以及資料(Data)所構成的。就像你在整理房間,類似的東西會擺在一起,例如衣服、書籍、廚具通常都會分開擺設,當然你可以擺在一起,但是使用上總是不那麼方便(洗乾淨的衣服擺在廚房?這也是滿奇特的選擇。)

 

 

同理,以電商系統來說,如果所有的資訊都記錄一起,不僅顯得資訊雜亂無章,更容易發現裡面的資料會產生太多的無效率性。例如你今天上架了一個商品,產品熱銷一小時就收到了1千筆訂單,結果不小心發現商品資訊貨號打錯,倉庫出貨反應對不到商品。這時你當然可以1千筆訂單慢慢一筆一筆改,但是也可以在資料庫欄位、表單設計上面加一點巧思,只要不到幾秒鐘一次改完。
 

 

例如商品條碼號為987654321,上架打錯成123456789

 


無效率設計:一個資料表

訂單編號 訂購者 商品名稱 商品條碼號 數量
Order001 王大明 iPhone 2000 123456789 1
Order002 李小明 iPhone 2000 123456789 2

這樣的好處是看起來直覺,但是如果今天有1000筆資料錯誤,就要改1000次

 

 

較有效率設計:拆成兩個資料表
 

商品編號 商品名稱 商品條碼號 剩餘數量
Product001 iPhone 2000 123456789 10000
Product002 Macbook Pro 2200 15" 220078987 2000

 

訂單編號 訂購者 商品編號 數量
Order001 王大明 Product001 1
Order002 李小明 Product001 2

 

這樣的壞處是要看完整資料比較麻煩,要取得王大明到底買了什麼需要先抓到他買的商品編號(Product001),再利用商品編號去找出商品名稱,有點像「連連看」。但是今天如果商品條碼號錯誤,只需要改一個值就好(只出現1次),方便很多。

 

此外,可能大家會想說「無效率版」總共只有10格資料欄位(不含標題)。但是「有效率版」用掉了16格資料欄位,感覺比較浪費空間。但其實那是因為只有2筆訂單的關係。如果用1000筆訂單來看。
 

「無效率版」,每筆訂單耗掉5格,1000筆就是5000格

「有效率版」,每筆訂單耗掉4格,1000筆就是4000格 + 商品欄位的 8格 = 4008格。所以其實只要量大到一定,下面消耗的格數就會比較少,而格數就可以想成是記憶體空間。


你也可以用簡單的數學來計算這個問題。
 

4 x Row + 8  > 5 x Row
請問 Row 最小等於多少時,這個式子成立。


答案是 Row  9 以上,所以在這樣的設計下只要有9筆訂單就會比較節省空間。
(真實情況要看你的欄位怎麼設計,一般不會設計的這麼簡單。)

 

 

所以一但今天資料變得巨量,意味著在進行新增、修改、刪除、查詢等動作時,「有很大的機會」會有較低的服務表現。所以關連式資料庫的基礎,就是透過欄位關聯的方式,來打破一張大表的概念,一張表拆分為多張表格,以增加儲存管理時的效率。而連結表格最重要的,就是代表每一列的為一值,我們稱作為「主鍵」 (Primary Key, 可縮寫為PK)。例如上面商品table的商品編號Product001,就是PK。而其他表所記錄的它表PK,就是所謂的外鍵 (Foreign Key, FK)。所以以上面的範例來看,雖然紀錄的是同一個值Product001,但是在商品table就是PK,在訂單table就是FK。FK必須要有PK才能成立,PK可以自己單獨存在。PK所對應的FK也不見得只有一個,可以有多張表都使用同一個PK。這聽起來有點複雜,不過我們後面的系列文章會再解釋。

 

 

所以回顧一下關連式資料庫,每一張紀錄的表單就是所謂的資料表Table,像是訂單資料、商品資料等等,以商品資料表而言,而每一筆橫向的資料就是一筆商品紀錄,而像敘述、規格等等Key值,就是所謂的欄位,最後每一個裡的文字,當然就是資料囉。而剛剛講到的新增、修改、刪除、查詢等動作執行時會用的語法,就是SQL(Structured Query Language:結構化查詢語言)。SQL語法是後來統整出來的標準,大部分的「關聯性資料庫」都遵守其規範,但是就像JavaScript 與瀏覽器之間的關係,雖然遵守規範,但不代表是完全符合,也不代表沒有獨特的功能與用法。


所以即使是SQL已經相當成熟的現在,用同樣的SQL語句在資料庫A可以執行,但是在資料庫B還是可能會報錯。或是在資料庫A、B都可以執行,但是出來的結果不同還是有可能的(不過可以放心,常用語句大多都會相同)。
 

 

不過以現在的流行趨勢來說,使用ORM系統相當主流。
所謂的ORM 系統就是像Ruby on Rails裡面的 Active Record, PHP Laravel 裡面的 Equlent。
在這些ORM系統裡面你多半不用直接撰寫SQL語句,而是用一般應用程式的語法來撰寫。

比方說如果你想要讓你的網頁讀取資料庫裡面的資料呈現,假設為Products 資料表
純SQL的寫法會是:

SELECT * from Products

然後要包裝成程式語句用字串的方式送出

DBconnect.excute("SELECT * from Products")

其中DBconnect.excute是虛擬碼,代表與資料庫通訊的API


但是如果以ORM 來說的話會是下面的寫法:

Ruby on Rails:
Product.all()


Laravel:
Product::all()


所以會發現簡單很多而且明確。不過ORM系統並不是有什麼額外管道可以從資料庫讀取資料,只是ORM系統會在內部執行的時候把 Product.all() 換成類似 DBconnect.excute("SELECT * from Products") 去執行罷了。因此很多情況如果ORM 系統效率不好的時候,還是要去研究它究竟幫我們轉換出了什麼語句,這時候SQL語法與資料庫知識就很重要了。
 

 

 

account-black-and-white-commerce-209137.jpg
 

 

相信在以上的介紹之後,大家對資料庫應該都有了基本上的概念了,但並非所有的架構都適合使用關聯式資料庫,畢竟結構化的關聯查詢,其實也是有著許多先天上的弱勢,例如當系統越複雜時,表示建立關聯的表格也會越來越多,資料庫結構就會複雜化;而當每一張表格裡PK和FK變多時,查詢和處理的過程和效率就會降低,舉例來說,像是查一個Data一次要組合6~7張表才能得到,這樣的效能通常不是很令人開心。不過這也是有解決方法,廣義來說的話就是用Cache 暫存的概念。但是當今天用到Cache的時候,就又會有資料同步問題。所以程式就會越來越複雜。

 

延伸閱讀:
[不是工程師] 讓網站速度飛快的秘密,你了解什麼是網頁快取(Cache)嗎?

 

 

但資料庫的結構化卻是一個必然的趨勢,在結構愈趨複雜的狀況下,如何做出應對的衍生,就是開發團隊必須具備的Know how,像是資料庫的分區管理,或是查詢介面搭配NoSQL資料庫等,也許都是相應的解法。而這也是專業系統分析人員的價值所在。

 

最後廣告一下,如果對資料庫設計和網站架設有興趣的話,可以考慮參加我們的Ruby on Rails課程。課程中包含詳細的網站架設與資料庫設計教學,內容涵蓋SQLite, MySQL, PostgreSQL,以及最後的募資平台(含資料表設計),可以參考看看喔!

線上程式教學課程: 快速開發,從頭教起的Ruby on Rails後端之旅



 


最後,如果你喜歡我們的文章,別忘了到我們的FB粉絲團按讚喔!!

Small logo

進度條編輯群

進度條編輯團隊