SQL(結構化的查詢語言)數據庫是過去四十年間存儲數據的主要方式。20世紀90年代末隨着Web應用和MySQL、PostgreSQL和SQLite等開源數據庫的興起,用戶爆炸式的增加。javascript
NoSQL數據庫自從20世紀60年代就已經存在了,直到MongoDB, CouchDB, Redis 和 Apache Cassandra等數據庫的流行才獲取了更多的關注。php
你能夠很容易地找到許多關於如何使用一款特定的SQL或NoSQL的教程,可是不多有討論你爲何優先的使用一款而不適用另外一款。我但願我可以填補這個空白。在這篇文章中將會介紹它們之間的不一樣。在後續的文章中,咱們將會根據典型的場景來肯定最佳的選擇。html
大多數的例子都適用於流行的關係型數據庫MySQL和MongoDB NoSQL數據庫.其它的SQL/NoSQL也是相似的,可是在語法和特色上會有一些細微的差異。java
在咱們進一步討論以前,咱們先不去考慮各類觀點......mysql
觀點一:NoSQL將會取代SQLsql
這個觀點就像是說船將會取代汽車,由於船是一種新的技術同樣,這是不可能發生的事情。SQL和NoSQL有着相同的目標:存儲數據。它們存儲數據的方式不一樣,這可能會影響到你開發的項目,一種會簡化你的開發,一種會阻礙你的開發。儘管目前NoSQL數據庫很是的火爆,可是NoSQL是不能取代SQL的--它僅僅是SQL的一種替代品。mongodb
觀點二:NoSQL要比SQL好/壞數據庫
一些項目可能會更適合使用SQL數據庫,然而一些項目可能會比較適合使用NoSQL,有些項目使用哪種均可以很好地達到預期的效果。本文不支持任何一方,由於沒有一種方式可使用到全部的項目中去。npm
觀點三:SQL與NoSQL之間有明顯的差異編程
這個觀點並非很正確。一些SQL數據庫也採用了NoSQL數據庫的特性,反之亦然。在選擇數據庫方面的界限變得愈來愈模糊了,而且一些新的混合型數據庫將會在不久的未來提供更多的選擇。
觀點四:語言或框架決定使用何種數據庫
咱們已經習慣於使用一些現有的框架進行開發,例如:
因爲不少實際的,歷史的和商業化的緣由致使了這些框架的發展,可是它們並非一種規則約束。你能夠在你的PHP和.NET的項目中使用MongoDB。也能夠在Node.js中使用MySQL或者SQL Service。或許在你使用上訴開發模式下不能找到很好的教程和資源,可是咱們開發應該是需求決定使用數據庫的類型,而不是數據庫語言來決定的。
(換句話說,不要自討苦吃!選擇一種小衆的技術組合或者是將SQL和NoSQL進行組合開發是有可能的,可是那樣你會發現尋找有經驗的開發者和相關的技術支持是很是困難的)
下面咱們來看一下它們之間的主要的差異......
SQL數據庫提供關係型的表來存儲數據。例如,若是你在維護一個在線的書店,書籍信息應該存放到book
的表中:
ISBN | title | author | format | price |
---|---|---|---|---|
9780992461225 | JavaScript: Novice to Ninja | Darren Jones | ebook | 29.00 |
9780994182654 | Jump Start Git | Shaumik Daityari | ebook | 29.00 |
每一行是一本不一樣書籍的一個記錄。這樣的設計有些死板,你不能使用同一張表來存儲不一樣結構的信息或者在規定插入數字的位置插入字符串。
NoSQL數據庫採用類JOSN的鍵值對來存儲文檔,例如:
{ ISBN: 9780992461225, title: "JavaScript: Novice to Ninja", author: "Darren Jones", format: "ebook", price: 29.00 }
同一類型的文檔存儲爲一個集合(collection),相似於關係型數據庫中的表結構。然而,你能夠在任意的文檔中存儲任意的數據,NoSQL數據庫不會去進行比較。例如:
{ ISBN: 9780992461225, title: "JavaScript: Novice to Ninja", author: "Darren Jones", year: 2014, format: "ebook", price: 29.00, description: "Learn JavaScript from scratch!", rating: "5/5", review: [ { name: "A Reader", text: "The best JavaScript book I've ever read." }, { name: "JS Expert", text: "Recommended to novice and expert developers alike." } ] }
SQL中的表結構具備嚴格的數據模式約束,所以存儲數據很難出錯。NoSQL存儲數據更加靈活自由,可是也會致使數據不一致性問題的發生。
在關係型數據庫中,除非你事先定義了表和字段的模式不然你沒法向其中添加數據。模式中包含了許多的信息:
在進行數據的邏輯操做以前咱們必需要定義數據模式。數據模式能夠在後期進行更改,可是對於模式的大改將會是很是複雜的。
在NoSQL的數據庫中,數據在任什麼時候候均可以進行添加。不須要事先去定義文檔和集合。例如在MongoDB中以下的操做將會在book
集合中從新建立一個文檔若是以前沒有建立。
db.book.insert( ISBN: 9780994182654, title: "Jump Start Git", author: "Shaumik Daityari", format: "ebook", price: 29.00 );
(MongoDB會在集合中爲每個文檔添加一個獨一無二的_id。若是你仍然想要定義索引,你也能夠本身在以後定義)
一個NoSQL數據庫更適合於那些不可以肯定數據需求的的工程項目。也就是說,不要爲本身的懶惰而製造麻煩:不在項目開始的時候設計一個好的數據存儲模型在未來會帶來必定的麻煩。
假設咱們想要在書店的數據庫中添加一項出版社信息。一個出版社會出版不少書,所以在數據庫中咱們建立了一個表publisher
:
id | name | country | |
---|---|---|---|
SP001 | SitePoint | Australia | feedback@sitepoint.com |
咱們要在book
表中添加一個publisher_id
的字段,用於引用出版社信息中的id:
ISBN | title | author | format | price | publisher_id |
---|---|---|---|---|---|
9780992461225 | JavaScript: Novice to Ninja | Darren Jones | ebook | 29.00 | SP001 |
9780994182654 | Jump Start Git | Shaumik Daityari | ebook | 29.00 | SP001 |
這樣的設計可以最小化數據的冗餘,咱們不須要爲每一本書重複的添加出版社的全部信息—只須要去引用就能夠了。這項技術叫作數據庫的規範化,具備實際的意義。咱們能夠更改出版社信息而不用修改book
中的數據。
在NoSQL中咱們也可使用規範化技術。在book
集合中的文檔:
{ ISBN: 9780992461225, title: "JavaScript: Novice to Ninja", author: "Darren Jones", format: "ebook", price: 29.00, publisher_id: "SP001" }
引用publisher
集合中的一個文檔
{ id: "SP001" name: "SitePoint", country: "Australia", email: "feedback@sitepoint.com" }
然而,在實際中咱們並不會這樣作。咱們會更傾向於選擇非規範化咱們的文檔爲每一本書中都重複出版社的信息
{ ISBN: 9780992461225, title: "JavaScript: Novice to Ninja", author: "Darren Jones", format: "ebook", price: 29.00, publisher: { name: "SitePoint", country: "Australia", email: "feedback@sitepoint.com" } }
這樣會使查詢更快,可是在更新出版社信息的記錄變多時效率將會顯著地降低。
SQL語言爲查詢提供了強大的JOIN操做。咱們可使用單個SQL語句在多個表中獲取相關數據。例如:
SELECT book.title, book.author, publisher.name FROM book LEFT JOIN book.publisher_id ON publisher.id;
這條SQL語句會返回全部書的書名,做者和相關的出版社的名稱。
在NoSQL中沒有與JOIN相同的操做,對於具備SQL語言經驗的人來講是很是使人震驚的。若是咱們使用是上面的規範化的集合,咱們須要取出book
集合中全部的文檔,檢索全部的publisher
的文檔,並在程序中進行手動鏈接。這也是非規範化存在的緣由之一。
大多數的數據庫容許經過定義外鍵來進行數據庫的完整性約束。咱們的數據庫可以保證:
publisher_id
都會對應於publisher
中的一個實體,publisher_id
與publisher
中的id對應,那麼該出版社就不能被刪除。數據模式確保了這些規則被數據庫遵照。開發者或者用戶不能添加、修改和移除一條記錄,若是這些操做致使數據產生無效的數據或者單條無用記錄。
在NoSQL數據庫中沒有數據完整性的約束選項。你能夠存儲任何你想要存儲的數據。理想狀況下,單個文檔將是項目的全部信息的惟一來源。
在SQL數據庫中,兩條或者多條更新操做能夠結合成一個事務(或者所有執行成功不然失敗)執行。例如,假設咱們的book數據庫中包含了order
和stock
表。當一本書被訂購以後,咱們要在order
中添加一條記錄並減小stock
中的庫存數目。若是咱們將兩條更新操做分別執行,一條成功另外一個失敗---這將會致使數據庫的不一致性。將兩條更新操做綁定爲一個事務確保了它們要麼所有成功要麼所有失敗。
在NoSQL數據庫中,對於一個文檔的更新操做是原子性的。換句話說,若是你要更新一個文檔中的三個值,要麼三個值都更新成功要麼它們保持不變。然而,對於操做多個文檔時沒有雨事務相對應的操做。在MongoDB中有一個操做是transaction-like options,可是,須要咱們手動的加入到代碼中。
增刪改查是數據庫的基本操做。本質上:
比較:
SQL | NoSQL |
---|---|
insert a new book record | |
INSERT INTO book ( ISBN, title, author)VALUES ( '9780992461256', 'Full Stack JavaScript', 'Colin Ihrig & Adam Bretz'); |
db.book.insert({ ISBN: "9780992461256", title: "Full Stack JavaScript", author: "Colin Ihrig & Adam Bretz"}); |
update a book record | |
UPDATE bookSET price = 19.99WHERE ISBN = '9780992461256' |
db.book.update( { ISBN: '9780992461256' }, { $set: { price: 19.99 } }); |
return all book titles over $10 | |
SELECT title FROM bookWHERE price > 10; |
db.book.find( { price: { >: 10 } }, { _id: 0, title: 1 }); The second JSON object is known as a projection: it sets which fields are returned (_id is returned by default so it needs to be unset). |
count the number of SitePoint books | |
SELECT COUNT(1) FROM bookWHERE publisher_id = 'SP001'; |
db.book.count({ "publisher.name": "SitePoint"}); This presumes denormalized documents are used. |
return the number of book format types | |
SELECT format, COUNT(1) AS totalFROM bookGROUP BY format; |
db.book.aggregate([ { $group: { _id: "$format", total: { $sum: 1 } } }]); This is known as aggregation: a new set of documents is computed from an original set. |
delete all SitePoint books | |
DELETE FROM bookWHERE publisher_id = 'SP001'; Alternatively, it’s possible to delete the publisher record and have this cascade to associated book records if foreign keys are specified appropriately. |
db.book.remove({ "publisher.name": "SitePoint"}); |
或許最具備爭議性的比較是:一般狀況下,NoSQL比SQL語言更快。這並無什麼好震驚的,NoSQL中更加簡單的非規範化存儲容許咱們在一次查詢中獲得特定項的全部信息。不須要使用SQL中複雜的JOIN操做。
也就是說,你的項目的設計和數據的需求會有很大的影響。一個好的SQL數據庫的設計的表現必定會比一個設計很差的NoSQL數據庫性能好不少,反之亦然。
隨着數據量的增加,咱們或許會發現有必要將負載分配到到不一樣的服務器上。對於基於SQL語言的開發的系統是很是困難的。如何分配相關的數據?集羣是一種最簡單可能的解決方案,多個服務器訪問同一個中央存儲器—及時是這樣也會有許多的問題。
NoSQL的簡單的數據模型可以簡化其過程,許多NoSQL數據庫在一開始就構建瞭解決大規模數據的功能。這僅僅是一個歸納,若是你遇到了這樣的問題應該去尋求專家的幫助。
最後,咱們考慮一下安全性和系統性的問題。流行的NoSQL數據庫已經存在好幾年了,它們展示的問題可能會比成熟的關係型數據庫多。許多問題都已經被發現了,可是全部的問題都指向了同一個問題:瞭解程度。
開發人員和系統管理員對於管理新型數據庫有不多的經驗,所以會產生許多問題。選擇NoSQL是由於感受它比較新穎,或者你想要避免數據模式的設計,都會在未來帶來一些問題。
SQL和NoSQL數據庫只是用不一樣的方式來完成相同的事情。咱們可能會先選擇其中之一而後更換到另外一個上,可是在選擇以前制定一個計劃將會節約許多的時間和金錢。
適合使用SQL開發的項目:
適合使用NoSQL開發的項目:
在咱們的例子中,一個關係型數據庫是一種更好的選擇— 尤爲是當咱們須要引入強大的事務支持的電子商務設備。在接下來的一篇文章中,咱們將討論更多的項目場景,並肯定使用一個SQL或NoSQL數據庫是不是最好的解決方案。