前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mongodb海量数据CRUD优化

mongodb海量数据CRUD优化

作者头像
JadePeng
发布2019-05-30 19:49:40
1.6K0
发布2019-05-30 19:49:40
举报
文章被收录于专栏:JadePeng的技术博客

1. 批量保存优化

避免一条一条查询,采用bulkWrite, 基于ReplaceOneModel,启用upsert:

代码语言:javascript
复制
 public void batchSave(List<?> spoTriples, KgInstance kgInstance) {
        MongoConverter converter = mongoTemplate.getConverter();
        List<ReplaceOneModel<Document>> bulkOperationList = spoTriples.stream()
                .map(thing -> {
                    org.bson.Document dbDoc = new org.bson.Document();
                    converter.write(thing, dbDoc);
                    ReplaceOneModel<org.bson.Document> replaceOneModel = new ReplaceOneModel(
                            Filters.eq(UNDERSCORE_ID, dbDoc.get(UNDERSCORE_ID)), 
                            dbDoc,
                            new UpdateOptions().upsert(true));
                    return replaceOneModel;
                })
                .collect(Collectors.toList());
        mongoTemplate.getCollection(getCollection(kgInstance)).bulkWrite(bulkOperationList);
    }

2. 分页优化

经常用于查询的字段,需要确保建立了索引。

对于包含多个键的查询,可以创建符合索引。

2.1 避免不必要的count

查询时,走索引,速度并不慢,但是如果返回分页Page<?>,需要查询totalcount,当单表数据过大时,count会比较耗时,但是设想意向,你真的需要准确的数字吗?

在google、百度等搜索引擎搜索关键词时,只会给你有限的几个结果,因此,我们也不必给出准确的数字,设定一个阈值,比如1万,当我们发现总量大于1万时,返回1万,前端显示大于1万条即可。

原理也很鉴定啊,我们skip掉MAX_PAGE_COUNT,看是否还有数据,如果有就说明总量大于MAX_PAGE_COUNT,返回MAX_PAGE_COUNT即可,否则,计算真正的count。

代码语言:javascript
复制
int MAX_PAGE_COUNT = 10000;


/**
     * 当总数大于阈值时,不再计算总数
     *
     * @param mongoTemplate
     * @param query
     * @param collectionName
     * @return
     */
    private long count(MongoTemplate mongoTemplate, Query query, String collectionName) {
        query = query.with(PageRequest.of(MAX_PAGE_COUNT, 1));
        if (mongoTemplate.find(query, Thing.class, collectionName).size() > 0) {
            return MAX_PAGE_COUNT;
        }
        return mongoTemplate.count(query, collectionName);
    }

前端显示:

大于10000
大于10000

2.2 避免过多的skip

分页不过避免需要先跳过一些数据,这个过程是需要消耗时间的,可以通过一个小技巧避免跳过。

比如,显示列表时,排序为按最后修改时间倒序,每页显示100条,现在要显示第100页。 按照正常的做法,需要跳过99*100条数据,非常大的代价。换一个角度思考,因为数据是有序的,因此第100页的数据的最后修改时间是小于第99页最小的修改时间,查询时加上这个条件,就可以直接取符合条件的前100条即可。

3. 全量导出优化

3.1 去掉不需要的字段

查询时,指定真正有用的字段,这样可以有效减少数据传输量,加快查询效率。 例如:

代码语言:javascript
复制
        Query query = new Query();
        query.fields().include("_id").include("name").include("hot").include("alias");

3.2 避免使用findAll或者分页查询,改用stream

全量导出有两个误区,一是直接findAll,当数据量过大时,很容易导致服务器OutofMermory,就算没有OOM,也会对服务器造成极大的负载,影响兄弟服务。另外,FindAll一次性加载数据到内存,整个速度也会比较慢,需要等待所有数据进入内存后才能开始处理。

另外一个误区是,分页查询,依次处理。分页查询可以有效减少服务器负担,不失为一种可行的方法。但是就和上面分页说的那样,分页到后面的时候,需要skip掉前面的数据,存在无用功。稍微好一点的做法就是按照之前说的,将skip转换为condtion,这种方式效率OK,但不推荐,存在代码冗余。

代码语言:javascript
复制
            Page<Thing> dataList = entityDao.findAllByPage(kgDataStoreService.getKgCollectionByKgInstance(kg), page);
            Map<String, Individual> thingId2Resource = new ConcurrentHashMap<>();

            appendThingsToModel(model, concept2OntClass, hot, alias, dataList, thingId2Resource);

            while (dataList.hasNext()) {
                page = PageRequest.of(page.getPageNumber() + 1, page.getPageSize());
                dataList = entityDao.findAllByPage(kgDataStoreService.getKgCollectionByKgInstance(kg), page);
                appendThingsToModel(model, concept2OntClass, hot, alias, dataList, thingId2Resource);
            }

更推荐的做法是,采用mongoTemplate的steam方法,返回CloseableIterator迭代器,读一条数据处理一条数据,实现高效处理:

代码语言:javascript
复制
@Override
    public <T> CloseableIterator<T> stream(final Query query, final Class<T> entityType, final String collectionName) {
        return doStream(query, entityType, collectionName, entityType);
    }

改用方法后,代码可以更简化高效:

代码语言:javascript
复制
  CloseableIterator<Thing> dataList = kgDataStoreService.getSimpleInfoIterator(kg);

            // 实体导入
            // Page<Thing> dataList = entityDao.findAllByPage(kgDataStoreService.getKgCollectionByKgInstance(kg), page);
            Map<String, Individual> thingId2Resource = new ConcurrentHashMap<>();

            appendThingsToModel(model, concept2OntClass, hot, alias, dataList, thingId2Resource);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-05-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 批量保存优化
  • 2. 分页优化
    • 2.1 避免不必要的count
      • 2.2 避免过多的skip
      • 3. 全量导出优化
        • 3.1 去掉不需要的字段
          • 3.2 避免使用findAll或者分页查询,改用stream
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档