SQL,NoSQL 以及數據庫的實質



SQL,NoSQL 以及數據庫的實質

     在之前的一些博文裏(比如這篇),我多次提到關係式數據庫和 SQL 的缺陷。我覺得它們是製造了問題又自己來解決,而且沒有解決好。現在有了點時間,我就把這裏面的細節稍微說一下,希望有一定的啓發作用。

描述性語言的侷限性

    當我指出 SQL 的問題時,總是避免不了有人反駁說:“SQL 是描述性的語言。你只告訴它 What,而不是告訴它 How。”我發現總是有人對一些我多年前就聽膩了,看透了的“廣告詞”執迷不悟,而現在這同樣的事又發生在 SQL 身上。他們沒有發現,我不但能實現 SQL,而且已經實現過比 SQL 強大很多的語言(邏輯式語言),所以我其實早已看透了所有這些語言的實質,我知道那些廣告詞在很大程度上是誤導。

    現在我就來分析一下 SQL 與邏輯式語言之間的關係,並且找出這類“描述性語言”共同的弱點。

Prolog 與人工智能的沒落

    可以說,“只告訴它 What,而不是告訴它 How”,只是一個不切實際的妄想,而且它並不是 SQL 首創的口頭禪。在 SQL 誕生兩年以前,有人發明了 Prolog,著名的“邏輯式語言運動”的先鋒。Prolog 使用了與 SQL 非常類似的廣告詞,聲稱自己能夠一勞永逸的解決人工智能和自動編程的問題,這樣人們不需要寫程序,只需要告訴電腦“想要什麼”,然後電腦就能自動生成算法,自動生成代碼來解決這問題。

    不需要理解數據結構和算法,直接告訴電腦需要什麼,它就給你答案,這是多麼美妙的事情。世界上總是有很多這種類似“減肥藥”的東西,每一個都聲稱自己是“不需運動,不需節食,一個星期瘦 20 斤!”然而由於人類的智力和經驗參差不齊,總會有人上當。Prolog 當年的風頭之大,以至於它被日本政府採用並且大力推廣,作爲他們所謂的“第五代計算機”的編程語言。可惜的是,減肥藥畢竟是減肥藥,科學道理決定了 Prolog 必定失敗,以及“人工智能冬天”(AI winter)的到來。

    爲什麼 Prolog 會失敗呢?這是因爲 Prolog 雖然“終究”有可能自動解決某些問題,然而由於它的算法複雜度太高,所以沒法在我們有生之年完成。說白了,Prolog 採用的“計算”方式就是“窮舉法”。爲了得到用戶“描述”的問題的答案,而不需要用戶指定具體的數據結構和算法,Prolog 必須對非常大的圖狀解空間進行完全的遍歷(Prolog 採用深度優先搜索)。而這種解空間的“狀態”數量往往是與程序運行時路過的分支數目成指數關係,這就決定了 Prolog 雖然“最終”可能找到問題的答案,卻很有可能在地球毀滅之前都沒法完成它的搜索。而且由於 Prolog 無法表達真正意義上的“邏輯否”操作,所以對於很多問題它永遠無法得到正確的答案(這是一個非常深入的問題,30 多年的研究,仍然沒有結果)。

    過於具體的細節我不想在這裏解釋,你只需要明白的是我絕不是在信口開河。在 Indiana 的日子裏,我重新實現,並且擴展了一種與 Prolog 類似的邏輯式語言,叫做 miniKanren。它也就是 Dan Friedman 的新書《The Reasoned Schemer》的主題。在兩三個星期的時間內,我不但完全重寫了 miniKanren 的代碼(代碼見這裏),而且爲它加入了一種技術叫做 constraint logic programming,並且在那之上實現了一個非常乾淨利落的“邏輯否”操作。經過這番動手操作,我對 miniKanren 和邏輯式語言的工作方式可以說是瞭如指掌。雖然 miniKanren 比起 Prolog 更加優雅,而且在搜索算法上有所改進(廣度優先而非深度優先),它本質上採用的計算方式也是一樣的:窮舉法。所以在很多時候它的效率很低,用法不靈活。像 Prolog 一樣,miniKanren 並不能用來解決很多實際的問題。有些很簡單的 Scheme 代碼,你卻不能把它翻譯成等價的 miniKanren。然而就是這樣一種語言,比起 SQL 的表達能力,其實也是天上地下。所以在實現並且擴展了 miniKanren 這樣的“智能語言”之後再來看 SQL,對於我來說就像是在解剖一隻青蛙。

    這裏只舉一個例子,說明我所看到的所謂“描述性語言”的侷限,看不懂的人可以暫時跳過。在 IU 的時候總有一些人喜歡用 miniKanren 來實現 Haskell 和 OCaml 的Hindley-Milner 類型系統(HM 系統)。HM 那種最基本的基於 unification 的類型推導,miniKanren 確實能做到,因爲 miniKanren,Prolog 和 HM 系統一樣,都是基於Robinson unification 算法。這種算法雖然精巧,表達能力卻是非常有限的。如果遇到一些必要的擴展,比如 HM 系統所需要的 let-polymorphism,你就需要對 miniKanren 語言本身進行擴展。也就是說,你不再是用 miniKanren 實現你的算法,而是用一種過程式或者函數式語言(比如 Scheme)把你的算法加到 miniKanren 裏面作爲“語言特性”,然後再利用這個你剛實現的新特性來“實現”你的算法。於是你就發現,其實 miniKanren 本身並沒有足夠的表達力表示完整的 HM 類型推導算法。如果 miniKanren 必須經過 Scheme 擴展才能表達 HM 算法,那麼比起直接的 Scheme 實現,miniKanren 並沒有任何優勢。一個新的語言特性要有價值,它必須能夠在很多地方使用。然而這些 miniKanren 的擴展,每一個只能用到一個地方。所以它們其實完全失去了作爲語言特性的價值,還不如直接寫一段 Scheme 代碼。

   這也就是爲什麼雖然我很感謝 miniKanren 教會了我邏輯編程的原理,然而我實現過的所有強大的類型系統(有些的能力大大超過 HM 系統),全都是用最普通的過程式或者函數式語言。“描述性語言”聲稱的好處,其實在這種關鍵時刻總是微乎其微,還不如調用普通語言的庫代碼。

