MongoDB 與 MySQL 對(duì)比

MongoDB 與 MySQL 對(duì)比

由于公司系統(tǒng)使用MongoDB嚷缭,雖然之前了解掺出,但并沒有深入學(xué)習(xí)MongoDB甸箱。見此機(jī)會(huì)闽坡,參考《MongoDB 權(quán)威指南》深入學(xué)習(xí)栽惶,結(jié)合對(duì)比MySQL愁溜,加深對(duì)兩種不同數(shù)據(jù)庫的理解疾嗅。特把學(xué)習(xí)過程記錄和大家分享。

一冕象、 表結(jié)構(gòu)對(duì)比

表結(jié)構(gòu)對(duì)比 MongoDB MySQL
collections tables
documents rows
主鍵 _id id 與業(yè)務(wù)無關(guān)的值作為主鍵代承。如果沒有顯式地在表定義時(shí)指定主鍵,InnoDB存儲(chǔ)引擎會(huì)為每一行生成一個(gè)6字節(jié)的ROWID
主鍵生成策略 24位的字符串(time + machine + pid + inc),自己指定 UUID, 自增
面向Documents數(shù)據(jù)庫 T F
面向行數(shù)據(jù)庫 F T
約束 主鍵約束渐扮,外鍵約束

二论悴、 數(shù)據(jù)類型對(duì)比

數(shù)據(jù)類型對(duì)比 MongoDB MySQL
整形 NumberInt("3"),NumberLong("3") TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT
浮點(diǎn) 默認(rèn)使用64位浮點(diǎn)型數(shù)值 FLOAT, DOUBLE, DECIMAL
字符 utf8 字符串 VARCHAR, CHAR
日期/時(shí)間 new Date(), 自新紀(jì)元依賴經(jīng)過的毫秒數(shù),不存儲(chǔ)時(shí)區(qū) DATE, DATETIME, TIMESTAMP
NULL null 不支持(null與null不相等)
布爾類型 true/false 不支持
正則表達(dá)式 支持 { "x" : /foobar/i } 不支持
數(shù)組 支持 { "x" : ["a", "b", "c"]} 不支持
二進(jìn)制數(shù)據(jù) 支持 GridFS BLOB, TEXT
代碼片段 { "x" : function() { /... / } } 不支持

三墓律、 SHELL終端對(duì)比

對(duì)比項(xiàng) MongoDB MySQL
啟動(dòng) mongo mysql -u root -p
查看庫 show dbs show databases
使用庫 use test use test
查看表 show collections show tables

四膀估、 查詢對(duì)比

