大家都在用的“關係資料庫”,竟是各種IT事故的根源

編者按:此文原題為《What I’m Telling Business People About Why Relational Databases Are So Bad》,作者是Lance Gutteridge博士,文章是其《避免IT災難》一書裡面的內容,旨在向商業人士解釋為什麼關係式資料庫是那麼多企業系統問題的根源。為了向一般受眾解釋清楚,裡面儘量避免了技術術語,但是技術受眾從中看看需要向非技術人員解釋些什麼東西也能有所收穫。

大家都在用的“關係資料庫”,竟是各種IT事故的根源

1970年代,IBM的Codd博士和Date博士提出了一種新型的資料庫。這種資料庫叫做“關係式”資料庫。現在,我從來都沒見過有任何跡象表明Codd或者Date曾經開發過任何真正的企業系統。如果有的話,我相信他們就會意識到關係式計算其實很不適合企業系統。反正又不需要讓系統正常工作,他們所需要做的只是給出人為的學術例子就行了。但任何做過企業系統的人都會明白,真正的系統要複雜得多。寫企業軟體很難。這是計算機和人類行為的交叉,要想滿足那些有時候會相互衝突的需求是很難的。

當時我正在給一個大型協會寫軟體,我記得人人都在談關係式資料庫。其實這些人都不知道關係式資料庫究竟是什麼,他們只是聽說了這個術語並且認為它很好。當時正值計算機術語進入到普通商業場所之時。很多像《Byte》、《PC Mag》這樣的雜誌開始出現到報攤,其中一些故事還被報紙報道了。資料庫的想法——把資料像檔案櫃一樣儲存起來的想法本來就挺吸引人。

然後就是“關係式”這個名字。有文章會告訴你它將如何讓你利用關係在資料中遍歷。類似於獲得專案的專案經理所在部門的名字這樣。但實際上關係式中的關係這個詞指的是關係的數學概念,也就是一組資料。如果兩個東西在一組內就可以說它們是相關的。實際上,關係的數學概念避開了相關聯物件之間的連線的概念,而是把關係定義為一組相關的東西。這樣的一個集合就是數學理論上的關係。這跟我們商業上的關係改變已經完全脫離,前者要求必定存在某種連線。如果某人告訴你一組物件對是關聯的,你一般會尋求某種連線。這樣設定一定是有什麼道理的,我們往往會設法去尋找其中隱藏的因素是什麼。模式尋找是人特有的一種本能。但是數學理論上的關係並不關心這個。哪怕只是偶然配對在一起的也會被視為一種關係。

我在紐約大學教數理邏輯的時候教過一門關係數學理論的課程。一些學生總是沒有辦法擺脫關係必須有某種規則的理念。這門理論的抽象概念的基礎是他們所不能理解的。當我聽說IBM提出了一種基於關係式計算的資料庫時我嚇了一跳。因為當時寫了很多企業軟體,我看不出把東西強制做成那麼正式和抽象的結構會有什麼好處。

在我看來這是複雜性和系統超限的罪魁禍首之一。不理解?且聽我慢慢道來。

SQL注入

你有沒有看過1920、1930年代時候的老電影裡面某人讀電報的場景?

那場景總是像這樣的:

已與DANNY私奔句號(STOP)會在馬德里度蜜月句號非常幸福句號

總是這樣,一堆的句號。這有什麼用?

要想理解這個,我們得回到布林戰爭,這是發生在20世紀之交的一場英國人和布林人為了爭奪南非殖民地而展開的骯髒戰爭。這場戰爭除了給世界引入了集中營和塹壕戰的概念以外,還是使用無線電報的第一場戰爭,部隊在前線就能透過電報接收到命令。前線是非常骯髒的地方,在20世紀之交的前線尤其如此,因為被汙泥和馬糞濺得到處都是。因為擔心紙上濺落的泥巴會被無人城逗號或者句號從而改變命令的意圖,英國戰爭部命令所有的標點符號都需要拼寫出來,比方說COMMA(逗號)。至於句號他們選擇了用STOP來表示,這是一種更為英式的“句號”表示法。