從 Prolog 到 SQL

    扯了這麼多 Prolog 和 miniKanren 的事情,這跟關係式數據庫和 SQL 的討論到底有何關係呢?其實,這些東西是有非常深層次的內在聯繫的。一個有趣的事情是,miniKanren 裏面的“Kanren”一詞並不是一個英語國家的人名,而是日語“関連”(かんれん,讀作 kanren)。而“邏輯式語言”的另一個名字,其實叫做“關係式語言”(relational language)。

   在數學上,“關係”(relation)意味着“沒有方向”,意味着“可逆”。然而具有諷刺意味的是,所謂的“關係式數據庫”並不具有這種可逆計算的能力。Prolog 和 miniKanren 其實是比 SQL 強大很多的語言,是真正的“關係式語言”,它們能夠在比較大的程度上完成可逆計算。比如在 miniKanren 裏面,你可以使用這樣“查詢操作”:如果 x+y 等於 10,y 等於 2,那麼 x 等於幾?很多 Prolog 和 miniKanren 可以表達的查詢,SQL 沒法表示。SQL 其實只能用於非常簡單的,有“明確方向”的查詢操作,基本上就像 Lisp 的 filter 函數。由於這些侷限性,再加上很多其他的設計失誤(比如語法像英語,組合能力弱),它只適合會計等人員使用,一旦遇到程序員需要的,稍微複雜一點的數據結構,它就沒法表達了,而且會像 Prolog 一樣引起諸多的性能問題。

  由於 SQL 比起邏輯式語言有更多的限制,表達力弱很多,再加上 SQL 對於基本的數據結構進行了“索引”,邏輯式語言的性能問題在 SQL 裏面得到了局部的緩解。比如,對於基本的算數操作x < 10,SQL 能夠通過對索引(B樹)的查找來進行“優化”,從而避免了對x 所有可能的值(一個非常大的空間)進行完全的遍歷。然而這種索引的能力是非常有限的,它幾乎沒有擴展能力,而且很難自動生成。所以一旦遇到更加複雜的情況,數據庫自帶的索引就沒法滿足需要了。除了極其簡單的情況,SQL 的編譯器無法自動生成高效的索引。

    更要命的是,這種問題的來源是根本性的,不可解決的,而不只是因爲某些數據庫的 SQL 編譯器不夠“智能”。很多人不理解這一點,總是辯論說“我們爲何需要 Java 而不是寫彙編,也就是我們爲何需要 SQL。”然而,把 Java 編譯成高效的彙編,和把 SQL 編譯成高效的彙編,是兩種本質上不同的問題。前者可以比較容易的解決,而後者是不可能的(除了非常個別的情況)。如果你理解“編譯器優化”的本質就會發現,這裏面有一個拓撲學上的質的飛躍。把 Java 編譯成高效的彙編,是一個非常簡單的,線性的優化。這個過程就像改進一個已經連接好的電路,把裏面太長的電線縮短一點,這樣時延和電阻可以小一些。而把 SQL 優化成高效的彙編,是一個非線性的優化。這個過程不只是縮短電線那麼簡單的問題,它需要解開一些錯綜複雜的“結”。這種優化不但非常難以實現,需要大量的“潛在數學知識”,而且有可能花費比執行代碼還多的時間。

    我只舉一個例子來說明這個問題。如果你需要迅速地在地圖上找到一個點附近的城市,SQL 無法自動在平面點集上建造像 KD-tree 那樣的數據結構。這是很顯然的,因爲 SQL 根本就不知道你的數據所表示的是平面上的點集,也不理解平面幾何的公理和定理。跟 B-tree 類似,知道什麼時候需要這種特殊的索引結構,需要非常多的潛在數學知識(比如高等平面幾何),所以你肯定需要手動的建立這種數據結構。你發現了嗎,你其實已經失去了所謂的“描述性”語言帶來的好處,因爲你完全可以用最普通的語言,加上一些構造 B-tree, KD-tree 的“庫代碼”,來實現你所需要的所有複雜查詢操作。你的 SQL 代碼並不會比直接的過程式代碼更加清晰和簡潔。再加上 SQL 本身的很多設計失誤,你就發現使用 SQL 數據庫其實比自己手工實現這些數據結構還要痛苦。你學會 SQL 是爲了避免編程,結果你不得不做比編程還要苦逼的工作,還美其名曰“performance tuning”。

    到這裏也許有人仍然會說,這只是因爲現在的 SQL 編譯器不夠智能,總有一天我們能夠製造出能夠“自動發明”像 B-tree, KD-tree 這樣索引結構的“優化算法”。我對此持非常不樂觀的態度。首先你要意識到,哪怕最基本的數學知識,也是經過了人類幾千年的實踐,研究和頓悟纔得到的。計算機雖然越來越快,它卻缺乏對於世界最直接的觀察和探索能力,所以在相當長的時間內,計算機是根本不可能自動“想到”這些數學和算法問題的,就不要談解決它們。其次,即使計算機有一天長了腳可以走路,有了眼睛可以看見東西,有了“自由意志”,可以自己去觀察世界,它卻不一定能夠發現並且解決“人類關心的數學問題”,因爲它根本不知道人類需要什麼。最後,我們需要在有生之年解決這些迫切的問題,我們無法等待幾十年幾百年,就爲了讓計算機自己想出像 KD-tree 一類衆所皆知的數據結構。

     計算機不可能猜到人類到底想要什麼,這就是爲什麼你幾乎總是需要手動指定索引的原因,而且這種索引需要數據庫“內部支持”。你一次又一次的希望 SQL 能夠自動爲你生成高效的索引和算法,卻一次又一次的失望,也就是這個原因。當然,你永遠可以使用所謂的 stored procedure 來擴展你的數據庫,然而這就像是我的 IU 同學們用 miniKanren 來實現 HM 類型系統的方式——他們總是先使用一種過程式語言(Scheme)來添加這種描述性語言的“相關特性”,然後歡呼:“哇,miniKanren 解決了這個問題!”而其實呢,還不如直接使用過程式語言來得直接和容易。

    這種總是需要擴展的顯現也出現在數據庫的語言裏面。經驗告訴我,如果想數據庫處理大量數據時達到可以接受的性能,你幾乎總是需要使用普通語言對手頭的數據庫進行所謂的“擴展”,然後從 SQL 等查詢語言“調用”它們。這種擴展代碼往往是一次性的,只能用在一個地方,從而使得這些查詢語言失去了存在的意義。因爲如果經常如此,我們爲何不直接發送這種過程語言到數據庫裏面執行,從而完全取代 SQL?

  另外有一種數據庫查詢語言叫 Datalog,它結合了 SQL 和 Prolog 的特點。然而以上對於 SQL 和 Prolog 的分析,同樣也適用於 Datalog。