查詢對(duì)比 MongoDB MySQL
檢索單列 db.users.find({ "age" : 27 }) SELECT * FROM users WHERE age = 27;
檢索多列 db.users.find({ "age" : 27, "username" : "joe" }) SELECT * FROM users WHERE age = 27 and username = 'joe';
指定需要返回的鍵 db.users.find({}, { "username" : 1, "email" : 1 }) SELECT username, email FROM users;
范圍檢索 db.users.find({"age" : { "$gte" : 18, "$lte" : 30 }}) $lt, $lte, $gt, $gte 分別對(duì)應(yīng) <, <=, >, >= SELECT * FROM users WHERE age >= 18 AND age <=30;
不匹配檢索 db.users.find({ "username" : { "$ne" : "joe" } }) SELECT * FROM users WHERE username <> 'joe';
IN 操作符 db.raffle.find({ "ticket_no" : { "$in" : [725, 542, 390] } }) $in非常靈活,可以指定不同類型 的條件和值耻讽。 例如在逐步將用戶的ID號(hào)遷移成用戶名的過程中察纯, 查詢時(shí)需要同時(shí)匹配ID和用戶名 SELECT ticket_no FROM raffles WHERE ticket_no IN (725, 542, 390);
NOT IN 操作符 db.raffle.find({ "ticket_no" : { "$nin" : [725, 542, 390] } }) SELECT * FROM raffles WHERE ticket_no not in (725, 542, 390);
OR 操作符 db.raffle.find({ "$or" : [{ "ticket_no" : 725 }, { "winner" : true }] }) SELECT * FROM raffles WHERE ticket_no = 725 OR winner = 'true';
空值檢查 db.c.find({"y" : null}) null不僅會(huì)匹配某個(gè)鍵的值為null的文檔 ,而且還會(huì)匹配不包含這個(gè)鍵的文檔。 所以饼记,這種匹配還會(huì)返回缺少這個(gè)鍵的所有文檔香伴。 如果 僅想要匹配鍵值為null的文檔, 既要檢查改建的值是否為null, 還要通過 $exists 條件 判定鍵值已經(jīng)存在 db.c.find({ "z" : { "$in" : [null], "$exists" : true }}) SELECT * FROM cs WHERE z is null;
多列排序 db.c.find().sort({ username : 1, age: -1 }) SELECT * FROM cs ORDER BY username ASC, age DESC;
AND操作符 db.users.find({ "$and" : [{ "x" : { "$lt" : 1 }, { "x" : 4 } }] }) 由于查詢優(yōu)化器不會(huì)對(duì) $and進(jìn)行優(yōu)化具则, 所以可以改寫成下面的 db.users.find({ "x" : { "$lt" : 1, "$in" : [4] } }) SELECT * FROM users WHERE x > 1 AND x IN (4);
NOT 操作符 db.users.find({ "id_num" : { "$not" : { "$mod" : [5,1] } } }) SELECT * FROM users WHERE id_num NOT IN (5,1);
LIKE 操作符(正則匹配) db.blogs.find( { "title" : /post?/i } ) MongoDB 使用Perl兼容的正則表達(dá)式(PCRE) 庫來匹配正則表達(dá)式即纲, 任何PCRE支持表達(dá)式的正則表達(dá)式語法都能被MongoDB接受 SELECT * FROM blogs WHERE title LIKE "post%";

五、 函數(shù)對(duì)比

