mongdob的介紹
官話:
MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era.
MongoDB是爲現代應用程序開發人員和雲時代構建的基於文檔的通用分佈式數據庫。
這裏我們看到這麼幾個關鍵字:文檔
和分佈式數據庫
。
天生就是分佈式數據庫,沒錢別用?
MongoDB is a document database, which means it stores data in JSON-like documents. We believe this is the most natural way to think about data, and is much more expressive and powerful than the traditional row/column model.
MongoDB是一個文檔數據庫,這意味着它將數據存儲在類似JSON的文檔中。我們認爲這是最自然的數據處理方式,比傳統的行/列模型更具表現力和功能。
關鍵字:類似JSON
? 那到底是不是JSON
?
類JSON格式的優點
官話:
- The most natural and productive way to work with data.
- Supports arrays and nested objects as values.
- Allows for flexible and dynamic schemas.
- 處理數據的最自然,最有效的方式。
- 支持數組和嵌套對象作爲值。
- 允許靈活和動態的schemas。
{
"_id": "5cf0029caff5056591b0ce7d",
"firstname": "Jane",
"lastname": "Wu",
"address": {
"street": "1 Circle Rd",
"city": "Los Angeles",
"state": "CA",
"zip": "90404"
},
"hobbies": ["surfing", "coding"]
}
> db.users.find({ "address.zip" : "90404" })
{ "_id": "5cf0029caff5056591b0ce7d", "firstname": "Jane", "lastname": "Wu", "address":{}}
{ "_id": "507f1f77bcf86cd799439011", "firstname": "Jon", "lastname": "Davis", "address":{}}
{ "_id": "5349b4ddd2781d08c09890f3", "firstname": "Jim", "lastname": "White", "address":{}}
{ "_id": "5bf142459b72e12b2b1b2cd", "firstname": "Jeff", "lastname": "Taylor", "address":{}}
{ "_id": "5cf003283b23d04a40d5f88a", "firstname": "Jerry", "lastname": "Miller", "address":{}}
{ "_id": "5bf142459b72e12b2b1b2cd", "firstname": "Jai", "lastname": "Williams", "address":{}}
{ "_id": "5cf0036deaa1742dd225ea35", "firstname": "Jess", "lastname": "Johnson", "address":{}}
{ "_id": "54495ad94c934721ede76d90", "firstname": "Jill", "lastname": "Brown", "address":{}}
{ "_id": "566eb3c704c7b31facbb0007", "firstname": "Janet", "lastname": "Jones", "address":{}}
{ "_id": "5a999cc461d36489a27f2563", "firstname": "Jan", "lastname": "Smith", "address":{}}
強大的查詢
Rich and expressive query language that allows you to filter and sort by any field, no matter how nested it may be within a document.
無論您在文檔中有多嵌套,都可以按任何字段進行過濾和排序。
Support for aggregations and other modern use-cases such as geo-based search, graph search, and text search.
支持聚合和其他現代用例,例如基於地理的搜索,圖形搜索和文本搜索。
查詢本身就是JSON,因此很容易組合。
Queries are themselves JSON, and thus easily composable. No more concatenating strings to dynamically generate SQL queries.
不再需要串聯字符串來動態生成SQL查詢。
什麼是文檔(Document)
百度百科:
1:在操作系統中,文檔是文件夾。你們可以看桌面上的
我的文檔
屬性’類型‘
2:在軟件中,新建的文檔,是文件。(一般爲:計算機用語,文件的另一種稱呼,一般將WORD,EXCEL等文字編輯軟件產生的文件叫做文檔)
mysql說:插入一條記錄 它真的插入了一條記錄;(行/列形式的)
mongodb說:不,我插入了一個文檔;(類json格式的)
個人認爲:mongodb中的文檔只是爲了區別SQL行/列那種形式的一種叫法;
官話:
BSON is a binary format in which zero or more ordered key/value pairs are stored as a single entity. We call this entity a document.
鏈接:http://bsonspec.org/spec.html
BSON是一種二進制格式,其中零個或多個有序
鍵/值對
存儲爲單個實體。
我們將此實體稱爲文檔。
類JSON格式 – BSON
Binary JSON
的縮小。
以下格式不是json
嗎?
{
"_id": "5cf0029caff5056591b0ce7d",
"firstname": "Jane",
"lastname": "Wu",
"address": {
"street": "1 Circle Rd",
"city": "Los Angeles",
"state": "CA",
"zip": "90404"
},
"hobbies": ["surfing", "coding"],
"joined": new Date("2016-05-01") //???是json嗎?
}
json
支持的數據類型
① 數組(array)、對象(object)
② 字符串(string)、數字(number)、布爾型(boolean)、NULL值
BSON
支持的數據類型
在JSON
的基礎上還支持
① Date
② BinData 二進制數據
並且其遍歷速度更快:
BSON在文檔中添加了一些“額外”信息,例如字符串和子對象的長度。
這樣可以使遍歷更快
mongodb的安裝
安裝過程不建議參考官網,安裝細節建議參考官網;
https://docs.mongodb.com/manual/tutorial/install-mongodb-enterprise-on-os-x/
配置文件:
https://docs.mongodb.com/manual/reference/configuration-options/#configuration-file
mongodb權限
https://docs.mongodb.com/manual/tutorial/enable-authentication/index.html
1、MongoDB是沒有默認管理員賬號,所以要先添加管理員賬號,再開啓權限認證。
2、切換到admin數據庫,添加的賬號纔是管理員賬號。
3、用戶只能在用戶的認證數據庫登錄,包括管理員賬號。
4、管理員可以管理所有數據庫,但是不能直接管理其他數據庫,要先在admin數據庫認證(登錄)後纔可以
mongodb身份:
① 普通用戶
② admin 管理員 可以查看所有數據庫,但是隻能操作認證數據庫
③ root管理員
啓用配置
security:
authorization: enabled
完整的:
systemLog:
destination: file
path: D:\mongodbdata\log\mongod.log
logAppend: true
storage:
journal:
enabled: true
dbPath: D:\mongodbdata\db
net:
bindIp: 127.0.0.1
port: 27017
security:
authorization: enabled
創建admin用戶
執行命令:
use admin
db.createUser(
{
user: "myUserAdmin",
pwd: "abc123",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
結果:
Successfully added user: {
"user" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
內置的角色:Built-In Roles
創建普通用戶
>use test
> db.createUser(
{
user:"test1",
pwd: "test1",
roles: [{ role: "readWrite", db: "test"}]
}
)
結果:
Successfully added user: {
"user" : "test1",
"roles" : [
{
"role" : "readWrite",
"db" : "test"
}
]
}
切換到其他數據庫
下面的命令可以到robo 3T
中執行,但是必須得一起執行
use myTest
db.mytest.find()
這圖是在window中執行。
mongodb 基本概念
SQL術語 | mongodb 術語 | 說明 |
---|---|---|
database | database | 數據庫 |
table | collection | 數據庫表、集合 |
row | document | 數據記錄行、文檔 |
column | field | 數據字段 |
index | index | 索引 |
table joins | $lookup | 錶鏈接、 只能關聯未分片的表 |
primary key | primary key | 主鍵,MongoDB自動將_id字段設置爲主鍵 |
關於$lookup
:
https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/index.html#lookup-aggregation
mongodb的客戶端
在本機安裝好server端後,需要客戶端進行連接,爲了熟悉命令和操作,建議使用:Robomongo
mongodb的CURD
更新
db.girl.update({firstname:"Jane"}, {$set:{lastname:"Yu"}}, false, false)
第三個參數:true,表示query
不匹配,就新增,否則就更新
第四個參數:true,表示匹配多條,就都更新,否則就更新第一條
https://docs.mongodb.com/manual/reference/method/db.collection.update/
分佈式事務
1、在4.0
版中,MongoDB
支持副本集上的多文檔事務。
2、在版本4.2
中,MongoDB
引入了分佈式事務,它增加了對分片羣集上多文檔事務的支持,併合並了對副本集上多文檔事務的現有支持。
https://docs.mongodb.com/manual/core/transactions/
當一個事務寫入多個分片時,並非所有外部讀取操作都需要等待已提交事務的結果在所有分片上可見。
例如,如果提交了一個事務,並且在分片A上可以看到寫1,
但是在分片B上還看不到寫2,則外部讀的安全級別設置爲“local,那麼可以讀取寫1的結果而看不到寫2。
在大多數情況下,與單文檔寫入相比,多文檔事務產生的性能成本更高,並且多文檔事務的可用性不應代替有效的schema設計。
在許多情況下,非規範化數據模型(嵌入式文檔和數組)對於我們的數據和用例依舊是最佳的。
也就是說,在許多情況下,對數據進行適當的建模將最大程度地減少對多文檔事務的需求。
Java 分佈式事務示例代碼:
/*
For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
String uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/admin?replicaSet=myRepl";
For a sharded cluster, connect to the mongos instances; e.g.
String uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017:27017/admin";
*/
// 拿到客戶端對象
final MongoClient client = MongoClients.create(uri);
/*
Prereq: Create collections. CRUD operations in transactions must be on existing collections.
*/
// 事務不會創建表,所以一定要保證表的存在
client.getDatabase("mydb1").getCollection("foo")
.withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0));
client.getDatabase("mydb2").getCollection("bar")
.withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0));
/* Step 1: Start a client session. */
// 事務的第一步
final ClientSession clientSession = client.startSession();
/* Step 2: Optional. Define options to use for the transaction. */
// 可選項,對事務的讀寫安全級別進行設置
// WriteConcern.MAJORITY 要求已寫入到副本集中的大多數服務器中
// ReadConcern.LOCAL 從實例返回數據,但不能保證數據已被寫入大多數副本集成員(即可以回滾)。
// 事務 從最近的節點(哪怕支持回滾的節點)中返回數據。
// 對於分片羣集上的事務 不保證來自分片上的同一快照。
TransactionOptions txnOptions = TransactionOptions.builder()
.readPreference(ReadPreference.primary())
.readConcern(ReadConcern.LOCAL)
.writeConcern(WriteConcern.MAJORITY)
.build();
/* Step 3: Define the sequence of operations to perform inside the transactions. */
// 定義在事務內的順序操作
TransactionBody txnBody = new TransactionBody<String>() {
public String execute() {
MongoCollection<Document> coll1 = client.getDatabase("mydb1").getCollection("foo");
MongoCollection<Document> coll2 = client.getDatabase("mydb2").getCollection("bar");
/*
Important:: You must pass the session to the operations.
*/
coll1.insertOne(clientSession, new Document("abc", 1));
coll2.insertOne(clientSession, new Document("xyz", 999));
return "Inserted into collections in different databases";
}
};
try {
/*
Step 4: Use .withTransaction() to start a transaction,
execute the callback, and commit (or abort on error).
*/
// 執行事務
clientSession.withTransaction(txnBody, txnOptions);
} catch (RuntimeException e) {
// some error handling
} finally {
clientSession.close();
}
事務的Java代碼示例:
https://docs.mongodb.com/manual/core/transactions/#transactions-api
一、當一個事務寫入多個分片時,並非所有外部讀取操作都需要等待已提交事務的結果在所有分片上可見。
例如,如果提交了一個事務,並且在分片A上可以看到寫1,
但是在分片B上還看不到寫2,則外部讀的安全級別設置爲“local,那麼可以讀取寫1的結果而看不到寫2。
二、在大多數情況下,與單文檔寫入相比,多文檔事務產生的性能成本更高,並且多文檔事務的可用性不應代替有效的schema設計。
在許多情況下,非規範化數據模型(嵌入式文檔和數組)對於我們的數據和用例依舊是最佳的。
也就是說,在許多情況下,對數據進行適當的建模將最大程度地減少對多文檔事務的需求。
存儲引擎
關鍵特性 | MMAPV1 | wiredTiger |
---|---|---|
簡介和默認引擎 | MongoDB從零開始引入,默認引擎到3.0版本。在4.0中已棄用,將來會刪除 | 在3.0版本中引入,從3.2版本開始默認 |
資料壓縮 | 不支持壓縮 | 使用默認的snappy壓縮方法和zlib壓縮方法進行壓縮。因此佔用的空間少於MMAPV1引擎 |
日誌記錄 | MongoDB首先將內存更改寫入磁盤日誌文件.如果在將更改提交到數據文件之前MongoDB關閉/終止,則MongoDB可以使用日誌文件將寫操作應用於數據文件並保持一致的狀態。 | WiredTiger日記保留檢查點之間的所有數據修改。如果MongoDB在檢查點之間退出,它將使用日誌重播自上一個檢查點以來修改的所有數據。 |
鎖與併發 | 直到2.6,MongoDB都使用了readers-writer [1]鎖,該鎖允許對數據庫的併發讀取訪問,但允許對單個寫入操作的獨佔訪問。從3.0開始,使用收集級別鎖定 | 它支持文檔級鎖定。 |
事務 | 對單個文檔的操作是原子的 | 多文檔事務僅適用於4.0版以上的部署 |
CPU 性能 | 添加CPU內核不會顯着提高性能 | 在多核系統上表現更好 |
加密 | 不能加密 | MongoDB企業版和PSMDB 3.6.8中的BETA均可使用靜態加密。 |
內存 | 自動使用計算機上的所有可用內存作爲其緩存 | 使用內部緩存和文件系統緩存 |
更新 | 它在具有大量插入,讀取和就地更新的工作負載方面表現出色。 | 不支持就地更新。它導致整個文檔被重寫 |
可調性 | 調整的機會更少 | 允許通過不同的變量對此引擎進行更多調整。例如:緩存大小,讀/寫票證,檢查點間隔等 |
參考地址:https://www.percona.com/blog/2019/01/03/mongodb-engines-mmapv1-vs-wiredtiger/
WiredTiger and in-place updates
簡單理解:
更新一條記錄時:
①在原有的基礎上更新
②先刪除再新增
①的方式就是 in-place updates。
https://stackoverflow.com/questions/49596247/wiredtiger-and-in-place-updates
常見問題
Sort operation used more than the maximum 33554432 bytes of RAM
因爲 mongo 的 sort 操作是在內存中操作的,必然會佔據內存,同時mongo 內的一個機制限制排序時最大內存爲 32M。
解決辦法就是創建索引。
正常情況下一次查詢使用一個索引,$or
查詢是個例外
db.foo.find({"$or":[{'x':123},{"y":456}]})
創建索引時,一定要後臺執行
db.people.ensureIndex({x:1,y:1},{background:1})
數據量很大的情況下,比如8千萬條數據,不加backgroud:true或1
整個集羣就卡死。
在數據庫建立索引時,默認時 “foreground” 也就是前臺建立索引,但是,當你的數據庫數據量很大時,在建立索引的時會讀取數據文件,大量的文件讀寫會阻止其他的操作。
深層次翻頁問題
公司有個業務,查詢的數據量很多,比如我要查詢2007-2018年的數據,總共有98萬
多條數據。
而我公司的交互,又是支持點擊最後一頁,這樣就會造成數據庫skip數據量很大,導致查詢速度非常慢,大概是10秒到13秒的樣子(已經建好了,最優的索引);
參考地址:
https://stackoverflow.com/questions/49596247/wiredtiger-and-in-place-updates
https://www.percona.com/blog/2019/01/03/mongodb-engines-mmapv1-vs-wiredtiger
https://cloud.tencent.com/developer/article/1168436
https://stackoverflow.com/questions/12438280/what-is-bson-and-exactly-how-is-it-different-from-json