關係模型的實質

    每當我批評 SQL,就有人說我其實不理解關係模型,說關係模型本身並沒有問題,所以現在我就來分析一下什麼是關係模型的實質。其實關係模型比起邏輯式語言,基本就是個衍生產物,算不上什麼發明。關係代數其實對應邏輯式語言裏面的一個很小的部分——它的數據結構及其基本操作,只不過關係模型有更大的侷限性而已。所以學會了邏輯式語言的設計之後,你直接就可以把關係模型這種東西想出來。

    每當談到關係模型,總是有人很古板的追究它與 SQL,Datalog 等“查詢語言”的區別。然而如果你看透了邏輯式語言的本質就會發現,其實“語言”和“模型”這兩者並沒有本質區別和明確界限。人們總是喜歡製造這些概念上的壁壘,用以防止自己的理論受到攻擊。追究語言和模型的差別,把過錯推到 SQL 和 IBM 身上,是關係式數據庫領域常見的託詞,用以掩蓋其本質上的空洞和設計上的失誤。所以在下面的討論裏爲了方便,我仍然會使用少量 SQL 來表示關係模型裏面對應的概念,但這並不削弱我對關係模型的批評。

關係模型與邏輯式語言

    我們先來具體探討一下關係模型與邏輯式語言的強弱關係。之前我們已經提到了,關係式數據庫所謂的“關係”,比起邏輯式語言來說,其實是小巫見大巫。關係式數據庫的表達能力,絕對不會超過邏輯式語言。關係式代數裏面的“=”,join 等構造都是沒有方向的。然而與邏輯式語言不同,這些“可逆操作符”在關係代數裏的用法受到非常大的限制。比如,這些可逆操作都不能跨過程,而且關係模型並不包含遞歸函數。所以你並不能真正利用這種“無方向的代碼”來完成比“有方向代碼”更加強大的功能,大部分時候它們本質上只是普通程序語言裏面最普通的一些表達式,只不過換了一種更“炫”的寫法而已。

    總是有人聲稱限制語言的表達力可以讓語言更加容易優化,然而如果一個語言弱得不能用,優化做得再好又有什麼用。關係模型的核心,其實是普通程序語言裏面最簡單的部分:表達式。如果缺乏控制結構和遞歸,這些表達式的能力只相當於最簡單的計算器。經驗告訴我,就算表達力這麼弱的語言,很多數據庫的編譯器也不能把優化做好,所以這不過是爲它的弱表達力找個藉口。另外由於這種無方向的表達式讓你在閱讀的時候很難看清楚數據的“流向”,所以你很難理解這裏麪包含的算法。這種問題也存在於邏輯式語言,但因爲邏輯式語言的表達力在某些方面強於過程式語言,所以感覺還不算白費勁。然而,關係模型有着邏輯式語言的各種缺點,卻不能提供邏輯式語言最基本的長處,所以比起過程式語言來說其實是一無是處。

