閱讀899 返回首頁    go 技術社區[雲棲]


SQL vs NoSQL:如何選擇?

在前一篇文章中,我們討論了 SQL 與 NoSQL 數據庫之間基本的區別。接下來,我們我們將應用我們在特定場景中的知識來確定最佳的選擇。

回顧一下:

SQL 數據庫:

在表中存儲相關聯的數據

在使用之前需要定義表的一個模式

鼓勵標準化減少數據冗餘

支持從多個表中檢索相關數據表連接在一個單一的命令

實現數據完整性規則

提供事務使兩個或兩個以上的成功或失敗的數據更改作為一個原子單元

可以擴展(有一些努力)

使用一個強聲明性語言查詢

提供足夠的支持,專業技能和工具。

NoSQL 數據庫

將相關聯的數據存儲在類似 JSON 格式,名稱-值 

可以保存沒有指定格式的數據

通常必須規範化,所以一個項目的信息包含在一個文檔裏

應該不需要連接(假設使用規範化的文檔)

允許任何數據被保存在任何時候任何地方,不需要驗證 

保證更新一個文檔 - 但不是多個文檔

提供出色的性能和可伸縮性

使用 JSON 數據對象查詢

是一個新的、令人興奮的技術。

SQL 數據庫是一個理想的項目,確定好了需求和健壯的數據的完整性是至關重要的。NoSQL 數據庫是無關理想,不確定的或者不斷變化的數據需求 ,在速度和可伸縮性上更重要。 簡單的術語:

SQL 是數字。它最適合明確的定義,精確規範的獨立項目。典型的使用案例是在線商城和銀行係統。

NoSQL 是模擬。它最適合無固定要求的組織數據。典型的使用案例是社交網絡,客戶管理和網絡分析係統。

一些項目要精準的符合。如果你有較淺的話,任何一種選擇都是可行的,或者自然的非規範數據。但是請注意這些簡化示例場景與全麵的概括!你比我更了解你的項目,我不建議切換從SQL到NoSQL或反之亦然,除非它提供了可觀的效益。這是你的選擇。在項目的開始要考慮利弊,你不能出錯。

場景一:一個聯係人列表

讓我們重新發明輪子,實現一個基於sql的通訊錄係統。我們最初接觸表的時候,天真的定義以下字段:

id (主鍵ID)

title (標題)

firstname (姓)

lastname (名)

gender (性別)

telephone (電話)

email   (郵箱)

address1 (地址1)

address2 (地址2)

address3 (地址3)

city       (城市)

region    (區/縣)

zipcode    (郵政編碼)

country    (國家)

問題一: 很少人隻有一個電話號碼。我們可能需要至少三個號碼:一個座機,一個移動電話,一個工作電話。但是有多少個號碼無關緊要——有些人、有些地方需要更多。讓我們創建一個單獨的 telephone 表,這樣的話他們想要多少聯係人都可以。這也讓我們的數據標準化了——我們不需要沒有號碼的聯係人顯示為NULL。

contact_id

name (文本,例如座機號,工作手機等)

number

問題二:Email地址有同樣的問題,因此我們也創建一個類似的 email 表:

contact_id

name (text such as home email, work email, etc.)

address

問題三:我們可能不想輸入一個(地理位置的)地址,或者我們想輸入多個地址,工作地,家裏,度假住所等。因此我們需要一個新的 address 表:

contact_id

name (text such as home, office, etc.)

address1

address2

address3

city

region

zipcode

country

我們原來的 contact 表簡化成:

id

title

firstname

lastname

gender

太棒了——我們有了一個能存放任意聯係人的任意多個電話號碼,Email 地址和住址的標準化數據庫。不幸的是……

Schema是固定不變的

我們沒有考慮到聯係人的中間名字、出生日期、公司或職位。我們添加多少字段都沒關係,我們很快會受到更新的需求要添加備注、紀念日、關係狀態、社交媒體賬號、內腿測量值、最喜歡的奶酪類型等字段。預測所有選項是不可能的,因此我們可能需要一個 otherdata 表,用來處理名字-值對。

數據是碎片化的

對開發者或者係統管理員來說,檢查數據庫並不容易。程序邏輯會變得更慢、更複雜,因為利用單個 SELECT 和多個 JOIN 語句查詢聯係人數據不太實際。(你可以這麼做,但是結果可能需要包含 telephone,email,和 address字段的每一種組合:如果有個聯係人有三個電話號碼,五個Email地址和兩個住址,那麼SQL查詢將會產生30條結果。) 最後,全文搜索很困難。如果有人輸入字符串"SitePoint",我們必須檢查所有的表,看看它是否為聯係人名字、電話、Email或者住址的一部分,並且需要做相應的排序。如果你用過WordPress的搜索功能,你就會明白這有多虐心。

選擇NoSQL