{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2 }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1 }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5 }
{ "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10 }
{ "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10 }
函數(shù)對(duì)比 MongoDB MySQL
COUNT db.foo.count() SELECT COUNT(id) FROM foo;
DISTINCT db.runCommand({ "distinct": "people", "key": "age" }) SELECT DISTINCT(age) FROM people;
MIN db.sales.aggregate( [ { $group: { _id: {}, minQuantity: { $min: "$quantity" } } } ]); 結(jié)果: { "_id" : { }, "minQuantity" : 1 } SELECT MIN(quantity) FROM sales;
MAX db.sales.aggregate( [ { $group: { _id: {}, maxQuantity: { $max: "$quantity" } } } ]); SELECT MAX(quantity) FROM sales;
AVG db.sales.aggregate( [ { $group: { _id: {}, avgQuantity: { $avg: "$quantity" } } } ]); SELECT AVG(quantity) FROM sales;
SUM db.sales.aggregate( [ { $group: { _id: {}, totalPrice: { $sum: "$price" } } } ]); SELECT SUM(price) FROM sales;

六博肋、 CURD 對(duì)比

CURD 對(duì)比 MongoDB MySQL
插入數(shù)據(jù) post = {"title" : "My Blog Post", "content" : "Here`s my blog post"}; db.blog.insert(post) 如果blog 這個(gè)集合不存在低斋,則會(huì)創(chuàng)建 INSERT INTO blogs(title, blog_content) VALUES ('My Blog Post', 'Here`s my blog post.')
批量插入 db.blog.batchInsert([{ "title" : "AAA", "content" : "AAA---" }, { "title" : "BBB", "content" : "JJJJ--" }]) 當(dāng)前版本的MongoDB能接受最大消息長度48MB, 所以在一次批量插入中能插入的文檔是有限制的匪凡。 并且在執(zhí)行批量插入的過程中拔稳,有一個(gè)文檔插入失敗, 那么在這個(gè)文檔之前的所有文檔都會(huì)成功插入到集合中锹雏, 而這個(gè)文檔以及之后的所有文檔全部插入失敗巴比。 INSERT INTO blogs(title, blog_content) VALUES('AAA', 'AAA---'), ('BBB', 'BBB---');
查詢數(shù)據(jù) db.blog.find(); db.blog.findOne(); SELECT * FROM blogs; SELECT * FROM blogs LIMIT 1;
更新舊數(shù)據(jù) post.blog_content = "十一"; db.blog.update({title: "My Blog Post"}, post) UPDATE set blog_content = "十一" WHERE title = "My Blog Post";
更新新增COLUMN post.comments = "very good"; db.blog.update({title : "My Blog Post"}, post) ALTER table blogs ADD COLUMN comments varchar(200); UPDATE blogs set comments = "very good" WHERE title = 'My Blog Post';
刪除數(shù)據(jù) db.blog.remove({ title : "My Blog Post" }) DELETE FROM blogs WHERE title = 'My Blog Post'
校驗(yàn) post.blog_visit = 123; db.blog.update({title : "My Blog Post"}, post); post.blog_visit = "asd.123aaa"; db.blog.update({title : "My Blog Post"}, post) 插入的時(shí)候,檢查大小礁遵。所有的文檔都必須小于16MB轻绞。 這樣做的目的是為了防止不良的模式設(shè)計(jì),并且保持性能一直佣耐。由于MongoDB只進(jìn)行最基本的檢查政勃,所以插入非法的數(shù)據(jù)很容易。 類型校驗(yàn)兼砖,長度校驗(yàn)奸远。 ALTER table blogs ADD COLUMN blog_visit INT(10); UPDATE blogs SET blog_visit = "asdasd" WHERE id = 1; ERROR 1366 (HY000): Incorrect integer value: 'asdasd' for column 'blog_visit' at row 1
刪除表 db.blog.remove({}), db.blog.drop() DELETE from blogs; drop table blogs;

七、有的沒的

MongoDB:

  • GridFS

    可以用來存儲(chǔ)大文件(>16M), 與MySQL BLOB讽挟,TEXT 類似懒叛。

  • MapReduce

    MapReduce
    是一種計(jì)算模型,簡單的說就是將大批量的工作數(shù)據(jù)分解執(zhí)行耽梅,然后再將結(jié)果合并成
    最終結(jié)果薛窥。MongoDB提供的MapReduce
    非常靈活,對(duì)于大規(guī)模數(shù)據(jù)分析也相當(dāng)實(shí)用眼姐。

  • 時(shí)間有限的集合

    MongoDB 2.2 引入一個(gè)新特性--
    TTL集合诅迷,TTL集合支持失效時(shí)間設(shè)置,使用expireAfterSeconds 來實(shí)現(xiàn)
    當(dāng)超過指定時(shí)間后众旗,集合自動(dòng)清除超時(shí)的文檔罢杉,這用來保存一些諸如session會(huì)話信息
    的時(shí)候非常有用,或者存儲(chǔ)數(shù)據(jù)使用贡歧。

    戳這里

  • 無JOIN

    MongoDB 為了更快的讀滩租,以及更方便的分布式拱镐,拋棄了JOIN操作。
    JOIN開銷其實(shí)很大持际。

  • 關(guān)于鎖

    當(dāng)資源被代碼的多個(gè)部分所共享時(shí)沃琅,需要確定這處資源只能在一個(gè)地方被操作。
    就版本的MongoDB(pre
    2.0)擁有一個(gè)全局的寫入鎖蜘欲。這就意味著貫穿整個(gè)服務(wù)器只有一個(gè)地方做寫操作益眉。
    這就可能導(dǎo)致數(shù)據(jù)庫因?yàn)槟硞€(gè)地方鎖定超負(fù)載而停滯。這個(gè)問題在2.0版本中得到
    了顯著的改善姥份,并且在2.2版本中得到了進(jìn)一步的加強(qiáng)郭脂。MongoDB
    2.2使用數(shù)據(jù)庫級(jí)別的鎖再這個(gè)問題上邁進(jìn)了一大步。

    圖中是兩個(gè)不同版本的MongoDB澈歉,寫入性能對(duì)比展鸡。


    戳這里
    戳這里

    MySQL InnoDB使用行級(jí)鎖,有效提高并發(fā)埃难。

  • 無事務(wù)

    不像MySQL
    這些多行數(shù)據(jù)原子操作的傳統(tǒng)數(shù)據(jù)庫莹弊。MongoDB只支持單個(gè)文件的原子修改。
    但這也正是MongoDB可以更快地讀的原因涡尘,沒有事務(wù)這些負(fù)載的處理忍弛。MongoDB
    可以輕松處理TB級(jí)別的數(shù)據(jù)。

  • 磁盤消耗

    MongoDB
    會(huì)消耗太多的磁盤空間了考抄。當(dāng)然细疚,這與它的編碼方式有關(guān),因?yàn)镸ongoDB會(huì)通過預(yù)分配
    大文件空間來避免磁盤碎片問題川梅。它的工作方式是這樣:在創(chuàng)建數(shù)據(jù)庫時(shí)疯兼,系統(tǒng)會(huì)創(chuàng)建
    一個(gè)名為[db_name].0的文件,當(dāng)該文件有一半以上被使用時(shí)贫途,系統(tǒng)會(huì)再次創(chuàng)建一個(gè)名
    為[db_namel].1的文件吧彪,該文件的大小是方才的兩倍。這個(gè)情況會(huì)持續(xù)不斷的發(fā)生潮饱,因此
    256来氧、512、1024香拉、2048大小的文件會(huì)被寫到磁盤上。