關係模型與數據結構

    我們再來探討一下關係模型與數據結構的關係。很多人認爲關係式數據庫比起數據結構是一個進步,然而經過仔細的思考之後我發現,它其實不但是一個退步,而且是故弄玄虛,是狗皮膏藥。在 IU 的時候,我做過好幾個學期數據庫理論課程的助教。當時我的感受就是,很多計算機系學生上了“數據結構”課程之後,再來上“數據庫理論”課程,卻像是被洗腦了一樣,彷彿根本沒有理解數據結構。經過一段時間的接觸之後,我發現其實他們大部分人只是被數據庫領域的諸多所謂“理論”,“模型”或者“哲學”給迷惑了。本來是已經理解的數據結構和算法,卻被數據庫理論給換成了等價卻又嚇人的新名詞,所以他們忽然搞不明白了。我是很負責的老師,所以我努力地思索,想讓他們找回自我,最後我成功了。經過我如下的分析,他們大多數後來都茅塞頓開,對關係式數據庫應用自如,最後取得了優異的成績。

其實,關係模型的每一個“關係”或者“行”(row),表示的不過是一個普通語言裏的“結構”(就像 C 的 struct)。一個表(table),其實不過是一個裝着結構的數組。舉個例子,以下 SQL 語句構造的數據庫表:

CREATE TABLE Students ( sid CHAR(20),
                        name CHAR(20),
                        login CHAR(20),
                        age INTEGER,
                        gpa REAL )

