PostgreSQL vs. MS SQL Server
從一個數據分析師的視角來對比兩個關系型數據庫。
0.本文是關于什么的?
我在一個全球專業服務公司做數據分析師(你肯定聽說過的)。我干了大概有10年。10中我處理數據、數據庫軟件、數據庫硬件、數據庫用戶、數據庫程序員以及數據分析方法,所以我對這些東西了解的比較多。我經常遇到對相關內容了解很少的人,雖然他們中的一部分并沒有意識到這件事。
這些年里,我已經太多太多次的討論了 PostgreSQL 和 MS SQL 的問題。IT 行業中一個知名的原則說:如果你準備不只一次的做同一件事,那就讓它自動化。本文是我的自動化方法的談話。
除非另有說明,我指的是PostgreSQL 9.3和MS SQL Server 2014,即使我的經驗是在MS SQL Server 2008 R2和2012版。為了公平起見,我將比較最新版的MS SQL Server和PostgreSQL。由于微軟的糟糕的文檔,我不得不大量的依賴于Google、Stack Overflow以及網絡上的用戶。因為我對兩個數據庫的經驗不相等,所以我知道像這樣的比較不夠科學嚴謹。不過這不是一個學者的練習題,這是現實中的比較。我盡可能讓我對于MS SQL Server的了解正確,因為我們都知道要糊弄整個互聯網是不可能的。如果我發現我弄錯了什么事情,我會修正的。
我將以一個數據分析師的角度來比較兩個數據庫。MS SQL Server可能會因為QLTP后臺而踢PostgreSQL的屁股(雖然我比較懷疑),不過那些不是我這里要關注的,因為我不是一個OLTP開發者/DBA/系統管理員。
最后,右上角有一個email地址。如果你愿意的話你會用到的,我會盡可能回復的。
免責聲明:本文所有觀點僅代表我個人。
1. 為什么說 PostgreSQL 比 MS SQL Server 強的多
額,劇透了。本節從數據分析的角度對比這兩種數據庫。
1.1. 支持 CSV
CSV 其實是轉移結構化數據(如: 表)的一種標準方式。不論是哪一種數據庫,都能用自己專有的格式,把數據導出來。以這種格式存儲的數據,其他軟件無法讀取. 用來做備份或者復制數據還行。如果想從 X 系統, 把數據移植到 Y 系統,那問題就大了。
一個數據分析平臺, 既要能讀取不同系統的數據, 也要能生成其他系統能讀取的分析結果. 也就是說, 要能快速, 穩定, 可重復的, 而且毫無痛苦的讀寫 CSV. 我再說一次:一個不能很好的處理 CSV 的數據分析平臺,就是沒用的累贅。
PostgresSQL對CSV的支持在業內是頂尖的。 COPY TO和 COPY FROM命令支持RFC4180(最接近官方標準的文檔)中列出的所有規格,也支持很多常見的和不常見的變種和方言。 這些命令運行速度很快而且很強大。 發生一個錯誤時,它們會給出有幫助性的錯誤信息。 更重要的是,它們不會默默地損壞、誤解、修改數據。
而MS SQL Server既不支持導入也不支持導出CSV文件。 很多人不相信當我告訴他們這一點時。 然后,某一次,他們自己驗證了這一點。通常他們的觀察是這樣的:
-
MS SQL Server默默地清除(truncate)了一個文本字段的數據
</li> -
MS SQL Server對文本進行編碼時發生錯誤
</li> -
MS SQL Server拋出一個錯誤信息因為它不理解引用或轉義(出乎人們的意料,對CSV來說引用和轉義不是特殊的擴展。從字面上看,引用和轉義是每一個人類可讀的數據序列化規范的基本概念。不要相信那些不懂這些東西的人。)
</li> -
MS SQL Server導出損壞的、不可用的CSV文件
</li> -
微軟有一篇驚人的文檔。他們怎么能把CSV這么簡單的東西如此復雜化的呢?
</li> </ul>如果你不相信,下載這個格式正確的、符合標準的UTF-8編碼的CSV文件,用MS SQL Server計算文件中最后一列(共有50列)字符串的平均長度(或者是字符的數量,等等)。繼續,試一下。
(你得到的答案將是 183.895。)
當然,事實上,對 PostgreSQL 來說,確定這么做非常簡單。最耗費時間的地方是創建保存這些數據的且具有50個字段的數據表。微軟本身似乎就很難理解CSV文件;而且打開這樣的文件還會引起Access和Excel中斷。
痛苦但卻是事實的情況是:我了解到近期一些數據庫編程人員花費大量的時間和精力編寫Python代碼,以實現對CSV文件的“清理”,從而讓MS SQL服務器可以把這些文件的內容導入到數據庫里。但是,這種處理方法不可避免的要更改實際的數據。這就像花費大量金錢購買了Photoshop,然后不得不編寫一些定制的代碼來讓Photoshop打開JPEG,到頭來僅僅發現只是稍稍修改了圖片那樣讓人抓狂。
1.2.人機工程
值得一提的是每個數據分析平臺都是圖靈完備的,這大概意味著任何一個數據分析平臺可以做其他數據分析平臺做的任何事情。也就不存在“你可以在A軟件中做X這件事而不可以在B軟件中做X這件事”。即你可以在任何軟件里做任何事情-所不同是難易程度。好的工具讓你要做的事情做起來非常簡單;差的工具就會讓你要做的事情做起來很難。說到底就是這么回事。
(理論上來講這一切都是正確的,然而現實中卻不是這樣的-例如,我了解到沒有關系型數據庫管理系統(RDBMS)使用3D圖形。不過,任意一個關系型數據庫管理系統都可以模擬GPU執行任何圖形計算。)
很顯然,PostgreSQL 是由實際關心如何對資料進行處理的人編寫的。而MS SQL服務器則是由那些根本就不需要使用MS SQL服務器來實現某件事情的人編寫的。下面的幾個例子就可以說明:
-
PostgreSQL支持
DROP TABLE IF EXISTS
,這是一個非常聰明且顯而易見的處理方式,它表明:“如果這個表不存在,就什么也不做,如果存在,就刪除它”。例如:DROP TABLE IF EXISTS my_table;
在MS SQL服務器中,你卻需要這么做:
IF OBJECT_ID (N'dbo.my_table', N'U') IS NOT NULL DROP TABLE dbo.my_table;
是的,只是多了一行代碼,不過要留意
OBJECT_ID
函數中令人奇怪的第二個參數。刪除視圖時你需要把它替換為N'V'
。刪除存儲過程時替換為N'P'
。我不知道所有不同類型的數據庫對象對應的各個字符(為什么我必須要知道呢?)還要注意到另一點:不必要地重復了表名。你稍不留意,就容易做出以下事情:
IF OBJECT_ID (N'dbo.some_table', N'U') IS NOT NULL DROP TABLE dbo.some_other_table;
看看此時會發生什么?這確實是令人懊惱、浪費時間的錯誤。
</li> </ul>
-
PostgreSQL支持DROP SCHEMA CASCADE,它會刪除模式以及該模式下的所有數據庫對象。對一個強壯的分析方法來說,做到這一點非常、非常重要,因為此時分割和重建是進行可重復的、可審計的協作分析工作的基本操作方法。而MS SQL服務器卻不是這樣的。你不得不手工刪除該模式下的所有對象,而且要按照正確的順序刪除,因為在你試圖刪除一個其他對象依賴的對象時,MS SQL服務器只會拋出一個錯誤。這使得整個處理過程非常笨拙。
</li> </ul>-
PostgreSQL 支持 CREATE TABLE AS。一個簡單的例子如下:
CREATE TABLE good_films AS SELECT * FROM all_films WHERE imdb_rating >= 8;
這就意味著你可以使用除第一行以外的其他行,并執行,在開發SQL代碼時,這是一個常見的且非常有用的處理方式。在MS SQL服務器里,你要采用如下代碼才能以上面的方式創建表:
SELECT * INTO good_films FROM all_films WHERE imdb_rating >= 8;
此時,要執行普通的SELECT語句的話,你需要注釋或者刪除INTO部分。是的,注釋兩行非常簡單;不過這不是我們關注的地方。我們關注的是在PostgreSQL里,你不需要修改代碼就可以執行這個簡單的任務,而在MS SQL服務器上,你無法做到這一點,而且你要做到這一點還會帶來另一個潛藏的漏洞和令人討厭的東西。
</li> </ul>
-
在PostgreSQL里,你可以在一次批處理里執行你愿意執行數量級的SQL語句;只要每個語句都以分號結束,你就可以執行你所想到的任何語句組合。對于哪些要執行自動批處理、構建重復數據或者進行輸出的程序來說,這是一個非常重要的功能。在MS SQL服務器里,在一個批處理的SQL語句中間不能出現
</li>CREATE PROCEDURE
語句。這么做沒有任何好的理由,僅僅是隨意加的一個限制。此時就意味著需要額外的手工操作來執行大量的SQL批處理。手工操作會增加風險,降低效能。 -
PostgreSQL 支持
</li> </ul>RETURNING
子句,允許UPDATE
,INSERT
和DELETE
語句返回已更改行上的數據值。這么做非常簡潔有益。MS SQL 服務器有個OUTPUT
子句可滿足這方面需求,不過它需要單獨定義表變量來實現此功能。這么做很笨拙而且不方便,還迫使程序開發人員創建并維護不怎么需要的代碼。-
PostgreSQL 支持用 $$ 將字符串括起來, 像這樣:
SELECT $$Hello, World$$ AS greeting;
這樣寫, 對動態生成 SQL 語句很有用, 因為 (a) 當嵌入字符串時, 能避免既繁瑣, 又容易出錯的手工引用和對特殊字符的轉義. (b) 由于文本編輯器和 IDE 一般不把 $$ 當作字符串分隔符, 動態生成的 SQL 語句依然根據語法高亮顯示。</li> -
PostgreSQL 允許你向數據庫引擎提交面向過程的編程語言代碼; 你可以使用, 像 Python , Perl , R 或 JavaScript, 或其他已被支持的語言(具體看下面), 在同一個腳本文件的 SQL 語句旁邊, 加上面向過程的代碼. 這樣做簡潔方便, 易于維護. 同時也方便查看代碼, 重復使用, 等等各種好處.
而 MS SQL Server, 你可以使用笨拙, 緩慢, 還有點尷尬的 T-SQL, 或者用 .NET 生成組件(Assembly) 然后加載到數據庫中. 。也就是說,你的代碼存在兩個不同的地方。你得在各種圖形界面之間切來換去的修改這些代碼。想要將這些東西統一打包放在一起,困難重重。而且也容易出錯。
</li> </ul>諸如此類例子還有很多. 這些問題, 分來開看, 好像沒什么. 可是放到一起, 問題就大了. 想要在 MS SQL Server 上面做好一件事, 要比在 PostgreSQL 做的難度大的多. 數據分析師把許多寶貴的時間和精力都花在, 解決各種問題, 手工處理的過程中, 而不是解決真正需要解決的問題.
更正: 有人跟我說, MS SQL Server 有個優勢, 是 PostgreSQL 不具備的. 那就是在 SQL 腳本中聲明變量. 如:
DECLARE @thing INT = 1;
SELECT @thing + 6; --returns 7</pre>
PostgreSQL 確實不能聲明變量. 真心希望它能加上這個實用的功能.
你能夠在Linux,BSD等平臺上運行PostgreSQL(當然,在Windows上也可以)
IT行業的開發人員都清楚跨平臺是當今一個關注點。支持跨平臺可以說是Java殺手級的特性,其實Java是一門尚顯粗糙、丑陋的編程語言,但它依然獲得了巨大的成功,廣泛的影響及普及。Linux與蘋果的崛起使微軟在桌面領域無法再保持壟斷地位。云服務的靈活性和高性能虛擬化技術的易訪問性,使IT基礎設施越來越多樣化。跨平臺軟件能夠提供給用戶控制他們的基礎設施。(工作中,我目前管理著好幾個PostgreSQL 數據庫,一些運行在Windows平臺上,一些在Ubuntu Linux上。我和同事自由地在這些平臺之間移動代碼和數據庫數據。我們使用Python和PHP,因為他們在兩種操作系統上都能運行。它們全部運行得很好。)
微軟的政策一直都是供應商鎖定。 他們不開放自己的代碼;他們不提供跨平臺版本的軟件;他們甚至自己創造一個完整的生態系統,.NET設計用于為微軟用戶和非微軟用戶搭建了一座橋梁。 這對他們是有利的,因為這種方式保證了他們的利潤。 這對你(用戶)是不利的,因為微軟限制了你的選擇,而且為你創建了一些不必要的工作。
這不是一篇對比 Linux和 Windows的文檔,盡管我確定我最后會提到幾點。 可以肯定地說,對于真正的 IT工作, Linux(和類 UNIX操作系統家族: Solaris, BSD等)把 Windows甩出幾條街。 類 UNIX操作系統主宰著服務器市場、云服務、超級計算(在這個領域它近乎壟斷)和科學計算,一個原因就是 - 這些系統是技術人員為技術人員設計的。 最終,他們以巨大的力量和靈活性換得了用戶友好性。 一個合格的類 UNIX OS 不僅僅是一個漂亮的命令行集合 – 它是一個包含各種程序、實用工具、功能的生態系統,并且提供支持使完成工作變得高效和有趣。 一個合格的 Linux黑客可以用一行被拋棄的 Bash腳本達到目的,但是這個任務在 Windows中是艱巨且耗時的。
(例如,某一天,我在查看朋友影片收集情況,他對我說,他認為他的文件系統中文件的總數量太多,他想知道究竟有多少影片文件,還想知道他是否可還以把一個大型的文件夾結構復制到影片文件夾下。我使用下面語句對每個文件夾及其子文件夾所包含文件數進行了計算:
find . -type f | awk 'BEGIN {FS="/";} {print $2;}' | sort | uniq -c | sort -rn | less
整件事情做下來編寫花了一分鐘,運行花了一秒鐘。同時還證實某些文件夾有問題,并告訴他具體哪個文件夾有問題。Windows下怎么能做到這些呢?)
在做數據分析時,關系型數據管理系統(RDBMS)不可能處在真空里;它是整套工具中一部分。因此它所處的環境就非常重要。MS SQL服務器只可在Windows系統上使用,而Windows是一個很差勁的可用于分析的環境。
1.4程序語言特性
這可是一個大問題。
一個“純”字可以概括SQL,因為它只專注于它被設計的初衷,那就是關系型數據的操作和查詢。如果你嘗試用它做更多的分析處理的話,比如復雜的利息計算、時間序列分析以及通用算法設計,你將很快達到它的極限。SQL數據庫的提供者對這些比較了解,所以幾乎所有的SQL數據庫都實現了某種程序語言。這就是使得數據庫用戶可以寫命令式風格的代碼以用于更復雜或繁瑣的任務。
PostgreSQL的程序語言支持比較好。對它來說在一個小范圍內是不可能做到公正的,不過這只是一個樣本。這些程序語言的任何一個都可以用來寫存儲過程和函數或直接轉儲到一個內聯執行的代碼塊。
-
PL/PGSQL: 它是PostgresSQL 原生的程序語言。 它與Oracle的PL/SQL類似,但是它比后者更現代、功能更完善。
</li> -
PL/V8:來自Google Chrome的V8腳本引擎在PostgresSQL中可以使用。 這個引擎穩定、功能豐富、速度不可思議地快 – 經常接近于經過優化和編譯的C語言代碼的執行速度。把它和PostgresSQL對JSON數據類型的原生支持結合起來(見下文),在一個單獨的包中你會有終極的力量和靈活性。甚至更好,PL/V8支持全局(跨函數調用,等等)狀態,允許用戶選擇性地快速隨機訪問RAM中高速緩存數據。 假設表A有100,000行數據,表B有1,000,000行數據,對于表B中的每行數據都需要與表A中所有數據進行關聯。 使用傳統的SQL,你要么需要關聯這兩張表(在中間表中會有10^11行數據,這會累死所有計算機,除最強大計算機外)或者進行一個類似于標量的子查詢(或者使用基于游標的嵌套循環,這更糟),如果查詢解析器沒有正確地讀懂你的意圖,這些方法會帶來沉重的I/O負擔。在PL/V8中,你只需在內存中緩存表A的數據,遍歷表B的數據時調用一個函數 – 訪問這個有100,000行的表A時,它會給你RAM級別的訪問速度(微不足道的延遲和隨機訪問懲罰;沒有非易失性I/O加載)。 最近我在我的一個項目中使用了這種方法- 我的PostgreSQL/PLV8代碼運行速度比微軟T-SQL解決方法快80倍,并且代碼更簡潔、更易維護。 由于運行耗時23秒而不是30分鐘,我因此能夠在1個小時內完成20個測試周期(運行-測試-修改),從而寫出功能完善、經過測試、無bug的代碼。 關于這一點,在這里可以看到更多細節。(由于使用 DROP SCHEMA CASCADE,并且在批量聲明中間可以隨意執行CREATE FUNCTION語句,所有那些測試周期才是可能完成的,正如上面解釋的那樣。 看它們在一起是多么搭配啊!)
</li> </ul>-
PL/Python:你可以在PostgreSQL里隨意使用Python。Python2或者Python3,隨你選,都可以,你可以使用大量的Python庫,Python正是因為它們才出名的。在SQL查詢語句中間想調用scikit-learn提供的SVM或者gmpy2提供的某些任意精度的算法,可以嗎?沒問題!
</li> -
PL/Perl:Perl已經不流行一段時間了,不過因其功能多而贏得了編程語言瑞士軍刀的美譽。在PostgreSQL里,你完全可以把Perl用做編寫存儲過程語言。
</li> -
PL/R:R是學術和數據科學領域統計編程的事實標準,而且還有很好的理由使用它-它免費、強大、功能全面,同時有大量高質量的插件和附件庫支持。因此PostgreSQL允許你可以使用R做為編寫存儲過程的語言。
</li> -
在PostgreSQL里,還可以用Java、Lua、sh、Tcl、Ruby和PHP做為編寫存儲過程的語言。
</li> -
C:它確實不屬于存儲過程語言列表,因為你需要單獨對它進行編譯,不過在這兒值得一提。在PostgreSQL中,可以非常容易地創建在數據庫后臺進程里進行C(或者C++或者匯編) 的編譯、優化的函數。這是一個非常強大的用戶功能,它可以讓哪些對性能有特別要求的任務運行速度最快、內存管理和資源利用得到精確地控制。我已經用它實現了復雜的支付狀態處理算法,可在一秒鐘操作一百萬行數據-而且是在桌面PC上運行的。
</li> </ul>MS SQL Server 內置的面向過程編程語言 (T-SQL 對 SQL 擴充的一部分) 既笨拙, 又緩慢, 各種缺點。 就如 Microsoft 自己的文檔說的那樣, 它有時會容易產生一些奇怪的錯誤和 Bug。 我還沒見過哪個程序員說他喜歡 T-SQL 的。
那放到 MS SQL Server 上面用的 .NET 組件呢 ? 這種不算面向過程語言支持, 因為你不能直接向數據庫引擎提交代碼。要知道, 可管理性和人類工程學(ergonomics )都很重要。 直接將 Python 代碼嵌入數據庫查詢語句中, 既簡單又方便; 啟動 Visual Studio, 然后管理一堆項目,復制一堆 DLL 文件 (都是在圖形用戶界面中處理的,不能很好的腳本化,版本控制, 自動化, 以及審查 )其實挺尷尬的,而且容易出錯,擴展性又不好。總之, 這種機制在很大程度上受限于.NET 語言。
1.5支持原生正則表達式
正則表達式(regexen或者regexes)對于分析工作來說就像會算術一樣的基礎,對于大量的文本處理任務來說它們是首選(經常是唯一選擇)。不支持正則表達式的數據分析工具就像一個沒有座的自行車一樣,你仍然可以用它,但是充滿痛苦(菊花都殘了當然痛—譯者加)。
PostgreSQL有開箱即用的正則表達式支持。看幾個例子:
取得所有以重復數字并且緊跟元音字母開頭的行:
SELECT * FROM my_table WHERE my_field ~ E'^([0-9])\\1+[aeiou]';
取得某一個字段中第一個出現的單獨的十六進制字符串:
SELECT SUBSTRING(my_field FROM E'\\y[A-Fa-f0-9]+\\y') FROM my_table;
將一個 字符串以空白字符分割,并且以單行的形式返回每一部分:
SELECT REGEXP_SPLIT_TO_TABLE('The quick brown fox', E'\s+'); -- Returns this:
-- | column | -- ----------- -- | The | -- | quick | -- | brown | -- | fox |</pre>
查找一個字符串中最少有10個字母的單詞(不區分大小寫):
SELECT REGEXP_MATCHES(my_string, E'\\y[a-z]{10,}\\y', 'gi') FROM my_table;
MS SQL Server有 LIKE ,SUBSTRING,PATINDEX 等等,不過它們與恰當的正則表達式支持不具可比性(如果你對此懷疑,你可以嘗試使用它們來實現上面的例子)。有第三方的庫可用于MS SQL Server,它們不像PostgreSQL的支持那樣好,并且獲取和安裝它們會增進管理開銷。
還要注意到PostgreSQL的支持擴展程序語言特性也讓你有好幾個其他的正則表達式引擎可用,當然也包括它們的各種特性。比如Python的正則庫提供的對正向和負向后行斷言的支持。這正符合PostgreSQL的一貫作風,給你干好工作的所有你需要的工具。
1.6自定義聚合函數
這是一個PostgreSQL和MS SQL Server兩者都提供的一個技術上的特性。不過,在實現上卻有巨大的不同。
在PostgreSQL中,自定義聚合很方便并且使用簡單,產生了可以快速解決問題和可維護的代碼:
CREATE FUNCTION interest_sfunc(state JSON, movement FLOAT, rate FLOAT, dt DATE) RETURNS JSON AS $$ state.balance += movement; //payments into/withdrawals from account if (0 === dt.getUTCDate()) //compound interest on 1st of every month { state.balance += state.accrual; state.accrual = 0; } state.accrual += state.balance * rate; return state; $$ LANGUAGE plv8;
CREATE AGGREGATE interest(FLOAT, FLOAT, DATE) ( SFUNC=interest_sfunc, STYPE=JSON, INITCOND='{"balance": 0, "accrual": 0}' );
--assume accounts table has customer ID, date, interest rate and account movement for each day CREATE TABLE cust_balances AS SELECT cust_id, (interest(movement, rate, dt ORDER BY dt)->>'balance')::FLOAT AS balance FROM accounts GROUP BY cust_id;</pre>
簡單吧?自定義的聚集函數主要關注的是內部的狀態和我們輸入新值給這個聚集函數時修改這個狀態的方法。在這個例子里,我們假設一開始每個客戶的余額為零,而且累計利息也為零,接著我們每天適當地進行利息累計,并對每天的支付和撤消記賬。在每個月的1號,我們進行利息復合。注意:這個聚集函數接納
ORDER BY
子句(因為它與SUM
、MAX
和MIN
不同,它是排序相關的),另外PostgreSQL有操作符可以從JSON對象里提取對應的數值。因此,我們在28行代碼里創建了每月對銀行賬戶進行利息復合的框架,使用這個框架就可以計算出最終的賬戶余額。如果打算給這個方法增添功能(比如根據借/貸額度進行利率修改,異常檢測),這一切都可以在轉換函數里實現,只要采用適合于實現復雜邏輯的語言編寫即可。(不幸的是:我看到許多組織機構使用較差的工具花費數萬英鎊經過數周的努力試圖完成同樣的任務。)順帶說明一下,上面的第二個鏈接里的例子實現了簡單的字符串連接聚集。注意:實現如此簡單的功能需要大量的代碼和技巧(而PostgreSQL內部提供了此功能,隨拿隨用。這可能是因為這個功能有用!)MS SQL服務器還禁止在聚集函數里指定排序,使用這樣的函數無法完成我現在要完成的任務-在MS SQL服務器里,字符串連接的順序是隨機的,因此使用這個函數查詢的結果就是無法確定的(即每次運行結果都可能不同),而且這樣的代碼也不會通過質量審查的。
缺乏排序支持還可能使得以前編寫的代碼無法運行,比如上面計算利息的例子。正如我所說,你無法通過使用MS SQL服務器自定義的聚集函數完成當前的任務。
(實際上,可以讓MS SQL服務器使用純SQL語句實現結果可以確定的字符串連接聚集,不過,你需要多次使用
RECURSIVE
查詢功能來實現。雖然可以把它當作一次有趣的學術性練習,但是這會生成運行速度慢、無法閱讀且無法維護的代碼,因此它不是一個可以使用在現實世界的解決方案。)1.7Unicode 支持
ASCII一統江湖的日子已經一去不復返了,“字符(character)”和“字節(byte)”是可互換的以及“外國(foreign)”(從Anglocentric觀點來看)文本是具有異國情調的異常。合適的國際語言支持不再是可選項。
所有問題的解決方案是Unicode。外面有許多對Unicode的誤解。它不是一個字符集,不是一個代碼頁,不是一個文件格式,并且它和加密也沒有任何關系。探索Unicode是如何工作的很讓人著迷的事,但是這個超出了本文的范圍,我打心底里推薦你Google它并且試試幾個例子。
Unicode對應的重要的數據庫功能如下:
-
Unicode編碼文本(對于我們的目的而言,這意味著只能使用UTF-8或者UTF-16)是一個可變長度的編碼。 在UTF-8中,一個字符可以占1、2、3或4個字節。 在UTF-16中,它可以占2或4個字節。 這意味著進行獲取子字符串、計算字符串長度等操作時,需要知道它們是Unicode編碼的,這樣操作才能正常進行。
</li> -
并非所有字節序列都是合法的Unicode。 操作合法的Unicode編碼的文本而不知道它是Unicode編碼,就像是生成一些不合法的Unicode文本。
</li> -
UTF-8和UTF-16互不兼容。 如果你每一個文件使用一種類型,然后把它們合并起來,你(可能)會得到一個既不是UTF-8格式也不是UTF-16格式的文件。
</li> -
對于大部分適合ASCII的文本而言,UTF-8格式的空間效率是UTF-16格式的2倍。
</li> </ul>PostgresSQL支持 UTF-8 。默認情況下,它的 CHAR 、 VARCHAR 、 TEXT 類型采用 UTF-8 格式,這意味著這些類型僅接受 UTF-8 數據和適用于 UTF-8 格式的所有轉換,從字符串級聯到使用正則表達式搜索,這些都是顯示的 UTF-8 格式。上面這些都是有效的。
MS SQL Server 2008 不支持 UTF-16;但它支持 UCS-2 -- UTF-16 的一個過時的子集(a deprecated subset)。多數情況下,不會有問題. 但是, 偶爾會損壞數據。因為,它把文本當成寬字符(如 2 個字節)處理,所以遇到 UTF-16 的 4-字節字符時,會毫不猶豫地切掉一半。輕者,數據損壞。嚴重的時候,會導致你的工具鏈中某些東西出現問題,后果非常嚴重。那些替微軟辯護的人會立刻反駁:這是不可能的。因為,在 Unicode 的基本多文平面(basic multilingual plane)外面,還包含其他東西。這種說法實在是荒謬。數據庫就是用來存儲,讀取和修改數據而已。 一個數據庫,如果因為存入錯誤的數據而出問題,那不是跟下載錯誤的文件會導致路由器崩潰一樣荒唐?
2012年后MS SQL Server版本都支持UTF-16,如果你確定你為數據庫設置了兼容UTF-16的校驗規則。 這在2012年后的版本中是一個莫名其妙的功能。不過,遲到總比不到好。
1.8. 可以正常使用的數據類型
一個普遍誤解的概念是所有的數據庫有相同的數據類型 – INT、 CHAR、 DATE等等。 不是這樣的。 PostgresSQL的數據類型系統非常有用、直觀、沒有 bug或效率低下的煩惱,顯然數據類型的設計使用生產效率為核心。
相比之下,MS SQL服務器的類型識別系統就像是Beta版的測試軟件。它不具有PostgreSQL類型識別系統所具有的功能集,而且由于諸多陷阱使得用戶異常困惑,從而讓粗心的用戶掉入缺陷網中。我們仔細對比一下:
-
CHAR、VARCHAR和其他字符類型
</li>-
PostgreSQL:它的文檔積極鼓勵你只使用
</li>TEXT
類型。它是一個高性能的、UTF-8編碼的文本存儲類型,可存儲的字符串高達1GB。它還支持PostgreSQL具有的所有文本操作:簡單地字符串連接和字串提取;正則搜索、正則匹配和分割;全文搜索;強制類型轉換;字符轉換等等。如果你有文本數據,那么就可以定義為TEXT
字段,并存儲。再者,由于TEXT
字段(或者是CHAR
或者VARCHAR
字段)的內容必須采用UTF-8編碼,因此就不存在編碼兼容的問題。由于UTF-8是事實上的通用的文本編碼。因此把文本轉換成此種編碼就非常容易和可靠。再者因為UTF-8是ASCII編碼的超集,所以此種轉換通常非常簡單或者說不需要轉換。正因為這樣,它才運行的非常好。 -
MS SQL服務器:這是一次非常痛苦的經歷。
TEXT
和NTEXT
兩個類型都有,而且可存儲的大小達2GB。然而,令人沮喪的是它們都不支持類型轉換。另外,微軟建議不要使用它們 -在將來的MS SQL服務器版本里,這兩個類型都將被刪除。你應當取代性地使用CHAR
、VARCHAR
以及它們的N前綴版本。很不幸的是:VARCHAR(MAX)
具有很差的性能,而且VARCHAR(8000)
(即緊鄰的最大存儲量,由于某些原因)最大只能存儲8000字節。(NVARCHAR
最大只能存儲4000字符。)想一下PostgreSQL怎么樣在一個每個數據庫上使用單一的文本編碼,從而讓一切平穩地運行的? MS卻沒有做到這樣:就像早期版本的SQL服務器那樣,在編碼轉換期間發生數據丟失是不會匯報的。[ 鏈接]
換句話說,MS SQL服務器可能會損壞數據,而且只有遇到其他非數據錯誤時你才知道。很簡單,這就是個麻煩制造者。可對數據進行沉默性更改、損壞或者丟失的數據分析平臺就是一個巨大的缺陷。想想不使用服務器而使用昂貴的ECC RAM做為防止因宇宙射線而造成的數據損壞荒謬行為,然后在其上運行軟件,那么無論如何都可能造成數據損壞。
</li> </ul>-
日期和時間類型
</li>-
PostgreSQL:你可以使用
DATE
、TIME
、TIMESTAMP
和TIMESTAMP WITH TIME ZONE
類型,所有這些類型都會做到你期望那樣。它們還具有極為出色的范圍和精度,支持從公元前5世紀到未來30萬年的毫秒級精度。它們也接受多種格式的輸入,最后一個是它們還提供對時區的完整支持。它們還可以與UNIX時間互轉,這一點在與其他系統的互操作方面就非常重要。它們還可以取特殊值infinity
和-infinity
。這不是一個形而上的、神學的、哲學方面的語句,而是一個非常有用的語義結構。例如,設置用戶密碼的過期日期為infinity
,表示他們不需要修改密碼。處理這種事情的標準方式是使用NULL
或者遙遠的未來的某個日期,不過,他們是一群愚蠢的黑客-他們不但把不精確的信息存儲到數據庫,而且還需要編寫應用邏輯來彌補。當開發人員看到NULL
或者3499-12-31
的時候,會怎么樣呢?如果你幸運,那么他會認識到要進行密鑰握手,而不會因此產生任何混亂。如果不幸運,那么他會假設這個日期是未知的,或者這個日期確實指的是第四個千年,那么你就會遇到問題。像這樣的黑客、工作場景和湊合的程序設計的累積結果就會生成一個不可靠的系統、不幸福的程序開發人員,從而增加商務上的風險。像infinity
和-infinity
這樣非常有用的語義結構就允許你說出你所想,然后寫出一致的、可讀性好的應用邏輯。它們還支持INTERVAL
類型,它非常有用,在這一節之后有專門的一節介紹。日期和時間類型的強制轉換為其他類型和它們之間的轉換非常簡單和直觀-你可以強制轉換任意一日期和時間類型為TEXT
,to_char
和to_timestamp
函數給你提供最大的靈活性,可以讓你使用格式字符串實現兩個方向的互轉。例如:SELECT to_char('2001-02-03'::DATE, 'FMDay DD Mon YYYY');--這條語句會生成字符串"Saturday 03 Feb 2001"
另一方向的轉換如下:
SELECT to_timestamp('Saturday 03 Feb 2001', 'FMDay DD Mon YYYY'); --這條語句會生成時間戳2001-02-03 00:00:00+00
像往常一樣,這一切都運行的非常好!作為一名數據分析師,我非常關心數據庫對日期的處理能力,因為日期和時間是以許多不同的格式來表現的,而且對分析來說它們通常都非常重要。
</li> -
MS SQL服務器: 日期類型只有由正的四位數字組成的年份,因此日期局限在公元0001到公元9999之間。它們也不支持
</li>infinity
和-infinity
。它們也不支持interval類型,因此日期的算法乏味笨拙。你可以在它們與UNIX時間間互相轉換,不過處理的技巧是在UNIX新紀元1970-01-01T00:00:00Z上增加秒數,因此你需要知道UNIX新紀元,而且要把它硬編碼到應用里。日期轉換在這兒特別值得一提,是因為即便遵循MS SQL服務器粗略的標準,日期轉換仍然讓人感覺到吐血般的恐怖。使用CONVERT
函數替代了PostgreSQL的to_char
和to_timestamp
,不過它運行方式如下:SELECT CONVERT(datetime, '2001-02-03T12:34:56.789', 126); --這條語句會生成datetime值: 2001-02-03 12:34:56:789
就是這樣-你只要知道“126”是把字符串轉換為某種格式的datetime的編碼即可。MSDN給出與這些奇奇怪怪數字對應的表。我沒有給出與PostgreSQL相同的例子,這是因為我沒有找到與格式"Saturday 03 Feb 200"相對應的奇怪的數字。如果某人給出的數據含有這個日期類型,那么我猜你將不得不做一些字符串處理的工作了(很遺憾,在MS SQL服務器里幾乎沒有字符串處理功能。)
</ul> </ul>INTERVAL
-
PostgreSQL:INTERVAL類型表示一個時間段,如“30微秒”或者“50年”。它也可以是負數,這看起來有些不合常理,如果你知道一個單詞“以前(ago)”存在的話就不會了。PostgreSQL也知道“ago”,事實上它也接受類似‘一天前(1 day ago)’字符串作為interval值(這個值在內部用-1天的時間段表示)。interva讓你有一個直觀的日期計算,并且作為第一類的數據類型來存儲持續時間。它們像你期望的那樣準確,并且可以自由的改造和轉換成任何有意義的數據,也可以由任何有意義的數據轉換而來。
</li> -
MS SQL Server:不支持interval數據類型。
</li> </ul> </span></h4>-
數組
</li>-
PostgreSQL:以一等數據類型的方式支持數組,這就意味著數據表的字段、PL/PGSQL中的變量、函數的參數等等都可以是數組。數組可以包含你喜歡的任意數據類型,包括其他數組數據類型。這一點非常,非常有用。你可以使用數組完成以下事情:
</li>-
存儲調用具有任意數量返回值函數的所返回的結果,比如正則匹配函數;
</li> </ul>-
把字符串表示為多個整型字表示的ID,可用在快速文本匹配算法里。
</li> </ul>-
對屬于不同分組的多個數據值進行聚集計算,對跨表計算尤其有用
</li> </ul>-
在不需要使用昂貴的連接的情況下,對多個數據值執行行操作。
</li> </ul>-
能夠精確、確切地表示工具套件中其他應用中的數組數據。
</li> </ul>-
給你工具套件中的其他應用傳送數組數據。
</li> </ul> 我認為沒有編程語言不支持數組的,除非像 Brainfuck 和 Malbolge 那樣瘋狂的語言。 數組非常有用 ,因此非常普遍。任何不支持數組的系統就是個殘缺不全的系統,尤其是不支持數組的數據分析平臺更是如此。
</ul>-
MS SQL服務器:不支持數組。
</li> </ul> </ul>-
JSON
-
PostgresSQL: 完全支持JSON,包括很多實現JSON類型和表字段類型相互轉化的工具函數。 解析(json對象轉化為字符串)和反解析(字符串轉化為json對象)通過簡單的組件進行處理,這是PostgresSQL中一個智能的、健壯的規則。 JSON也可以在PL/V8過程化語言中以你期望的方式進行使用 – 實際上,一個JSON類型的內部狀態在一個自定義的聚合(詳見這里,它的轉化函數使用PL/V8編寫)中提供了一種非必要的/必要的兩全齊美的效果,這個 功能是如此強大、方便,感覺像是騙人的。JSON(以及它的變種,如JSONB)毫無疑問是web和其它一些數據平臺(如MongoDB、 ElasticSearch,實際上包括使用RESTful風格接口的任意系統)上進行數據傳輸的標準格式。 有理想的分析即服務供應商(或開發人員)可以留意下。
</li> -
MS SQL Server: 不支持JSON。
</li> </ul> </li> </ul>-
HSTORE
</li>-
PostgreSQL:HSTORE是PostgreSQL的一種擴展,它用一種數據類型實現了對鍵值對的快速存儲。與數組相似,這一種數據類型非常有用,因為幾乎每一種編程語言都有這一設計理念(也可以這么說,因為這一設計理念非常有用,所以幾乎每一種編程語言都采納它)。JavaScrip中的對象,PHP的關聯數組,Python中的字典,C++中的有序映射
</li>(std::map)
和無序映射(std::unordered_map)
,Go中的map等等。鍵值對存儲這一設計思想如此重要和有用,以致于把它做為一種NoSQL數據庫主要的存儲模型。好吧,我們就稱這樣的存儲模型為鍵值存儲。這一數據類型還有我們意想不到的一些非常有趣的用法。近期,有位同事問我是否有一種好的方法能把文本數組中重復的項刪除。我采用以下語句解決這個問題:SELECT akeys(hstore(my_array, my_array)) FROM my_table;
即把數組放入到HSTORE的鍵值對里,這樣就會強制刪除重復的項(因為不允許鍵重復),然后再從HSTORE中提取鍵就可以了。這再一次體現了PostgreSQL的功能多樣性。
-
MS SQL服務器:不支持鍵值對存儲。
</li> </ul>-
范圍類型
</li>-
PostgreSQL:范圍類型能夠很好的體現范圍這一概念。每一個數據庫開發人員都層遇到過
</li>start_date
和end_date
這樣的字段,而且他們中的大多數人還不得不編寫邏輯代碼來檢測是否出現重疊的現象。一些人甚至會發現在范圍上采用BETWEEN
進行連接這一處理方法由于很多原因而深陷錯誤的泥沼之中。PostgreSQL的處理方法是把時間范圍定義為一級數據類型。你不僅僅可以把時間(INT
或者NUMERIC
或者其他類型)范圍放入單獨的數據值中,而且還可以使用大量的內置操作符來安全快速地對范圍進行維護和查詢。你甚至還可以使用為范圍特別開發的索引,這樣就可以大大地提高使用操作符進行查詢的速度了。簡言之,PostgreSQL非常重視范圍,而且還提供了高效處理范圍的各種工具。我不想把這篇文章寫成一系列PostgreSQL文檔的鏈接,但是我還想提一下,我建議你親自去閱讀一下(,如果預定義的類型不能滿足你的要求,那么你可以自己定義自己需要的類型。你不需要更改源代碼,PostgreSQL數據庫提供了許多方法做這些事情)。 -
MS SQL服務器:不支持范圍類型。
</li> </ul>-
NUMERIC和DECIMAL
</li>-
PostgreSQL:
</li>NUMERIC
(以及DECIMAL
-它們兩個同義)幾乎可以達到任意精度:在小數點之前它可以支持131,072位十進制數,在小數點后可支持16,383位十進制數。如果你正在管理一家銀行,進行技術性計算,在彗星上實現飛船著陸或者做一些無法容忍四舍五入所帶來的誤差,那么你就可以使用這種類型。 -
MS SQL服務器:
</li> </ul>NUMERIC
(以及DECIMAL
-它們兩個同義)總體上支持的精度是38個十進制有效位。-
XML(很慚愧,XML已經有些過時了...)
</li>-
PostgreSQL:支持
</li>XML
數據類型,PostgreSQL數據庫有大量的函數進行XML處理。支持Xpath查詢 -
MS SQL服務器:終于,見到好的消息了!MS SQL服務器也支持
</li> </ul> </ul>XML
數據類型,同時提供大量對XML處理的方法。1.9. 腳本化
PostgreSQL 完全可以由命令來操作. 因為它在操作系統中就是這么用的 (Windows 操作系統是個例外). 這種方式既高效, 又安全. 如果有需要, 你甚至可以在手機上, 通過 SSH 登錄服務器配置 PostgreSQL(這種事, 本人干過幾次). 通過腳本, 能執行諸如: 自動部署, 性能調節, 安全, 管理 和分析任務等操作. 跟圖形用戶界面不一樣, 腳本能被復制, 版本控制, 文檔化, 自動化, 審查化(Reviewed), 批量化, 以及差異化(Diffed). 對于重要的工作來說, 文本編輯器和命令行才是王道.
MS SQL Server 通過圖形用戶界面(GUI)操作. 就算加上 Powershell 的輔助, 我也不知道它能在多大程度上實現自動化; 如果你在 Google 上搜 MS SQL Server 的用法, 得到的答案會基本上是 "在數據庫上點右鍵, 然后選 任務...(Tasks...)". 在速度慢或者高延時的網絡連接中, 使用文本命令行的效果, 遠比用圖形用戶界面好的多. 在寫這篇文章的時候, 我正準備通過 V*N, 登錄一臺位于 3,500 英里外的服務器, 執行管理操作. 這里的 WiFi, 信號相當不穩定. 謝天謝地, 我用的是 Ubuntu/PostgreSQL.
(真的有地球人通過圖形用戶界面管理服務器嗎?)
1.10.很好地整合了外部語言
由編程環境連接并使用PostgreSQL非常、非常簡單,這是因為libpq,即PostgreSQL的外部應用程序接口(API),設計的非常完美而且文檔也非常完備。這就意味著編寫嵌入到PostgreSQL里的應用將非常簡單方便,這也使得PostgreSQL功能更多,更適合于應用在數據分析上。我曾多次用C或者C++編寫了簡短的程序,它可進行PostgreSQL連接,獲取數據以及對獲取到的數據進行大量計算,其中用到了多線程或者特殊的CPU指令-不過不適合對數據庫本身進行數據填入。我還寫過這樣的C程序:它使用了setuid,從而允許在PostgreSQL里以普通用戶執行某些管理員才能完成的任務。快速而且簡練地做到這些真的很方便。
MS SQL服務器整合的外部語言的方法各有不同。有時候你需要安裝其他驅動。有時候你需要創建類來存儲你所查詢的數據,這種情況下就意味著你在編譯時就要知道數據是什么樣子。最為重要的是,它的文檔讓人困惑、一團糟,要做成一件事就要
耗費不必要的時間,而且非常痛苦。
1.11 文檔
數據分析基本上意味著你得是一個“萬事通”。我們使用各種廣泛的編程語言和工具。(在我的腦子里,我工作中使用的編程/腳本語言有PHP、JavaScript、Python、R、C、C++、Go、三種SQL方言、PL/PGSQL和Bash。)不要期望你可以預先學習所有你需要的東西。干好工作經常依賴于閱讀文檔。一個有良好文檔的工具更有用,它使得分析師更高產并且完成高質量的工作。
PostgreSQL的文檔非常優秀。它涵蓋了所欲的東西,但是又不只是一個參考手冊,其中有很多例子、提示、有用的建議和指南。如果你是一個高級程序員并且想要真正的深入,你可以很容易的閱讀PostgreSQL的源代碼,所有這些都是開放的并且可以自由獲取。這個文檔也很有幽默感:
第一個世紀開始于公元0001-01-01 00:00:00 ,雖然當時他們并不知道。這個定義在所有使用公歷的國家使用。沒有世紀編號為0的,直接從-1世紀跳到了1世紀。如果你對此不贊同的話,請寫下你的抱怨到這個地址:羅馬教廷圣彼得大教堂教皇收。
MS SQL服務器的文檔都在MSDN上,而且很不友好、龐大、煩亂。由于微軟是個大企業,而且其客戶基本很保守、缺乏幽默感,因此這樣的文檔就很“適合商務”-即啰啰嗦嗦、令人厭煩和枯燥。它不但在開發日期算法的時候沒有參考天主教的歷史,而且還異常乏味,藏匿在不必要的分類以及炫耀式的官方術語之下,難以理解。試試這個:進入MS SQL服務器2012的 產品文檔頁面,試試能從這里獲取一些有用的信息。或者閱讀下面摘錄的部分(我承諾,絕不是精心挑選的):
部分report定義就是XML格式的report定義文件的一部分。在可以通過創建report定義來創建部分report,然后在這個report里選擇report項,把它們做為多個部分report單獨進行發布。
是不是一開始就不知道“report"是究竟是什么?
1.12.日志記錄確實有用
MS SQL服務器的日志分散在幾個地方-錯誤日志、Windows事件日志、分析器日志、代理日志和安裝日志。要實現對這些日志的訪問,你還需要各種級別的權限,而且還需要使用多個工具,其中一些工具是只有圖形用戶界面下才可以運行的。也許像Splunk這樣的軟件能幫助你對這些日志進行自動收集和解析。我沒有試過,我也不知道別人有沒有試過。有關這個問題的谷歌搜索結果得到的信息少的讓人吃驚,幾乎沒有什么用處。
默認情況下PostgreSQL的所有日志是存儲在一個地方。你可以通過更改文本文件的幾個設置,讓數據庫記錄日志記錄為CSV文件(由于我們現在正在討論的是PostgreSQL,因此這兒的CSV是正常的,而不是非正常的)。你很容易設置日志級別為任何級別:由“不記錄任何日志”到“全面記錄分析和調試的輸出”。日志文檔甚至包含CSV格式的日志文件導入的目的表的DDL語句。你還可以把日志記錄到標準錯誤或者系統日志或者Windows事件日志里(當然,假設你正在Windows系統上運行PostgreSQL)。
日志本身即是人可閱讀的,也是機器可閱讀的,而且包含的數據可能是系統管理員非常關注的。誰在什么地點,什么時間登入和退出?正在執行哪一條查詢語句,是由誰來執行的?他們使用了多長時間?每一次批處理里提交了多少個查詢?由于數據是以非常完善的CSV格式存儲的,因此在R或者PostgreSQL自身或者Python的matplotlib或者其他你喜歡的軟件里,對其進行可視化和分析都非常容易。像top,iotop和iostat這些Linux應用所提供的豐富的信息遠超過日志提供的信息,因此你可以非常容易、可靠地使用你可能需要的所有服務器遠端測控技術。
1.13支持
PostgreSQL該如何贏得這一局呢?每個人都知道大型商業公司為昂貴的旗艦企業級產品提供難以置信的技術支持,而同時免費軟件則一點也沒有。
當然,這都是廢話。商業產品當然為支持它們的人民提供支持,因為它們花了錢的。在滿足SLA條款時他們總是做到最少。在我敲這篇文章時,我知道有幾個IT專家正在等待一個主要硬件供應商來幫助它們解決一個 £40,000服務器的性能問題。它們已經和供應商談了數周時間。應供應商的要求,他們花費時間和精力來運行擴展測試和基準測試。目前,供應商的臉上混合著無能、低效和淡漠。而那個£40,000服務器正坐在那非常非常慢的運行著,它的用戶每周工作70小時以試圖保持進度。
數年來,我見過昂貴商業軟件的許多許多問題,包括從bug到性能問題、兼容性問題、不完備的文檔等一切問題。有時這些問題導致用戶熬至深夜或周末加班,有時又導致錯過最后期限并激怒客戶,有時又冒法律和聲譽的風險。
每一次都發生同樣的事情:最終用戶混合著血、汗水、淚水、Google和熬夜將問題解決。我從未見過供應商趕來救急并將一切都搞定。
那么PostgreSQL的支持是什么樣的呢?有兩次我向PostgreSQL郵件列表請求幫助,在24小時內我從 Tom Lane那收到了回復。花了點時間點開鏈接并閱讀wiki,那哥們不只是PostgreSQL的首席開發者,還是一個知名得計算機程序員。沒啥說的,他的建議就是好的建議。其中一次,我問了一個關于實現跨函數調用持久內存分配的最好方法的問題,Lane用我應該學習的PostgreSQL的特性回復了我,并且給我的問題提出解決方案,另外他就我的試驗性解決方案(一個C靜態變量)為什么是垃圾這個問題,給我列出了一份非常好的原因清單。這種支持你是買不到的,但是你可以從熱情的開源開發者社區取得支持。(⊙o⊙)哦,我有沒有提到那個數據庫軟件,還有那些來自于廣受好評的程序員的充滿幫助的忠告和建議總共花費了 £0.00?
我說的支持, 是指技術上真正解決問題的支持. 有些人(一般都是那些沒有過這些產品的) 一提到技術支持合同, 想到更多的是法律方面的問題 – 他們并不關心是不是會真的獲得幫助. 純粹就是想找人臭罵幾句, 發泄一下. 我在這里有討論.
(如果你真的想花錢購買技術支持, PostgreSQL 有許多提供專業技術支持的機構可以選擇. 跟那些以銷售商業軟件為主, 提供技術支持為輔的供應商不同. 這些機構提供技術支持的質量決定了他們的生死存亡. 所以這方面沒什么好擔心的.)
1.14靈活的,可腳本化的數據庫轉儲
我已經談論過可腳本化,不過數據庫轉儲是如此重要,所以他們在本文中占有一席之地。PostgreSQL的數據庫轉儲特別靈活,采用命令行驅動方式(使得它很容易實現自動化和腳本化)并且記錄良好(與PostgreSQL其他部分一樣)。這使得數據庫遷移、復制和備份這三種重要和嚇人的任務可控、可靠和可配置。而且,備份可以以空間壓縮的格式或者純文本的SQL來處理完整的數據,兩者都是人類可讀并且可執行。可以備份單個表或整個數據庫集群。用戶可以按他喜歡的方式去做。只需要一點點工作和小心的選擇幾個選項,甚至可以生成一個僅有DDL純文本的SQL語言的PostgreSQL備份,該備份可在不同的RDBMS中執行。
而MS SQL Server的備份則是以一個專有的、無記錄的、不透明的二進制格式進行。
1.15可靠性
無論是 PostgreSQL 還是 MS SQL Server 都不希望發生意外,不過MS SQL Server有一個奇怪的失敗模式,我遇到過不止一次:它的事物日志變的巨大并且阻止了數據庫正常工作。理論上日志可以被截斷或刪除,但是文檔中對此類動作又充滿了可怕的警告。
而PostgreSQL只是坐在那里并且將工作做好。在日常使用中我從來沒有遇到過一次PostgreSQL數據庫意外。
1.16 易于安裝和更新
這個有什么關系嗎?當然有。基礎設施的靈活性比以往任何時候都要重要,并且這個趨勢只會繼續下去。多年穩坐不動的胖服務器安裝的日子已經一去不復返。現在全部都是關于快速、可靠、靈活的配置和跟上尖端技術。常言道,時間就是金錢。
我裝過MS SQL Server幾次。我已經記不清自己到底安裝PostgreSQL多少次了,很可能最少有50次了。
安裝MS SQL Server非常的慢。它需要下載大量數據(現在還有誰使用物理媒介進行安裝?)而且臭長,只有死板的進度條說明這貨還活著。如果你沒有安裝正確版本的.NET或者正確的Windows服務包的話,你有可能安裝失敗。這些都需要你的系統管理員找一整塊時間來做。
安裝PostgreSQL的canonical 方法是簡單至只敲一條命令(從一個Linux倉庫),就像這樣:
sudo apt-get install postgresql
這需要花費多長時間?我只是通過在云中運行一個廉價的虛擬機,然后用上面的命令安裝PostgreSQL來進行測試。只花了 16秒。這是下載和安裝的全部時間。
至于更新,任何軟件支持的Linux repo是非常容易從repo更新補丁。因為repo很聰明,PostgreSQL不太臃腫,下載的更新和應用,都是小而快的,并且是有效的。
我不知道怎么樣容易地讓MS SQL Server更新。我知道,很多在生產中的MS SQL Server在某些組織的版本還是2008 R2...
1.17.構建軟件捐贈模塊
貌似PostgreSQL這一大堆的設置還不夠,它又弄了一堆叫做構建軟件捐贈模塊的擴展。里面有一些函數,類型以及對服務器核心設置元素不那么重要的的實用功能的庫。有模糊串匹配,快速整形數組處理,外部數據庫鏈接,密碼,UUIO生成,樹形數據類型和負載的庫。還有一些模塊甚至什么也不做,只是為了讓開發者和高級用戶開發自己的擴展和功能。
當然,這些擴展安裝十分瑣碎。比如安裝fuzzystrmatch的擴展,需要這么做:
CREATE EXTENSION fuzzystrmatch;
1.18. 自由與免費
PostgreSQL 既自由又免費, 這兩樣都很重要。
首先,PostgreSQL 是個開源軟件, 在授權方面很自由。也就是說,你可以隨心所欲地使用和修改它。包括發布包含或基于它的軟件。 不論何時, 何地, 想怎么用就怎么用。
免費包含兩個重要方面。 首先, 如果你也像我一樣,在大機構中就職,花公家的錢,就會牽扯到許多繁文縟節。各種繁雜手續的拖延, 耗盡精力和激情; 抵制了創新。其次, 由于 PostgreSQL 是免費的, 許多開發人員, 實驗人員,黑客,學生, 發明家, 科學家等等 (基本上都是窮書生)都在使用。慢慢地發展成為一個強大的社區。來自這群精英們的支持和貢獻不斷增長。 結果越做越好, 創新能力越來越強, 各種問題的解決方案也越來越多。更多的時間和精力用來解決更重要的問題。
2. 反駁
讓我不解的是, 大家經常無視上面的論點和論據, 用一些錯誤的, 奇怪的, 甚至荒唐透頂的觀點來反駁 PostgreSQL 。 比如:
2.1. 不是說大牌廠商更可靠么!
絕對不是。這就好比說 "沒人會因為購買 IBM 而被炒魷魚"。 搞笑的是, 如果你谷歌下, 就會發現,排在第一的是 Wikipedia 的這篇文章, 恐懼,不確定,懷疑 。 最搞的是, 里面第一個提到的就是微軟。我發誓我沒動過 Wikipedia 那篇文章,我看到的時候, 它就是這么寫的。
在給客戶提供服務的數據分析領域(client-serving data analytics),容不下半點差錯。如果你因為搞砸了一份工作而損害了自己的名聲,別指望軟件供應商能幫你挽回。如果被起訴, 倒是有可能從他們那里得到一些賠償, 前提是, 他們確實有錯。 MS SQL Server 在技術上倒是沒有什么錯。他們不過是發布了一件垃圾產品,然后坦白的在文檔里告訴你,這件產品有多爛。它運行起來就像最初設計時期望的那樣。 問題是它的設計本來就很爛。不能因為你挑選數據庫的時候, 不夠盡職盡責, 就去控告微軟。
就算你成功地讓供應商背上黑鍋,已經搞砸的工作和憤怒的客戶, 是不可逆轉的。他們才不管是不是 MS SQL Server's 錯誤地把 UTF-16 當成 UCS-2 處理, 導致在進行子字符串處理的時候,代理對(surrogate pair) 被截斷。結果無法識別引起錯誤的關鍵字(incriminating keyword)。輕者,他們依然想要分析結果(也許還要給他們些折扣)。嚴重的,他們說你做的東西不能用,直接不要了。當他們的文檔沒有半點歉意的告訴你,你的數據可能會被悄無聲息的破壞掉,而你卻把全部的希望都寄托在他們的數據庫上。一旦出問題, 你覺得你能怪他們嗎?
降低風險的最好辦法就是把事做對。優秀的工具能幫你輕松做到這一點。優秀的工具, 我指的是 PostgreSQL 啦。
2.2 不過,如果PostgreSQL的作者掛了怎么辦?
假如MS SQL Server的作者同樣屎掉了會發生什么——結果是一點事沒有。當然了,沒啥說的“PostgreSQL的作者”和“MS SQL Server作者”一樣毫無意義。根本就沒有這回事。
有個前輩,是一個IT基礎設施監管人到是問過我這個問題(是關于Hadoop,不是PostgreSQL)。大家好像對所有的開源軟件的認識都有誤區,就好像這些軟件是躲在媽媽的地下室的獨行俠寫的一樣。這顯然不是真的。大型開源項目如PostgreSQL和Hadoop是由擁有高級技能的開發者團隊所寫,他們經常受到商業贊助。在它們的核心,PostgreSQL的開發模式就像MS SQL Server的開發模式一樣:有某個組織向一個大型程序員團隊支付報酬。不會有單點失效的問題。
但是兩者至少有一個重要的差異: PostgresSQL的源碼是開放的,因此大批高級程序員能夠進行代碼走查、代碼優化、貢獻代碼、提高代碼的質量并理解代碼的邏輯。 這是PostgresSQL為什么比MS SQL Server更好的一個原因。
關鍵一點,由于開源軟件往往由那些非常關心代碼質量的人編寫(經常是由于他們打賭他們可以保證軟件盡可能好用),因此軟件開發通常采用最高的標準( PostgreSQL, Linux, MySQL, XBMC, Hadoop, Android, VLC, Neo4JS, Redis, 7Zip, FreeBSD, golang, PHP, Python, R, Nginx, Apache, node.js, Chrome, Firefox...)。 另一方面,商業軟件通常由某一委員會設計,在公司的格子間里開發,并且編碼的時候通常沒有適當的指導和靈感( Microsoft BOB, RealPlayer, Internet Explorer 6, iOS Maps, Lotus Notes, Windows ME, Windows Vista, QuickTime, SharePoint...)。
2.3 但是開源軟件不安全、不穩定、不值得信任、不適用于企業級生產等等!
這些東西都沒法說。說這些的人都是些很無知的人,你應該忽視他們,或者你自我認為很大方,你可以教育教育他們。好吧,我認為我是一個大方的人:
安全:一個舊的誤解是閉源軟件更安全,我會簡要總結幾個好的原因(讀一讀這個鏈接吧,很棒):保密不意味著安全;開源審查相比閉源來說更有可能找到弱點;正確的審查開源軟件很難或不可能在其中構建一個后門。如果你喜歡軼事、邏輯論證什么的,想想Microsoft Internet Explorer 6,一個曾經的企業級閉源商業軟件,被廣泛的認為是有史以來最不安全的軟件。Rijndael算法,作為AES背后的算法,世界上的政府用來保護頂級秘密信息,是一個開放標準。在任何案例中,關系型數據庫不是安全軟件。在IT世界里,“安全”有點像美國的“支持我們的軍隊(support our troops)”,或紙牌中的王牌“想想孩子(think of the children)”,它可以否決其他所有,包括常識和證據。注意別上當。
- 可靠性:Windows有一點比較有名,那就是它的不穩定性,雖然現在好了很多。(Windows 9x的以毫秒計的內部時間計數器達到32位無符號整型數的上限時,也就是 2 32毫秒以后或大概49.7天, 就會自動發生意外。我一直想試試來著。)在服務器市場中Linux占主導地位,服務器的穩定性是很重要的,Linux通常用年 計量時間。Internet Explorer一直以來與web標準不兼容(現在還這么干),導致了網站碎片或功能不當;該領域的領頭羊是開源瀏覽器Chrome和Firefox。 Lotus Notes是一個片狀、經常發生問題、亂七八糟的玩意兒,也只有雷鳥還正常工作。我不止一次看到過MS SQL Server的事務日志吹氣球一樣膨脹,然后把自個搞崩潰了,而PostgreSQL從來不會發生這樣的事。 </ul>
-
誠信:除非過去幾年里你一直在石頭里生活,否則你就知道愛德華斯諾登是誰。感謝他,我們確切的知道了誰不能相信:政府以及他們插手的大型組織。自從斯諾登公布后,我們清楚的知道NSA的后門存在于大量的各種產品中,包括硬件和軟件,這些都是個人或組織用來保證數據安全的。
</li> </ul>
唯一預防方法是開放代碼審查。如果你使用有版權的閉源軟件,你沒有辦法知道隱藏在兜帽下面的它們真正在做什么。感謝斯諾登,我們現在知道了放棄自己秘密的非常棒的方法。-
企業適用性:
企業不用開源軟件的說法純粹是胡說八道。如果你在一家無視開源軟件的機構技術部門就職,那就盡情享受吧。 因為它離倒閉不遠了。
</li>-
在我寫本文的時候,全世界 500 臺超級計算機中, 有 485 用的是 Linux 。
</li> -
到 2014年7月份為止,Nginx 和 Apache, 這兩個開源服務器,已經為超過70%的,問量最大的網站提供服務。
</li> -
國際空間站(有史以來, 最昂貴的人造物)的電腦,已經在2013年,把 Windows 替換成 Linux。 為的是提高系統的穩定性和可靠性。
</li> -
Skype 的后臺數據庫 (說起來好笑,這家公司現在已經被 Microsoft 收購了) 用的就是 PostgreSQL.
</li> -
GCHQ 最近的報告指出,Ubuntu Linux 是常見的操作系統中,最安全的。
</li> -
大型強子對撞機是全世界最大的科學實驗設備。支撐它的 IT 設備, Worldwide LHC Computing Grid, 是全世界最大的計算網格。 它能每年處理 30 PB 的數據,跨躍36個國家, 170 個計算中心。大部分用的都是 Linux 。
</li> -
Hadoop, 許多想在大數據領域占有一席之地的大型咨詢機構的新寵,也是開源的。
</li> -
此外,還有: Red Hat Enterprise Linux; CEntOS (Community Enterprise OS); SUSE Linux Enterprise Server; Oracle Linux; IBM Enterprise Linux Server 等。
</li> </ul> </ul>2.4. 可是 MS SQL Server 能利用多個 CPU 內核處理單條查詢!
當你的查詢語句運行時, 性能受限于 CPU 而不是 IO,那么 MS SQL Server 就比較有優勢。但是在現實的數據分析中, 這種情況幾百年也難得見一回。當這種少見,又特殊的情況使得 CPU 變成性能瓶頸的時候。依靠數據庫系統是解決不了問題的。他們又不擅長數字密集運算。
當服務器需要同時處理多個任務的時候(服務器基本上都這樣) MS SQL Server 就沒有什么優勢了。PostgreSQL 用的是多進程模式 -- 一個進程負責處理一個數據庫鏈接,也就是說,它也用了多個 CPU 內核。當然, 具體怎么分配, 那是操作系統的事。
我懷疑,MS SQL Server 的自定義聚集程序集(custom aggregate assemblies) 用的也是這種并行查詢機制。把聚集操作分配到多個線程中計算, 然后再將結果合并到一起,有點類似 MapReduce 的作風。 我還懷疑, 這就是為什么MS SQL Server 的聚集語句不能使用 ORDER BY 子句的原因。所以, 恭喜,PostgreSQL 也是可以利用多個 CPU 內核的。只是你不能使用基本字符串匯總(basic string roll-up)。
2.5. 我只會 MS SQL Server , 沒用過 PostgreSQL!
如果你寧愿繼續使用那個臃腫, 笨拙, 不穩定的系統, 也不愿意花點時間, 學一門稍微有些區別, 但是又比較簡單查的詢語言. 那就求神拜佛, 別在下次面試的時候遇到我.
2.6. 難道數以億計的 Microsoft 用戶都錯了?!
這是以前和我一起工作過的一名資深的數據分析師問的問題. 我的回答是 "這世上有 1.5 億 穆斯林教徒, 1.2 億 天主教徒. 不見得他們全都對". 所以, 就算一億個人都錯了, 也沒什么奇怪的. (這里指的是 2.7 億個人都錯了.)
2.7. 真要這么好, 怎么可能會免費!
大家都喜歡這么說。 真是替他們感到可惜, 因為他們無法說服別人不為錢做事。 就當他們不知道,這世上還有慈善機構, 自愿者,和其他純粹就是做點貢獻的人存在好了。
這個觀點, 還建立在另外一個荒唐的假設上--開源軟件開發無利可圖。 大型企業開之所以開放源代碼,花錢請人開發和維護這些代碼, 無非是能從中收益。設想下,如果你把代碼開源給他人使用,別人就會給你軟件免費修改 Bug,添加新功能, 審查代碼,測試, 甚至宣傳。如果你的產品做的足夠好, 用的人也就會越來越多,自然就會形成被業界廣為接受的標準。作為支持和發布該軟件的供應商,你當然會在市場上占據相當有利的地位。 就算你是個利己主義者, 開源也是個明智的選擇。比如說,我現在就自己花錢做網站,替 PostgreSQL 做宣傳。可能 Teradata 或 Oracle 也不錯。但是他們太貴了, 我用不起, 所以也就沒有給他們宣傳。
2.8 但是你存在偏見!
好吧,我確實偏向于更好的數據庫。本文的目的是演示,用事實說話。偏見是有理由的,或者更確切的說,這根本不是偏見,而是偏好。在任何案例中,PostgreSQL都是免費軟件,所以我沒有經濟上的動機。我也沒有給它寫過什么(除了我提交過一次bug修復),所以這也不是我個人的問題。并且和我關系近的人中也沒有一個參與PostgreSQL的開發與支持。我只是想用好的工具來把我的工作盡可能的干好。為什么會有如此多的疑問呢??
2.9. 但是“PostgreSQL"是個愚蠢的名字!
這是可以證明的;它相當的尷尬。容易發錯音并且也經常被不正確的大寫書寫。人們選擇工業軟件時對”二逼名字“不格外顧慮倒不妨它是一份干得漂亮的活。
盡管如此,對SQL服務器來說,MS SQL Server是微軟選擇的所有可能名字中最沒勁的一個。無論哪個詞都有6到8個音節,這取決于你是否將"Microsoft"縮寫和你是否將它念做“sequel"或"ess queue ell",一個產品的名字這也太長了點。雖然微軟有一個非常非常長名字的產品-或許這是它一直以來最偉大的成就來了
Microsoft? WinFX? Software Development Kit for Microsoft? Pre-Release Windows Operating System Code-Named "Longhorn", Beta 1 Web Setup
我數了數有38個音節。哇靠。
2.10.但是SSMS比PGAdmin要好點!
它更流暢,必須的嘛。它也更好。它有代碼自動完成功能—雖然我總是把這個功能關掉因為這個功能總是壞我事—而且每次它讓我走出段名或表名的困局的時候,至少有一件它做的好的事,例如自動-”糾正“一個普通的SQL關鍵詞”table"為一個微軟的奇怪的玩意“TABULATION_NONTRIVIAL_DISCOMBOBULATED_MACHIAVELLIAN_GANGLYON_ID”或別的什么東西
事實上中止SQL并且看看GUI中的結果,PGAdmin很不錯。它只是不華麗而已。
還有另外一個東西:psql。它是PostgreSQL的命令行SQL接口。它是真的真的非常好。它有大量有用的目錄查詢功能。它可以聰明的顯示扁平化的數據。它還有tab鍵補齊功能,不像SSMS的代碼補齊哪有,它確實有用,因為它是根據上下文感知的。打個比方,如果你鍵入 DROP SCHEMA t 并且按下tab鍵,它將會給你提供名稱以“t”開頭的schema(如果只有一個的話,就會自動補齊)。它也可以讓你在文件系統中來回跳轉,也可以使用像內聯的vim那樣特別強大的文本編輯器。它自動保留了已執行命令的列表。它還提供了方便的有用的數據導入導出功能,包括"COPY TO PROGRAM"這樣的特性,利用管道和命令行提供了另一個級別的靈活性和數據控制能力。它靈活的使用屏幕空間。快速并且方便。你能夠通過一個SSH鏈接甚至是較慢的鏈接來使用它。
唯一嚴重的問題是,對于那些害怕命令行和敲鍵盤,還想成為數據分析師的人來說有點不合適。
2.11MS SQL Server可以直接從Excel導入!
是的。那又怎樣?Excel可以輸出到CSV文件(比較難得的是,微軟Excel的CSV導出代碼工作的挺好),PostgreSQL可以從CSV導入。當然了,多了一步。在分析平臺中,能夠直接從Excel導入是一個很重要的特性嗎?
2.12PostgreSQL比MS SQL Server要慢!
更確切的說應該是“MS SQL Server稍微更寬容,如果你不知道你在做什么的話”。
對于某些操作,PostgreSQL確實要比MS SQL Server慢,最簡單的例子可能就是COUNT(*)了,在MS SQL Server中就是一瞬間的事(我是這么想的),在PostgreSQL中就需要全表掃描(這是由于它們使用的是不同的并發模型)。PostgreSQL是一個慢開箱即用產品,因為它默認配置是使用少量系統資源,不過對于任一系統都已經被調整用于處理大量工作,所以天生的開箱即用性能不是一個值得爭論的事情。
我曾經看到過PostgreSQL因為慢而被批評,因為它在一個大型表中需要花很長時間來做一些巨大的、復雜的正則表達式操作。不過每個人都知道,正則表達式操作是一種非常昂貴的計算。在任一案例中,PostgreSQL的什么被用來做比較呢?當然不是MS SQL Server了,因為它做不了正則操作。
PostgreSQL支持非常聰明的索引操作,比如范圍型索引和trigram索引,對于某一類操作來說比MS SQL Server有數量級的速度。不過只有你知道如何合適的使用這些特性才行。
你從最偉大的程序語言那里得到了巨大的靈活性支持,并且聰明的數據類型允許面向基于PostgreSQL的解決方案,它勝過基于MS SQL Server的解決方案好幾個數量級。 查看我更早的例子。
無論如何,關于速度的爭論不僅僅限于計算機的時間(執行時間); 開發人員的時間也是一樣。 這就是為什么像PHP或者Python這么流行的原因, 盡管實際上C的執行速度比他們快。 雖然他們運行慢,但是他們開發更快速。 你要花一個小時編寫可維護的,優雅的SQL就被允許運行一個小時, 還是花費三天寫一個多bug的程序, 盡管它的工作時間只有45分鐘?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-