關係數據庫經過幾十年的發展,已經非常成熟,但同時也存在不足:
- 存儲的是行記錄,無法存儲數據結構
例如微博的關注關係,“我關注的人”是一個用戶ID列表,使用關係數據庫只能將列表拆成多行,然後查詢組裝,無法直接存儲一個列表。
- schema 擴展不方便
表結構是強約束的,業務變更時擴充很麻煩。
- 在大數據場景下 I/O 較高
如果對大數據量的表進行統計運算,I/O會很高,因為即使只針對某列進行運算,也需要將整行數據讀入內存。
- 搜索功能較弱
全文搜索只能使用 Like 進行整表掃描,性能非常低。
針對這些不足,產生了不同的 NoSQL 解決方案,在某些場景下比關係數據庫更有優勢,但同時也犧牲了某些特性,所以不能片面的迷信某種方案,應將其作為 SQL 的有利補充。
NoSQL != No SQL,而是:
NoSQL = Not Only SQL
典型的 NoSQL 方案分為4類:
- K-V 存儲
- 解決存儲數據結構的問題,以 Redis 為代表。
- 文檔數據庫
- 解決 schema 強約束的問題,以 MongoDB 為代表。
- 列式數據庫
- 解決大數據下 I/O 問題,以 HBASE 為代表。
- 全文搜索引擎
- 解決全文搜索性能問題,以 ElasticSearch 為代表。
1. K-V 存儲
Redis 是典型,其 value 是具體的數據結構,包括 string, hash, list, set, sorted set, bitmap, hyperloglog,常被稱為數據結構服務器。
以 list 為例:
LPOP key 是移除並返回隊列左邊的第一個元素。
如果用關係數據庫就比較麻煩了,需要操作:
- 為每條數據添加 位置編號,否則沒法判斷哪條數據是第一條。不能用ID作為位置編號,因為會往列表頭部插入數據。
- 查詢出第一條數據。
- 刪除第一條數據。
- 更新從第二條開始的所有數據的位置編號。
Redis 的缺點主要體現在不支持完成的ACID事務,只能保證隔離性和一致性,無法保證原子性和持久性。
2. 文檔數據庫
最大的特點是 no-schema,無需在使用前定義字段,讀取一個不存在的字段也不會導致語法錯誤。
特點:
- 新增字段簡單。
- 兼容歷史數據,即使沒有新增字段,不會出錯。
- 很容易存儲複雜數據,使用 JSON 描述數據,比關係數據庫方便得多。
以電商為例,不同商品的屬性差異很大,如冰箱和電腦,這種差異性在關係數據庫中會有很大的麻煩,而使用文檔數據庫則非常方便。
文檔數據庫的主要缺點:
- 不支持事務
- 無法實現 join 操作
3. 列式數據庫
關係數據庫是按行來存儲的,列式數據庫是按照列來存儲數據。
按行存儲的優勢:
- 同時讀取多個列時效率高,一次磁盤操作就把一行數據中的各列都讀取到內存了。
- 能夠一次完成對一行中多個列的寫操作,保證了對行數據寫操作的原子性和一致性;如果使用列式存儲,可能出現多次寫操作,因為這些列都不在一起存儲。
在某些場景下,這些優勢就成為劣勢了,例如,計算超重人員的數據,只需要讀取體重這一列進行統計即可,但行式存儲會將整行數據讀取到內存中,很浪費。
而列式存儲中,只需要讀取體重這列的數據即可,I/O 將大大減少。
除了節省I/O,列式存儲還有更高的壓縮比,可以節省存儲空間。普通行式數據庫的壓縮比在 3:1 到 5:1 左右,列式數據庫在 8:1 到 30:1,因為單個列的數據相似度更高。
列式存儲的隨機寫效率遠低於行式存儲,因為行式存儲時同一行多個列都存儲在連續空間中,而列式存儲將不同列存儲在不連續的空間。
一般將列式存儲應用在離線大數據分析統計場景,因為這時主要針對部分列進行操作,而且數據寫入後無須更新。
4. 全文搜索引擎
關係數據庫通過索引進行快速查詢,但在全文搜索的情景下,索引就不夠了,因為:
- 全文搜索的條件可以隨意排列組合,索引很難滿足。
- 全文搜索的模糊匹配方式,索引無法滿足,只能用 like,效率極低。
假設有一個交友網站,信息表如下:
- 美女1:我要找在上海做PHP的哥哥。
需要匹配性別、地點、語言列。
- 美女2:我要找北京愛旅遊的哥哥。
需要匹配性別、地點、愛好列。
實際搜索中,各種排列組合非常多,關係數據庫很難支持。
全文搜索引擎是使用倒排索引技術,建立單詞到文檔的索引,例如上面的表信息建立倒排索引:
所以特別適合根據關鍵詞來查詢文檔內容。
小結
上面介紹了幾種典型的NoSQL方案,及各自的適用場景和特點,您可以根據實際需求進行選擇。
閱讀更多 IT實戰聯盟 的文章