其實相當於以下 C 代碼構造的結構的數組:

struct student {
  char* sid;
  char* name;
  char* login;
  int age;
  double gpa;
}

每一個 join,本質上就是沿着行裏的“指針”(foreign key)進行“尋址”,找到它所指向的東西。在實現上,join 跟指針引用有一定區別,因爲 join 需要查軟件哈希表,所以比指針引用要慢。指針引用本質上是在查硬件哈希表,所以快很多。當然,這些操作都是基於“集合”的,但其實普通語言也可以表示集合操作。

所謂的查詢(query),其實就是普通的函數式語言裏面的 filter, map 等抽象操作,只不過具體的數據結構有所不同。關係式代數更加笨拙一些,組合能力弱一些。比如,以下的 SQL 語句

SELECT Book.title
 FROM Book
 WHERE price > 100

本質其實相當於以下的 Lisp 代碼(但不使用鏈表,執行機制有所不同而已):

(map book-title
     (filter (lambda (b) (> (book-price b) 100)) Book)

所以關係模型所能表達的東西,其實不會超過普通過程式(函數式)語言所用的數據結構,然而關係模型卻有過程式數據結構所不具有的侷限性。由於經典的關係“行”只能有固定的寬度,所以導致了你沒法在結構裏面放進任何“變長”的東西。比如,如果你有一個變長的數組需要放進結構,你就需要把它單獨拿出來,旋轉 90 度,做成另外一個表,然後在原來的表裏用一個“key”指向它們。在這個“中間表”的每一行,這個 key 都要被重複一次,產生大量冗餘。這種做法通常被叫做 normalization。這種方法雖然可行,然而我不得不說這是一個“變通”。它的存在是爲了繞過關係模型裏面的無須有的限制,終究導致了關係式數據庫使用的繁瑣。說白了,normalization 就是讓你手動做一些比 C 語言的“手動內存管理”還要低級的工作,因爲連 C 這麼低級的語言都允許你在結構裏面嵌套數組!然而,很多人寶貴的時間,就是在構造,釋放,調試這些“中間表格”的工作中消磨掉了。

這些就是關係模型所有的祕密。如果你深刻的理解了數據結構的用法,那麼通過反覆推敲,深入理解以上這番“補充知識”,你就能把已知的數據結構常識應用到所謂的“關係模型”上面,從而對關係式數據庫應用自如,甚至可以使用 SQL 寫出非常複雜和高效的算法。

另外有一些人(比如這篇文章)通過關係模型與其它數據模型(比如網狀模型之類)的對比,以支持關係模型存在的必要性,然而如果你理解了這小節的所有細節就會發現,使用基本的數據結構,其實可以完全的表示關係模型以及被它所“超越”的那些數據模型。說實話,我覺得這些所謂“數據模型”全都是故弄玄虛,無中生有。數據模型可以完全被普通的數據結構所表示,然而它們卻不可能表達數據結構帶有的所有信息。這些模型之所以流行,是因爲它們讓人誤以爲知道了所謂的“一對一”,“一對多”等膚淺的概念就可以取代設計數據結構所需要的技能。所以我認爲它們其實也屬於技術上的“減肥藥”。

NoSQL 的“革命”

      SQL 和關係模型所引起的這一系列無須有的問題,終究引發了所謂 NoSQL 的誕生。很多人認爲 NoSQL 是劃時代的革命,然而在我看來它很難被稱爲是一次“革命”,最多可以被稱爲“不再愚蠢”。而且大多數 NoSQL 數據庫的設計者們並沒有看到以上所述的問題,所以他們的設計並沒有完全擺脫關係模型以及 SQL 帶來的思維枷鎖。

      最早試圖衝破關係模型和 SQL 限制的一種數據庫叫做“列模式數據庫”(column-based database),其代表包括 Vertica, HBase 等產品。這種數據庫其實就是針對了我剛剛提到的,關係模型無法保存可變長度數組的問題。它們所謂的“列壓縮”,其實不過是在“行結構”裏面增加了對“數組”的表示和實現。很顯然,每一個數組需要一個字段來表示它的長度,剩下的空間用來依次保存每一個元素。所以在這種數據庫裏,你大部分時候不再需要進行 normalization,也不需要重複存儲很多 key。這種對數組的表示,是一開始就應該有的,卻被關係模型排除在外。然而,很多列模式數據庫並沒有看到這一實質。它們經常設定一些無端的限制,比如你的變長數組只能有非常有限的嵌套層數之類,所以它們其實沒能完全逃脫關係式數據庫帶來的思想枷鎖。讓我很驚訝的是,如此明顯的事情,數據庫專家們最開頭恁是看不到。到後來改來改去改得六成對,還美其名曰“優化”和“壓縮”。

      最新的一些 NoSQL 數據庫,比如 Neo4j, MongoDB 等,部分的針對了 SQL 的表達力問題。Neo4j 設計了個古怪又不中用的查詢語言叫 Cypher,MongoDB 使用冗長繁瑣的 JSON 來直接表示對數據的查詢,就像是在手寫編譯器裏的 AST 數據結構。Neo4j 的 Cypher 語言不但語法古怪,表達力弱,而且效率非常低,以至於幾乎任何有用的操作你都必須使用 Java 寫擴展來完成(參考這篇博文)。所以到現在看來,數據庫的主要問題已經轉移到了語言設計的問題,而且它們會在很長一段時間之內處於混沌之中。

       其實數據庫的問題哪有那麼困難。只要你有一個好的程序語言,你就可以發送這種語言的代碼到“數據庫服務器”,這個服務器可以遠程執行你的代碼,調用服務器上的“庫代碼”對數據進行索引,查詢和重構,然後返回代碼指定的結果。如果你看清了 SQL 的實質,就會發現這樣的“過程式設計”其實並不會損失 SQL 的“描述性語言”的表達能力。反而由於過程式語言使用的簡單性,直接性和普遍性,會使得開發效率大大提高。NoSQL 數據庫比起 SQL 和關係式數據庫存在一些優勢,也就是因爲它們在朦朧中朝着這個方向發展。

       然而,NoSQL 並不總是朝着正確的方向發展。因爲設計它們的人往往沒有專業的修習過程序語言的設計,缺乏對歷史教訓的認識,所以他們經常犯下不應有的設計錯誤。我經歷過好些 NoSQL 數據庫之後發現,它們的查詢語言設計幾乎完全沒有章法。而且由於具體的實現質量以及商業動機,這些數據庫往往有各種各樣惱人的問題。這是必然的現象,因爲這些數據庫公司靠的就是諮詢和服務作爲收入,如果他們把這些數據庫高質量又開源的實現,沒有煩人的問題,誰會給他們付費呢?

      所以,這些 NoSQL 數據庫問題的存在,也許並不是因爲人們都很笨,而是因爲世界的經濟體制仍然是資本主義,大家都需要騙錢餬口,大家都捨不得給“小費”。有人說我這是“陰謀論”,可惜總有一天你會意識到,這的確是一個陰謀。如果你想知道跟 NoSQL 數據庫公司打交道是什麼感覺,可以參考一下我這篇博文裏面關於 Neo4j 的部分。

總結

說了這麼多,其實主要的只有幾點:

  1. 關係模型是一個無需有的東西。它嚴重束縛了人們的思想,其本質並不如普通的數據結構簡單和高效。它比起邏輯式語言的理論來說是非常膚淺的。
  2. SQL,Datalog,Prolog 等所謂“描述性語言”的價值被大大的高估了。使用它們的人往往有“避免編程”的心理,結果不得不做比編程還要痛苦的工作:數據庫查詢優化。
  3. 數據庫完全可以使用普通的程序語言(Java,Scheme 等)的“遠程執行”來進行查詢,而不需要專門的查詢語言。這在某種程度上就是 NoSQL 數據庫的實質和終極發展方向。

    對數據庫的問題有更多興趣的人,可以參考我的一篇相關的英文博客,以及這篇《一種新的操作系統的設計》裏面的相關部分。

習題

有人評論說我其實不懂 SQL,現在我就來考考你的 SQL 編程能力,看看到底是誰理解 SQL 多一些 :)

     題目:請用 SQL 實現 Dijkstra 的最短路徑算法。

    爲了加深對數據庫的認識,每個人都應該用 SQL 來實現這樣稍微複雜的算法,而不只是寫一些高中生都會的基礎程序。如果你仍然相信“What,not How”的廣告,反對使用 SQL 來寫這樣的過程式算法,那麼就請你更進一步,使用你所謂的“What 查詢方式”來高效的解決最短路徑問題。


原文地址:

http://www.yinwang.org/blog-cn/2014/04/24/sql-nosql/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章