17

我是數據庫的新手,我從未與任何RDBMS合作過。但是我得到關係數據庫的基本思想。至少我覺得我做的;-)關係與非關係數據建模 - 有什麼區別

比方說,我有一個用戶數據庫,每個用戶的以下屬性:

  • 用戶
    • ID
    • 拉鍊
    • 城市

關係數據庫我想例如模型,可以在一臺名爲user

  • 用戶
    • ID
    • LOCATION_ID

,並有第二個表稱爲location

  • 位置
    • ID
    • 拉鍊
    • 城市

location_id是對location表中的條目的外鍵(參考)。如果我理解正確,這裏的優勢在於,如果某個城市的郵政編碼發生變化,我只需要更改一個條目。

因此,我們來看看非關係型數據庫,我開始使用Google App Engine。在這裏,我真的會模擬它,就像它在規格中首先寫下來一樣。我有一種user

class User(db.Model): 
    name = db.StringProperty() 
    zip = db.StringProperty() 
    city = db.StringProperty() 

的好處是,我不需要連接兩個「表」,但缺點是,如果郵政編碼改變我要運行一個腳本,通過一切順利用戶輸入並更新郵政編碼,對嗎?

因此,現在Google App Engine中有另一種選擇,即使用ReferenceProperties。我可以有兩種:userlocation

class Location(db.Model): 
    zip = db.StringProperty() 
    city = db.StringProperty() 

class User(db.Model): 
    name = db.StringProperty() 
    location = db.ReferenceProperty(Location) 

如果我沒看錯我現在有完全相同的模式,如上述的關係數據庫。我現在想知道的是,首先,這是錯誤的,我剛剛做了,並且這會破壞非關係數據庫的所有優點。我明白,爲了得到zip和城市的價值,我必須運行第二次查詢。但在另一種情況下,要更改郵政編碼,我必須通過所有現有用戶。

那麼在Google的數據存儲庫這樣的非關係數據庫中,這兩種建模可能性有什麼影響。對於它們兩者來說,典型的用例是什麼,這意味着什麼時候我應該使用一個,什麼時候使用另一個。

另外作爲一個額外的問題,如果在一個非關係數據庫中,我可以建模完全相同的模型在關係數據庫中,爲什麼我應該使用關係數據庫呢?

很抱歉,如果其中一些問題聽起來很樸素,但我相信他們會幫助一些對數據庫系統不熟悉的人加以幫助。

回答

4

您對關係數據庫概念的理解是有缺陷的。關係數據庫在包含一組相同類型的元組的關係中組織它們的數據。換句話說,數據存儲在表中,每行包含相同數量的相同類型的字段,並且順序相同。

您提供的使用外鍵的示例演示database normalization。這是一個可以應用於關係數據庫以及其他類型數據庫的概念。

對不起,我無法回答你有關Google存儲系統的問題,但希望這可以讓你明白你的理解。

16

根據我的經驗,最大的區別是非關係型數據存儲迫使您根據您的查詢方式進行建模,因爲缺少連接以及您將如何編寫。這當然會導致非常規化的模型。過了一段時間,我開始定義所有的查詢第一個,以避免以後重新考慮模型。

由於關係數據庫的靈活性,您可以分別考慮每個數據族,在它們之間建立關係並在最後查詢您希望如何(在許多情況下濫用聯接)。

+3

+1很好的答案。現在我想到了,我沒有意識到這一點。 – 2011-05-14 15:25:36

+3

這正是我正要寫的。 :) – 2011-05-15 01:33:16

10

想象一下,GAE有兩種數據存儲模式:RDMS模式和非RDMS模式。 如果我將您的ReferenceProperty示例的目標是「列出所有用戶及其所有郵政編碼」並編寫一些代碼來打印所有這些郵件。

有關[小說]關係數據庫管理系統模式的數據存儲,可能看起來像:

for user in User.all().join("location"): 
    print("name: %s zip: %s" % (user.name, user.location.zip)) 

我們的關係數據庫管理系統已經處理了絕佳周邊後面的數據去規範化,做全退給了很好的工作我們在一個查詢中需要的數據。這個查詢確實有一點點開銷,因爲它必須將我們的兩個表拼接在一起。

對於非關係數據庫管理系統的數據存儲我們的代碼可能看起來像:

for user in User.all(): 
    location = Location.get(user.location)† 
    print("name: %s zip: %s" % (user.name, location.zip)) 

這裏的數據存儲不能幫助我們加入我們的數據,我們必須爲每個額外的查詢,每user實體獲取在我們可以打印之前使用location

這實質上就是爲什麼你想要避免在非RDMS系統上過度標準化的數據。

現在,在他們使用RDMS或不使用RDMS的情況下,每個人都在邏輯上規範化了他們的數據,訣竅是在便利性和性能之間找到平衡點。

†這是無效的appengine代碼,我只是說明user.location會觸發數據庫查詢。也沒有人應該像我上面的極端例子那樣編寫代碼,你可以通過提前批量提取位置來解決相關實體的不斷提取問題。

如果在非關係數據庫中,我可以模擬正是我可以在關係數據庫模型一樣,我爲什麼要使用一個關係型數據庫呢?

關係數據庫擅長存儲成百上千萬行復雜的相互關聯的數據模型,並允許您執行難以置信的複雜查詢以改進和訪問數據。

非RDB擅長存儲數十億行簡單數據並允許您使用更簡單的查詢獲取數據。

這個選擇應該與你的用例真正相符。非關聯模型的簡單結構和設計約束是AppEngine能夠承諾根據需求擴展您的應用程序的主要方式之一。