電報碼中將句號寫成STOP成為了一種實踐。當大家大聲讀出來的時候他們會本能地讀成單詞STOP而不是把它當作表示句子結束的句號。

你可能會問“這跟關係式資料庫有什麼關係?”給關係式資料庫下達的命令採用的是用可讀的文字形式。這種文字是一種叫做SQL(Structured Query Language,結構化查詢語言)的語言。就像電報用單詞STOP來斷句一樣,SQL也使用標點符號來分隔命令。就像電報一樣,從效果上來說資料庫以文字流的形式獲取命令,每句命令之間會有個STOP。

看看這個例子:

UPDATE CUSTOMER_TABLE SET NAME=“John Smith” WHERE CUSTOM_NO=2333 STOP UPDATE …

這是一條SQL語句的命令,意思是更新客戶記錄2333,將名字改為John Smith。

現在請留意一下引號之間的文字比如“John Smith”。這是哪兒來的?

好吧則其實是某人透過瀏覽器填寫表格輸入的。填表單的那個人輸入了“John Smith”然後點選提交按鈕。網站程式碼將輸入的引號之間的文字放到SQL語句裡面然後傳送給資料庫執行。

現在假設這位客戶心存惡意這樣輸入他的名字:

John” STOP DELETE CUSTOMER_TABLE STOP

如果網站把它放進SQL語句的話結果會變成這個樣子:

UPDATE CUSTOMER_TABLE SET NAME=“John” STOP DELETE CUSTOMER_TABLE STOP” STOP UPDATE …

可能你已經看出來發生了什麼變化了。這是一條將客戶表中的名字設為John的命令,會被正常執行,但只有它就會執行那位惡意客戶插入的下一條命令,這條會刪除整個表的資料。記住,這條命令是由具備更新資料庫的充分許可權的任務來完成的。

這就是所謂的“SQL注入”。

SQL注入曾經是破解網站和入侵公司最具破壞性的一項技術。超過90%的主流網站滲透都是透過SQL注入來完成的。你只需要google一下就會看到一堆的資料洩露,受累的信用卡、被吸乾的銀行賬號以及被暴露的個人資訊高達數億。

請在仔細觀察一下這裡發生的事情。資料庫命令是文字形式的,而網際網路使用者透過web表格輸入的資料會被併入該文本里面,這就給填表格的人愚弄資料庫讓後者不正確地解釋命令創造了機會。

如果說在你看來這似乎是很愚蠢的做事方式的話,你的感覺完全正確。

這大概是有史以來做出的最愚蠢的,被使用得最廣泛、代價最高昂的技術決定了。

這種軟體就相當於核電站將控制室跟參觀室設在了一起。

把兩個東西拆開,也就是一個是命令,一個是來自表格的資料,然後再合併到一起,接著反覆進行一場不要被愚弄把資料當成命令的實際部分的技術戰爭,這種做法根本毫無意義。

為什麼一開始就要把它們揉到一起呢?

這就是一個非常糟糕的架構,這個架構要為全球各個組織數十億美元的損失負責。

但是關係式資料庫的故事比這還糟。

不要重複自己

假設你有一份實現軟體的工作時間記錄表(timesheet)。這份記錄表有一個員工號。現在你要展示這份工作時間記錄表,同時你想將員工姓名找出來。但姓名是在員工表上的,所以你得建立一條像這樣的SQL語句:

SELECT EMPLOYEE WHERE EMPLOYEE。NUMBER EQUALS TIMESHEET。EMPLOYEE_NUMBER輸入

這條語句會查詢員工表將其與timesheet表進行匹配。你在這裡做的其實是定義員工與timesheet的關係。你可以說他們是透過timesheet上的員工號連線在一起的。