MySQL:

  • 強(qiáng)大的引擎

    InnoDB 引擎: MySQL默認(rèn)的事務(wù)性引擎中狂。它被設(shè)計(jì)用來處理大量的短期事務(wù)凫碌,短期
    事務(wù)大部分情況是正常提交的,很少會(huì)被回滾胃榕。InnoDB采用MVCC來支持高并發(fā)盛险。

    MyISAM 引擎: 5.1以及之前的默認(rèn)版本瞄摊。全文索引,壓縮苦掘,空間函數(shù)换帜,但是MyISAM不支持事務(wù)和
    行級(jí)鎖。MyISAM最整張表加鎖鹤啡,而不是針對(duì)行惯驼。讀取時(shí)會(huì)對(duì)需要讀到的所有表加
    共享鎖,寫入時(shí)則對(duì)表加排它鎖递瑰。

    Memory 引擎:比MyISAM表塊一個(gè)數(shù)量級(jí)祟牲,因?yàn)樗械臄?shù)據(jù)都保存在內(nèi)存中,不需要進(jìn)行磁盤I/O抖部。數(shù)據(jù)會(huì)丟失

    Infobright 是最有名的面向列的存儲(chǔ)引擎说贝。但該引擎不支持索引。

  • 事務(wù)

    確保數(shù)據(jù)庫的狀態(tài)從一個(gè)一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€(gè)一致狀態(tài)慎颗。一致狀態(tài)的含義是數(shù)據(jù)庫中

    的數(shù)據(jù)應(yīng)滿足完整性約束乡恕。

  • schema

    有利于數(shù)據(jù)整理,數(shù)據(jù)存儲(chǔ)俯萎,并執(zhí)行正規(guī)化的行為几颜。 保證數(shù)據(jù)的完整性,一致性讯屈。

    描述了數(shù)據(jù)存儲(chǔ)的模板蛋哭,比如創(chuàng)建table。

    校驗(yàn)數(shù)據(jù)的格式涮母,比如整形的column 就不能存放字符串?dāng)?shù)據(jù)谆趾。

