CouchDB用起來可能不是很舒服

jopen 9年前發布 | 10K 次閱讀 CouchDB NoSQL數據庫

最近我花了一個星期研究NoSQL,我有一個400萬記錄的MySQL速度比較慢,準備遷移到NoSQL上,因為主要是一些JSON格式的文檔,本來序列化存在MySQL中的,因為看上了Erlang這個號稱非常牛X的平臺,挑中了CouchDB,但導入40萬有效測試數據,在本地運行的時候,發現速度特別慢(本地機器為2011年的iMac,配備16G內存,根本不弱的),而且查詢功能很弱,可能還沒到成熟的時候。

CouchDB特點:

面向文檔數據庫,不需要范式,直接存儲JSON就可以,CouchDB默認會生成 _id,_rev 兩個鍵,_id是一條記錄(文檔)的唯一標識,如果不提供_id,_id會自動生成,也可以手動指定_id,比如用手機號做主鍵:

{'_id' : '+86186*****', name: '' }

 _rev是其版本號,每更新一次 _rev就會自動發生變化,格式為

5-6a8617596d2adfea245662df0df611ao

,標識第5個版本,后面是HASH簽名,可以通過_rev尋找到所有的歷史版本,所以用來做需要存儲版本的文檔系統應該非常不錯,比如多人協作修改一篇文檔等應用。

CouchDB提供RESTful接口訪問,只需要執行http請求就能完成增刪改功能,好處是,只需要命令行cURL就可以開始工作了,不需要特別的驅動,比如:獲取一篇文檔:

curl -X GET http://127.0.0.1:5984/dbname/_id

就可以了,而壞處是,http協議的效率并不高,尤其是如果執行一個頁面需要多個請求的時候,用MySQL可以公用一個打開的鏈接就可以不斷執行查詢,而用http?得想想怎么樣讓http復用一個socket鏈接,所以越是入門簡單,后面的麻煩就越多!

CouchDB的查詢功能非常弱,CouchDB如何執行查詢呢?不同于MySQL,扔一條SQL過去就得了。得為每一次查詢創建一個view,view的格式:

{"map": "function(doc){ emit( key,  value); } "}

,這里面的function必須是一個字符串,而不能是javascript的合法語句,所以你寫一個稍微復雜一點的語句,得先保證在node/console里調試好,然后把他轉換成字符串,然后再構造出合法的json字符串post過去,這個過程非常的痛苦。而且這個view在第一次查詢的時候速度會慢的嚇死人,40萬條數據,執行一次需要的時間大概要5分鐘左右,400萬條,我就不敢測試了,但stackoverflow上有網友說他跑了4個小時還沒跑出結果來,因為這個map可不存在什么優化的地方,map就是一條條在運行,所以不管做什么查詢,都要遍歷所有doc,能不慢么!

另外,view其實也是像其他普通的記錄一樣實實在在存在數據庫里的,可以通過 _utils 看到,view中是不可以傳遞變量的(臨時view可以),比如在一個庫里存在 member 數據有 name, email, city等,需要查詢 city為"shenzhen"的member,那么怎么辦?第一用臨時view: temp_view,構造動態的查詢map語句:

curl http://127.0.0.1:5984/dbname/_temp_view?include_docs=true -H 'Content-Type: application/json'  -d \
'{"map": "function(doc){  if(doc.city.match(/shenzhen/) ) emit(doc._id, 1 );  }" }'

最好把這個 _temp_view 存儲成永久的view,否則每次查詢一個新的city都會很慢的,一旦執行過一次查詢,后面的訪問就會比較快,但是前提是:得執行過一次查詢!

但如果存儲為永久view,就需要寫死 shenzhen這個字符串在view中,這種傳遞變量的辦法顯然是不可取的,非常呆板,難道我要查詢一個 city為 shenzhen的就得新建一個 view,那么全國那么多city,是不是每一個都要新建一個city?view這種方式查詢真的很愚蠢!

除了temp_view外,到底有沒有辦法可以動態傳遞參數的?可以啊 startkey 和 endkey啊,但這兩個參數光從名字就可以看出設計的是多么愚蠢了。

好這樣查詢,先創建一個view,保存為 member/city_query

'{"map": "function(doc){  emit([doc.city, doc._id],   1 );  }" }'

接下來就可以痛快查詢啦:

curl \
http://127.0.0.1:5984/dbname/_design/member/_view/city_query?startkey=[shenzhen]&endkey=[shenzhen]
-H 'Content-Type: application/json'

這個語句是不能運行的,需要手動將中括號 [] 轉義。看就是這么無聊。

執行的過程是這樣的:startkey傳遞了一個數組參數,只有一個值 shenzhen,在view的map里,emit不再是一個普通的key,而是一個數組,startkey第一個值對應于emit的第一個參數中的第一位即 doc.city, 結果就會檢索 city的值>=shenzhen,再指定一個endkey就OK了啊!可以想想,這個map還是會遍歷所有的記錄!


這樣的設計的很低級,而且非常不好用,如果我要查詢 正則匹配怎么辦?老老實實創建一個新的view? 結果就是如果你的查詢比較多樣化,里面的view可能比數據還多!

最終我的結論是,不要在大數據上嘗試CouchDB,不要在需要頻繁查詢的地方使用CouchDB,不要在需要大量匯總、分析數據的地方使用CouchDB,他只適合最多幾千條數據的小博客、小文檔系統,并且不需要各種花式查詢的地方,他的性能不如想想中來的那么暢快,而且CouchDB內部存儲就是實實在在的文件而已,沒有什么優化,提升查詢速度也不是CouchDB最近的目標,他們更多關注在功能上而非性能。并且CouchDB的開發初衷是Apache基金會的一廂情愿,并非工程需求,所以如果選擇NoSQL,要盡可能找在工程需求中開發出來的數據庫。

來自:http://my.oschina.net/jsk/blog/491096

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!