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