八、 MySQL 與 MongoDB 寫入對(duì)比

options MySQL MongoDB
Time taken for tests: 548.281 seconds 661.318 seconds
Total transferred: 44000000 bytes 44200000 bytes
Requests per second: 182.39 [#/sec] 151.21 [#/sec]
Time per request: 274.141 [ms] 330.659 [ms]
Time per request(across all concurrent requests): 5.483 [ms] 6.613 [ms]
Transfer rate: 78.37 [Kbytes/sec] received 65.27 [Kbytes/sec] received

在本測(cè)試?yán)又信驯荆琈ySQL 寫入情況好于 MongoDB

壓測(cè)參考命令:

   ab -c 50 -n 100000 http://127.0.0.1:6666/deals/mysql_write
   ab -c 50 -n 100000 http://127.0.0.1:6666/deals/mongodb_write

九沪蓬、 MySQL 與 MongoDB 讀取對(duì)比

options MySQL MongoDB
Time taken for tests: 1181.881 seconds 606.406 seconds
Failed requests: 2239 0
Non-2xx responses: 2239 0
Total transferred: 359397490 bytes 44100000 bytes
Requests per second: 84.61 [#/sec] 164.91 [#/sec]
Time per request: 590.941 [ms] 303.203 [ms]
Time per request(across all concurrent requests): 11.819 [ms] 6.064 [ms]
Transfer rate: 296.96 [Kbytes/sec] received 71.02 [Kbytes/sec] received

在本測(cè)試?yán)又校?MySQL 讀取性能沒有 MongoDB好

壓測(cè)參考命令:

   ab -c 50 -n 100000 http://127.0.0.1:6666/deals/mysql_read
   ab -c 50 -n 100000 http://127.0.0.1:6666/deals/mongodb_read

參考

MySQL 外鍵使用

MongoDB

MongoDB核心貢獻(xiàn)者:不是MongoDB不行,而是你不懂来候!

MongoDB和MySQL性能測(cè)試及其結(jié)果分析

Apache Benchmark 的使用的個(gè)人淺薄經(jīng)驗(yàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跷叉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子营搅,更是在濱河造成了極大的恐慌云挟,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件转质,死亡現(xiàn)場(chǎng)離奇詭異园欣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)休蟹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門沸枯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來日矫,“玉大人,你說我怎么就攤上這事绑榴∧慕危” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵翔怎,是天一觀的道長窃诉。 經(jīng)常有香客問我,道長姓惑,這世上最難降的妖魔是什么褐奴? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮于毙,結(jié)果婚禮上敦冬,老公的妹妹穿的比我還像新娘。我一直安慰自己唯沮,他們只是感情好脖旱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著介蛉,像睡著了一般萌庆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上币旧,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天践险,我揣著相機(jī)與錄音,去河邊找鬼吹菱。 笑死巍虫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鳍刷。 我是一名探鬼主播占遥,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼输瓜!你這毒婦竟也來了瓦胎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤尤揣,失蹤者是張志新(化名)和其女友劉穎搔啊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芹缔,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坯癣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了最欠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片示罗。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖芝硬,靈堂內(nèi)的尸體忽然破棺而出蚜点,到底是詐尸還是另有隱情,我是刑警寧澤拌阴,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布绍绘,位于F島的核電站,受9級(jí)特大地震影響迟赃,放射性物質(zhì)發(fā)生泄漏陪拘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一纤壁、第九天 我趴在偏房一處隱蔽的房頂上張望左刽。 院中可真熱鬧,春花似錦酌媒、人聲如沸欠痴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喇辽。三九已至,卻和暖如春雨席,著一層夾襖步出監(jiān)牢的瞬間菩咨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工陡厘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抽米,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓雏亚,卻偏偏與公主長得像缨硝,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子罢低,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容