我們的聯係人數據關注的是人。他們難以預測,在不同的時間有不同的需求。使用NoSQL數據庫,聯係人列表將會從中受益。數據庫將一個聯係人的所有數據存儲在一個單獨的文檔裏的contacts 集合裏。

{
  name: [
    "Billy", "Bob", "Jones"
  ],
  company: "Fake Goods Corp",
  jobtitle: "Vice President of Data Management",
  telephone: {
    home: "0123456789",
    mobile: "9876543210",
    work: "2244668800"
  },
  email: {
    personal: "bob@myhomeemail.net",
    work: "bob@myworkemail.com"
  },
  address: {
    home: {
      line1: "10 Non-Existent Street",
      city: "Nowhere",
      country: "Australia"
    }
  },
  birthdate: ISODate("1980-01-01T00:00:00.000Z"),
  twitter: '@bobsfakeaccount',
  note: "Don't trust this guy",
  weight: "200lb",
  photo: "52e86ad749e0b817d25c8892.jpg"}

在這個例子裏,我們沒有存儲聯係人的頭銜或者性別,我們還添加了一些數據,而這些數據不需要應用到任何其他聯係人。沒關係——我們的NoSQL數據庫不會介意,我們還可以隨意添加或移除字段。

由於聯係人數據在單獨的文檔裏,我們可以用一條查詢語句獲取一部分或全部信息。全文搜索也變得簡單;在MongoDB裏,我們可以這樣定義 contact 中的所有文本字段的索引:

db.contact.createIndex({ "$**": "text" });

然後執行全文搜索:

db.contact.find({
  $text: { $search: "something" }});

場景二:社交網絡

社交網絡可能使用類似的聯係人數據存儲,但是它會根據功能集合擴展,比如關係鏈、狀態更新、發送消息和”讚“。這些功能可能會根據用戶需求來實現或者移除——無法預測它們會怎樣演進。

另外:

大部分的數據更新都來自單個源:用戶。任何時候我們不太可能同時更新兩條或更多記錄,因此不要求類似事務控製的功能。

盡管有些用戶可能認為,狀態更新失敗不可能引起係統崩潰或經濟損失。應用程序的接口和性能比數據完整性優先級更高。

NoSQL看來是個好的方案。它允許我們快速地實現存儲不同類型數據的功能。例如,可以用單個文檔裏的 status 集合替換所有用戶的過時的狀態更新。

{
  user_id: ObjectID("65f82bda42e7b8c76f5c1969"),
  update: [
    {
      date: ISODate("2015-09-18T10:02:47.620Z"),
      text: "feeling more positive today"
    },
    {
      date: ISODate("2015-09-17T13:14:20.789Z"),
      text: "spending far too much time here"
    }
    {
      date: ISODate("2015-09-17T12:33:02.132Z"),
      text: "considering my life choices"
    }
  ]}

文檔可能會變得很長,但我們可以獲取數組的子集,比如最近的更新。每個用戶的所有的曆史狀態記錄都能被快速搜索到。

現在假設我們想在發布更新的時候引入表情符號選擇。這涉及到給 update 數組裏的新記錄添加圖引用。不像 SQL 存儲,沒必要把之前消息裏的表情符號置為 NULL——我們的程序邏輯可以顯示默認圖片或者沒有圖片,如果沒有設置表情符號的話。

場景三:倉庫管理係統

考慮一個監控倉庫貨物的係統。我們需要記錄:

送達倉庫並被分配到指定位置的物品

倉庫內物品的移動,也就是重新整理庫存,以便讓同樣的物品放在相鄰的位置

訂單以及後續將物品搬出倉庫,準備發貨

我們的數據需求:

  1. 通用的物品信息,比如包裝數量、尺寸和顏色等可被存儲,但這些是我們可以識別並應用到任何物品上的離散數據。我們不太可能關注細節,例如筆記本處理器速度或者智能手機的電池壽命。

  2. 最小化出錯的可能是必要的。我們不能讓物品憑空消失或者移到已經有別的物品存放的位置。

  3. 簡單來說,我們在記錄物品從一個物理區域到另一個物理區域的轉移——或者從A位置移走,放到B位置。這是同一個動作的兩次更新。

我們需要一個具備強製數據完整性和事務支持的健壯存儲係統。(當前)隻有 SQL 數據庫滿足這些需求。

表現自己!

我希望這些場景有所幫助,但是每個項目是不同的,最終,你需要做出自己的決定。(雖然,我們開發人員擅長於證明我們的技術選擇,不管他們有多好!)

最好的建議:顯露你自己盡可能多的技術。這些知識可以讓你對SQL或者NoSQL做出一個理性和情感上公正的判斷。祝您好運。

文章轉載自 開源中國社區[https://www.oschina.net]

最後更新:2017-07-08 11:03:30

  上一篇:go  集群管理器和調度器 Nomad
  下一篇:go  新加坡政府開放數據門戶網站