MongoDB实验--选择合理的数据库结构设计来优化效率(引用结构与内嵌结构)

非结构化数据库虽然平时用的比较少,但老师还是布置了一些MongoDB的实验供我们了解,其中有一个“选择合理的数据库结构设计来优化效率”的题目:
请给出打印集合 book1 中所有书的所有作者信息的程序代码和运行时间截图、打印集合 book2 中所有书的所有作者信息的程序代码和运行时间截图。 比较两种结构下的查询效率差异, 你觉得什么应用情景下使用内嵌式文档设计比较好?
集合book1的结构是内嵌式的,创建代码如下:

 MongoCollection<Document> book1Collection = md.getCollection("book1");

        long startMili3 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            Document d1 = new Document();
            d1.append("name", "book" + i);
            d1.append("publication year", 2019);

            /*为了创建内嵌式文档,所以需要一个List存储书的作者,每一个作者也是一个文档*/
            /*“authors”数组存储的是完整的作者信息*/
            ArrayList<Document> authors = new ArrayList<Document>();

            Document author1 = new Document();
            author1.append("name", "author123456");
            author1.append("country", "China");
            authors.add(author1);

            Document author2 = new Document();
            author2.append("name", "author654321");
            author2.append("country", "China");
            authors.add(author2);

            d1.append("authors", authors);

            /*插入这本书的信息到book1集合中*/
            book1Collection.insertOne(d1);

        }
        long endMili3 = System.currentTimeMillis();
        System.out.println("生成book1(内嵌式文档)数据,总耗时为:" + (endMili3 - startMili3) + "毫秒");

集合book2是引用式,创建代码并插入数据代码如下:

MongoCollection<Document> book2Collection = md.getCollection("book2");

        long startMili4 = System.currentTimeMillis();

        /*这里要创建的是引用式文档,所以存储的是ObjectId*/
        ArrayList<ObjectId> authorsOID = new ArrayList<ObjectId>();
        Bson b1, b2, b;

        /*首先需要在author集合中查找author123456、author654321的ObjectId*/
        b1 = Filters.eq("name", "author123456");
        b2 = Filters.eq("country", "China");
        b = Filters.and(b1, b2);
        MongoCursor<Document> mongoCursor = authorCollection.find(b).iterator();
        authorsOID.add(new ObjectId(mongoCursor.next().get("_id").toString()));

        b1 = Filters.eq("name", "author654321");
        b2 = Filters.eq("country", "China");
        b = Filters.and(b1, b2);
        mongoCursor = authorCollection.find(b).iterator();
        authorsOID.add(new ObjectId(mongoCursor.next().get("_id").toString()));

        /*生成book2中的图书信息,全部采用引用式设计,“authors”数组只存储作者的ObjectId*/
        for (int i = 0; i < 1000000; i++) {
            Document d2 = new Document();
            d2.append("name", "book" + i);
            d2.append("publication year", 2019);
            d2.append("authors", authorsOID);
            book2Collection.insertOne(d2);
        }
        long endMili4 = System.currentTimeMillis();
        System.out.println("生成book2(引用式文档)数据,总耗时为:" + (endMili4 - startMili4) + "毫秒");

两个集合都关联到的author集合结构如下:

MongoCollection<Document> authorCollection = md.getCollection("author");

        long startMili2 = System.currentTimeMillis();

        /*生成数据,逐个插入*/
        for (int i = 0; i < 1000000; i++) {
            Document author = new Document();
            author.append("name", "author" + i);
            author.append("country", "China");
            authorCollection.insertOne(author);
        }

        long endMili2 = System.currentTimeMillis();
        System.out.println("生成author数据,总耗时为:" + (endMili2 - startMili2) + "毫秒");

为了比较两种结构下的查询效率差异,分别查询并打印出两个集合中所有数据的author信息,代码如下:

 MongoCollection<Document> collection =
                mongoDatabase.getCollection("book1");
        long startMili1 = System.currentTimeMillis();
        MongoCursor<Document> mongoCursor = collection.find().iterator();
        long endMili1 = System.currentTimeMillis();
        while (mongoCursor.hasNext()) {
        Document d = mongoCursor.next();
        //System.out.println(d.get("name").toString() + d.get("publication year").toString());
        ArrayList<Document> authors =
                (ArrayList<Document>) d.get("authors");
        endMili1 = System.currentTimeMillis();
        for (int i = 0; i < authors.size(); i++) {
            Document author = authors.get(i);
            System.out.println(author.get("name").toString() + author.get("country").toString());
        }
        }
        System.out.println("查询book1中所有书的所有作者信息完毕,总耗时为:" + (endMili1 - startMili1) + "毫秒");

为了防止无关因素可能会干扰实验结果,两个查询不要放在一个程序里一起执行。

MongoCollection<Document> collection =
                mongoDatabase.getCollection("book2");

        long startMili1 = System.currentTimeMillis();
        MongoCursor<Document> mongoCursor = collection.find().iterator();
        long endMili1 = System.currentTimeMillis();

        while (mongoCursor.hasNext()) {
            Document d = mongoCursor.next();
            /*拿到引用的作者的 ObjectId,类似于 Mysql 中的外键,但是 mongoDB 中没有表连接关系*/
            ArrayList<ObjectId> authors =
                    (ArrayList<ObjectId>) d.get("authors");
            Bson authorFilter = Filters.in("_id", authors);
            MongoCollection<Document> authorCollection =
                    mongoDatabase.getCollection("author");
            /*利用刚才拿到的作者的 id, 再执行一次对作者信息的查询*/
            MongoCursor<Document> authorCursor =
                    authorCollection.find(authorFilter).iterator();
            endMili1 = System.currentTimeMillis();
            while (authorCursor.hasNext()) {
                Document author = authorCursor.next();
                System.out.println(author.get("name").toString() + author.get("country").toString());/*拿到了想要的属性*/
                //author.get("country");/*拿到了想要的属性*/
            }
        }
        System.out.println("查询book2中所有书的所有作者信息完毕,总耗时为:" + (endMili1 - startMili1) + "毫秒");

最后结果如下:
在这里插入图片描述在这里插入图片描述
查找资料分析差异原因:但是用内嵌结构通过一个集合去访问量一个集合时,优点就是不需要单独执行一条查询数据库语句去获取内嵌的内容。而缺点是无法把被内嵌的文档当做单独的实体去访问,更新不方便。
一般情况下,当数据对象之间有 “contains” (包含) 关系、数据对象之间有一对多等关系时, “多个”或者子文档会经常和父文档一起被查找。通常情况下,内嵌数据会对读操作有比较好的性能提高,也可以使应用程序在一个单个操作就可以完成对数据的读取。同时,内嵌数据也对更新相关数据提供了一个原子性写操作。
引用比内嵌要更加灵活一些。但客户端应用必须使用二次查询来解析文档内包含的引用。换句话说,对同样的操作来说,规范化模式(引用)会导致更多的网络请求发送到数据库服务器端。

发布了7 篇原创文章 · 获赞 7 · 访问量 134

猜你喜欢

转载自blog.csdn.net/gxs_hhxx/article/details/104565822