mongodb
文档、非关系型数据数据库,底层索引结构使用的是B-树,只要找到它的子索引就可以进行访问,单次查询在结构上看是优于mysql,因为mysql是B+树
(1)B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和
data 在一起 适合随机读写 ,而区间查找效率很差。
(2)B+树更适合外部存储,也就是磁盘存储,使用B-结构的话,每次磁盘预读中的很多数据是用不上
的数据。因此,它没能利用好磁盘预读的提供的数据。由于节点内无 data 域,每个节点能索引的范围
更大更精确。
(3)注意这个区别相当重要,是基于(1)(2)的,B-树每个节点即保存数据又保存索引 树的深度大
小,所以磁盘IO的次数很少,B+树只有叶子节点保存,较B-树而言深度大磁盘IO多,但是区间访问比较
好。
基本操作语句
//查看所有集合
show collections;
//切换数据库
use xiaoy;
//查看当前操作的数据库
db;
//查询所有
db.mongoHotel.find();
db.mongoHotel.find({name: /全季/});
//排序
db.mongoHotel.find().limit(2).skip(2).sort({"score":-1});
//精准查询
db.mongoHotel.findOne({"city":"福建福州"});
//等于 == eq
db.mongoHotel.find({"city":{$eq: "上海"}});
//大于600
db.mongoHotel.find({ price : { $gt : 600,$lt : 1600}});
db.mongoHotel.find({ $or : [{city: "北京"},{city: "上海"}]});
//插入多个文档
db.mongoHotel.insertMany([{},{}],[{},{}])
//根据id查询
db.mongoHotel.findOne({"_id": 1});
//分页db.users.find().skip(页码-1 * 每页显示的条数).limit(每页显示的条数) 第一页,2条数据
db.mongoHotel.find().skip(1-1 * 2).limit(2);
//前10条数据
db.mongoHotel.find().limit(10);
//跳过前50条数据,即查询的是第61-70条数据,即第6页的数据
db.mongoHotel.find().skip(50).limit(10)
//设置查询结果的投影,即只过滤出自己想要的字段 1表示显示 0表示不显示
db.mongoHotel.find({},{city:1,address:1,_id:0}).explain();
//修改值$set
db.mongoHotel.updateOne({"name":" 福州全季酒店"},{"$set":{ "name":"福州全季酒店"}});
//删除指定字段$unset
db.mongoHotel.updateOne({"name":"福州全季酒店"},{"$unset":{"courses": "Dubbo"}});
//在某个文档新增字段
db.mongoHotel.updateOne({"name":"福州全季酒店"},{"$push":{"courses":"Dubbo"}});
//修改字段名
db.mongoHotel.updateOne({"name":"福州全季酒店"},{"$rename":{"pswd":"password"}});
//统计
db.mongoHotel.find().count();
//对city进行分组,统计各个城市的文档值
db.mongoHotel.aggregate([{"$group":{"_id": "$city","num":{"$sum":1}}}]);
//获取索引
db.mongoHotel.getIndexes();
//所有文档新增字段
db.集合.updateMany({},{$set:{ "新字段": 0}})
//模糊查询
db.集合.find({name:{$regex:"^.*keyword.*$"}})
创建用户
db.createUser({
user:"用户名",
pwd:"密码",
roles:[{
role:"dbOwner", //用户权限
db:"关联的数据库"
}]
}
);
mongo原子操作
mongo无事务操作,不能要求它的完整性,它提供了多个原子操作,如:$set、$unset、$inc(加)、$push(减)等操作都是原子操作。
Update update=new Update();
update.inc("filed");//+1
乐观锁
默认在修改删除操作时+1
//标识乐观锁字段
@Version
private Integer version;
分页操作
默认分页limit().skip()方式
db.mongoHotel.find().limit(2).skip(2).sort({"score":-1});
通过skip和limit方法可以简单的实现分页操作,但是如果数据量特别巨大的时候,会出现性能的问题,不建议使用
Pattern pattern = PatternFactory.getPattern(keyword);
Criteria criteria = Criteria.where("name").regex(pattern); //模糊查询
Query query = Query.query(criteria)
.with(PageRequest.of(pageNum-1, pageSize)) //分页
.with(Sort.by(Sort.Direction.DESC, "createTime")); //排序
mongoTemplate.find(query, 实体.class);
find().limit()方式
先查询10条,然后记录最后一个id记为lastId
Query query = new Query();
query.with(PageRequest.of(page, size, Sort.by(Sort.Direction.DESC,"price")));
query.with(Sort.by(Sort.Direction.DESC,"_id"));
query.addCriteria(Criteria.where("_id").gt(new ObjectId(lastId)).limit(10);
注意
使用ID进行范围查询时要 new ObjectId()
索引优化准则
- 根据ESR原则创建索引
精确(Equal)匹配的字段放最前面,排序(Sort)条件放中间,范围(Range)匹配的字段放最后面,同样适用于ES,ER。 - 每一个查询都必须要有对应的索引
- 尽量使用覆盖索引 Covered Indexes(可以避免读数据文件)
需要查询的条件以及返回值均在索引中 - 使用 projection 来减少返回到客户端的的文档的内容
- 尽可能不要计算总数,特别是数据量大和查询不能命中索引的时候
- 避免使用skip/limit形式的分页,特别是数据量大的时候
替代方案:使用查询条件+唯一排序条件
第一页:db.posts.find({}).sort({id: 1}).limit(20);
第二页:db.posts.find({_id: {![gt: <第一页最后一个_id>}}).sort(<第一页最后一个_id>}}).limit(20);
第三页:db.posts.find({gt: <第二页最后一个_id>}}).sort({_id: 1}).limit(20);
https://www.jianshu.com/p/36599a0011c9
MongoDB索引类型
MongoDB 支持多种类型的索引,包括单字段索引、复合索引、多 key 索引、文本索引等,每种类型的索引有不同的使用场合。
- 单字段索引:_id;
- 复合索引:有多个字段需要建索引的场景,多个索引字段的组合;
- 多 key 索引:一般使用场合为字段是对象场景,会给改对象字段里的每个字段自动加索引;
复合索引字段先后顺序
:
age 字段的取值很有限,即拥有相同 age 字段的文档会有很多;而 name 字段的取值则丰富很多,拥有相同 name 字段的文档很少;显然先按 name 字段查找,再在相同 name 的文档里查找 age 字段更为高效。
创建索引
(通俗理解)其实就是在数据的底层给这个字段加一个位置标识,并排序好,这样下次搜索是根据标识去搜索,就像你给sql语句加了一个where条件类似。
db.table_Name.createIndex( {field: 1|-1 ,filed1:1} ) // 单个字段建立索引 、联合索引
db.table_name.createIndex({filed: "text"},{name: "索引别名"}); // 单个字段建立 全文索引
db.table_name.createIndex({"实体类.属性":1}); //创建子文档索引
1升序排序,-1降序排序
注:创建索引会阻塞,在创建过程中是无法对集合进行读写操作。
查看当前几个所有索引
db.table_name.getIndexes()
explain
db.table_Name.find({query}).explain(cond)
winningPlan.stage: IXSCAN 表示走索引
COLLSCAN: 全表扫描
stage(阶段) | |
---|---|
COLLSCAN | 全表扫描 |
IXSCAN | 索引扫描 |
FETCH | 根据索引去检索文档 |
SHARD_MERGE | 合并分片结果 |
IDHACK | 针对 _id 进行查询 |
强制使用索引
db.table_name.find({query}).hint({"index_name":1});//强制使用索引
字段维护
db.video_info.updateMany({},{"$unset":{
"aliStatus": null //删除aliStatus字段
}});
db.video_info.updateMany({},{"$set":{
"aliStatus": 0 //新增字段加默认值
}});
db.video_info.updateMany({},{"$rename":{"pswd":"password"}}); //改字段名
mongodb:objectId理解
MongoDB的文档固定是使用"_id"作为主键的,ObjectId使用12字节的存储空间,每个字节两位十六进制数字,是一个24位的字符串。
前4为时间戳隐含了文档的创建时间
mongodb分片机制
存储容量需求超出了单机磁盘容量,需要分片来横向扩展
数据分部策略:mongos也会根据各个shard上的chunk的数量来自动做[负载均衡]
范围分片
:根据查找值在范围内的数据进行分片
范围分片缺点 如果shardkey有明显递增(或者递减)趋势,则新插入的文档多会分布到同一个chunk,无法扩展写的能力
hash分片
:Hash分片是根据用户的shard key计算hash值(64bit整型),根据hash值按照『范围分片』的策略将文档分布到不同的chunk
hash分片优点:Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围分片的不足
hash分片缺点:但不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。(需要合理的选择shard key)
分组聚合查询
db.表.aggregate([{
$group: {
"_id": "$分组字段",
"统计别名": {
"$sum": 1
}
}
},
{
$project: {
"分组字段": "$_id",
"统计别名": 1,
"_id": 0 //id不显示
}
}])
List<AggregationOperation> operations=new ArrayList<>();
MatchOperation matchOperation = Aggregation.match(Criteria.where("筛选条件").in(ids));
GroupOperation groupOperation = Aggregation.group("分组字段").count().as("别名");
ProjectionOperation projectionOperation = Aggregation.project("需要的字段","分组字段别名").and("分组字段").previousOperation();
operations.add(groupOperation);
operations.add(projectionOperation);
TypedAggregation<VideoComment> videoCommentTypedAggregation = Aggregation.newAggregation(
VideoComment.class, operations);
.and("分组字段").previousOperation(); //的意思是将_id转换为parentId
标签:mongoHotel,name,mongodb,db,id,索引,find From: https://www.cnblogs.com/daoping/p/16915281.html