記住那份timesheet表格已經描述給軟體了。你說timesheet上的欄位是員工號,所以基本上此時軟體已經知道了這一關係了。但是現在你卻要很麻煩地構建一條SQL語句然後發給資料庫去執行,然後在返回一組表的行記錄再從中選出你需要的資訊。這完全是毫無必要!因為這份timesheet上與員工有關的資訊已經跟軟體溝通過了。採用關係式資料庫導致這一資訊被無視並且還得用一種完全不同的語言去重新定義這種關係。

計算機科學有一條原則叫做DRY(Don’t Repeat Yourself),意思是不要重複自己。其主要信條是每個不同的程式碼片段或資料僅在一個位置上出現。程式碼你應該編寫一次然後在計算需要的時候進行呼叫。然而,這一原則也延伸到各個消除冗餘性的地方。這是一條減少無序/複雜性的原則。相同的計算採用相同的程式碼消除了兩個不同的實現走亂步伐的可能性。

用SQL表達已經在不同的表格上被表示過的資料之間的“關係”完全就是對DRY原則的違背。在軟體裡面資訊是很寶貴的。資訊被捕捉到之後就應該物盡其用,永遠都不應該重新輸入這一資訊。你永遠都不應該輸入某個可以透過之前輸入過的地方獲取的東西。這麼做就會製造出一條資訊兩個版本搞亂的可能性。

自從關係式資料庫被提出以來,我就一直對為什麼這種似乎非常怪異的架構還能存在感到困惑。

這就好像讓你的檔案室講外語然後所有的指令都要用那門語言編寫一樣。

但情況其實還要糟糕。當你把那份timesheet儲存進關係式資料庫時,你必須把它分開,頭資訊放在一個表,所有分配工時給專案的明細記錄又是一行行記錄組成的另一張表。你必須把那張表拆開然後構建SQL來操作和儲存它們。哦是的,如果你想按照同樣的次序還原那張工時記錄表的話,你還得給每一條明細記錄行分配一個序號。當你想要要回那張表時,你得編寫SQL指令將表格聯合起來然後你還得從返回結果中選擇所有的timesheet資訊再拼湊成一份表格。

有人把這描述成

每晚回家時你得把你的車拆卸下來,把部件掛到車庫牆上,然後早上再重新組裝才能開車

這一切需要大量的額外編碼才能讓關係式資料庫與面向物件軟體這兩個不同的世界能夠對話。額外的程式碼意味著多餘錯誤的可能性。

物件—關係式阻抗不匹配

如果這還不夠糟,關係式資料庫中資料的儲存方式更適應的是1980年代的程式語言而不是現代的面嚮物件語言。在今天現代的面嚮物件語言中所有資料都得編碼成這些原子的資料型別。

這有時候被稱為“物件—關係式阻抗不匹配”。嚴重嗎?揚聲器與放大器之間的阻抗不匹配我還能理解,因為這是一種真正的物理現象。但這種背景下這個說法會製造技術上的含糊,其實應該用“一個真正愚蠢的架構的後果”來替代。

如果你想知道為什麼企業系統經常會失敗,這個不是全部單至少是主要原因之一。被迫用不同語言複製所有這些邏輯的必要性,以及用不同方式表達資料,給ERP系統製造了大量的混亂/困惑。

多年來由不同的人對一個老一點的程式碼庫進行大量補充和修改,然後試圖針對新情況進行定製,這一切會增加關係式資料庫的複雜性,專案就會被置於嚴重風險之中。

話雖如此,關係式資料庫無所不在倒是真的。多到有程式設計師從來都沒見過其中型別的資料庫,以為所有的資料庫都是關係式的。

關係式資料庫是有史以來敗壞了一個行業領域的最糟糕的技術。將如此大量的額外混亂傾倒到系統裡面是企業系統為什麼失敗會如此頻繁的主要原因。

原文連結:https://codeburst。io/what-im-telling-business-people-about-why-relational-databases-are-so-bad-6f38d3d6c995

編譯組出品。編輯:郝鵬程。