回答问题

问题说明

我的 REST API 存在很大的性能问题。我在谷歌上找不到任何帮助,所以我在这里问我的问题。

我可以针对慢查询,但这不是由于查询本身,因为当我直接在 Compass 中运行时,它需要 0ms。

我认为问题是由于Java,将查询结果转换为POJO时,但如何改进呢?

工程设置及代码

Pom.xml

        <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com</groupId>
        <artifactId>myproject</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>myproject</name>
        <description>myproject API</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
    
            <dependency>
                <groupId>com.newrelic.agent.java</groupId>
                <artifactId>newrelic-java</artifactId>
                <version>5.12.1</version>
                <scope>provided</scope>
                <type>zip</type>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-mongodb</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-rest</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-mail</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.session</groupId>
                <artifactId>spring-session-core</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.google.auth</groupId>
                <artifactId>google-auth-library-oauth2-http</artifactId>
                <version>0.16.1</version>
            </dependency>
            <dependency>
                <groupId>com.google.firebase</groupId>
                <artifactId>firebase-admin</artifactId>
                <version>6.9.0</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-annotations</artifactId>
                <version>1.5.14</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>4.1.2</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.1.2</version>
            </dependency>
    
            <dependency>
                <groupId>org.passay</groupId>
                <artifactId>passay</artifactId>
                <version>1.6.0</version>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>3.0.2</version>
                    <executions>
                        <execution>
                            <id>unpack-newrelic</id>
                            <phase>package</phase>
                            <goals>
                                <goal>unpack-dependencies</goal>
                            </goals>
                            <configuration>
                                <includeGroupIds>com.newrelic.agent.java</includeGroupIds>
                                <includeArtifactIds>newrelic-java</includeArtifactIds>
                                <overWriteReleases>false</overWriteReleases>
                                <overWriteSnapshots>false</overWriteSnapshots>
                                <overWriteIfNewer>true</overWriteIfNewer>
                                <outputDirectory>${project.basedir}</outputDirectory>
                                <destFileName>newrelic</destFileName>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
    </project>

项目.java

    /*
     *  Copyright (C) 2020
     *  Produced by Wuidev
     */
    package com.myproject.api.model;
    
    import lombok.Data;
    import org.springframework.data.annotation.Id;
    
    @Data
    public class Item {
    
        @Id
        private String id;
    
    }

MenuChoice.java

    /*
     *  Copyright (C) 2020
     *  Produced by Wuidev
     */
    package com.myproject.api.model;
    
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    import org.springframework.data.mongodb.core.index.Indexed;
    import org.springframework.data.mongodb.core.mapping.DBRef;
    
    import java.util.List;
    
    @Data
    @EqualsAndHashCode(callSuper = false)
    public class MenuChoice extends Item {
    
    //    private String customerId;
        @DBRef
        private Customer customer;
    
        @Indexed
        @DBRef
        private Menu menu;
    //    private String menuId;
        private List<MenuItemChoice> choices;
        private String comment;
        private String timeSlot;
    
    }

MenuChoiceRepository.java

package com.myproject.api.dao;

import com.myproject.api.model.Menu;
import com.myproject.api.model.MenuChoice;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;

/**
 * The interface Menu choice repository.
 */
public interface MenuChoiceRepository extends MongoRepository<MenuChoice, String> {

    
    /**
     * Find all by menu list.
     *
     * @param menu the menu
     * @return the list
     */
    List<MenuChoice> findAllByMenu(Menu menu);

}

DefaultMenuChoiceService


@Component
public class DefaultMenuChoiceService extends AbstractDefaultItemService<MenuChoice> implements MenuChoiceService {

    @Override
    public List<MenuChoice> getChoicesForMenu(final Menu m) {
        final long startTime = System.currentTimeMillis();
        if(m == null) {
            return Collections.emptyList();
        }
        final List<MenuChoice> choices = menuChoiceRepository.findAllByMenu(m);
//        final List<MenuChoice> choices = menuChoiceRepository.findAllByMenu_Id(m.getId());
        LOG.info("getChoicesForMenu total = {}", (System.currentTimeMillis() - startTime));
        return choices;
    }


}

结果

我已将 mongoTemplate 日志记录级别设置为 DEBUG,这是查询:

find using query: { "menu" : { "$java" : { "$ref" : "menu", "$id" : "foo" } } } fields: Document{{}} for class: class com.myproject.api.model.MenuChoice in collection: menuChoice

在本地环境中

MenuChoices 文档总数:22

返回的 MenuChoice 文档数:1

getChoicesForMenu total = 561

在生产环境中

MenuChoices 文档总数:341

返回的 MenuChoice 文档数:27

getChoicesForMenu total = 27149

尝试过的解决方案

1.在MenuChoice集合的菜单字段上添加索引

2.升级Spring Boot版本

  1. 我试过关闭再打开

但一切都没有改变。

Answers

我怀疑您的问题在于 @DBRef。我从未使用过它,但根据文档,您的查询还将从不同的集合中检索 Customers,Menu 也是如此(即每个 MenuChoice +2 查询,不知道如何SpringJPA 处理它,但由于 MongoDB 是 NO-SQL,我怀疑这些查询是不同的)。

MongoDB 上的更多详细信息 - DBREF 是否必要?

查询在 Compass 中运行得如此之快的原因是这些额外的查询没有被执行,而 SpringJPA 也执行额外的查询,所以你有一个完整的 POJO。

在改进方面,您有以下选择:

  1. 对 Menu 和 Customer 使用外键并根据需要检索它们。

  2. 将 Customer 和 Menu 移动到同一个集合中,因此不需要引用。

  3. 如果您希望使用引用,那么 MongoDB 不适合,请考虑使用 Postgre、MySQL、MSSQL、OracleSQL 等关系数据库。

Logo

MongoDB社区为您提供最前沿的新闻资讯和知识内容

更多推荐