【问题标题】:Mongodb read query very slow with Spring Data and fast with MorphiaMongodb 使用 Spring Data 读取查询非常慢,使用 Morphia 读取查询非常快
【发布时间】:2016-07-02 13:06:52
【问题描述】:

我想将我的项目从 Morphia 转换为 Spring Data,但是 Spring Data 的一些基本查询非常慢。

例如:

@Override
public List<PTDefaultBlacklistContact> findByBlacklistId(ObjectId defaultBlacklistId, int limit, int offset, String sortBy) {
    Query query = Query.query(Criteria.where("blacklistId").is(defaultBlacklistId));

    if (limit != 0)
        query.limit(limit);

    if (offset != 0)
        query.skip(offset);

    if (StringUtils.hasLength(sortBy))
        query.with(new Sort(sortBy));


    log.debug("findByBlacklistId query={}", query);
    return mongoOperations.find(query, PTDefaultBlacklistContact.class);
}

大约需要 2 分钟

还有 Morphia

@Override
public List<PTDefaultBlacklistContact> findByBlacklistId(ObjectId defaultBlacklistId, int limit, int offset, String sortBy) {
    Query<PTDefaultBlacklistContact> q = createQuery().disableValidation().filter("blacklistId", defaultBlacklistId).limit(limit)
        .offset(offset);
    if (StringUtils.hasLength(sortBy)) {
        q.order(sortBy);
    }
    return q.asList();
}

大约需要 5 秒。

我的配置是基本的,所以理解起来很奇怪。 我只是在我的 application.yml 中有这个,并且有 spring boot mongodb 自动配置。

spring.data.mongodb.uri: mongodb://serv1,serv2,serv3/${mongodb.database}

有什么想法吗? 我想知道原因是否可能是生命周期的事件。

谢谢

编辑:

型号:

PTDefaultBlacklistContact

@Document(collection = "PTDefaultBlacklistContact")
public class PTDefaultBlacklistContact extends PTModel {
private static final long serialVersionUID = 1L;
@Deprecated
@DBRef
protected PTDefaultBlacklist blacklist;
private   String             identifier;
@Indexed
private   ObjectId           blacklistId;

private List<PTHistory> history;

public PTDefaultBlacklistContact() {
}

@Override
public int hashCode() {
    int prime = 31;
    int result = 1;
    result = prime * result + ((blacklistId == null) ? 0 : blacklistId.hashCode());
    result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    PTDefaultBlacklistContact other = (PTDefaultBlacklistContact) obj;
    if (blacklistId == null) {
        if (other.blacklistId != null) {
            return false;
        }
    } else if (!blacklistId.equals(other.blacklistId)) {
        return false;
    }
    if (identifier == null) {
        if (other.identifier != null) {
            return false;
        }
    } else if (!identifier.equals(other.identifier)) {
        return false;
    }
    return true;
}

@Override
public String toString() {
    return "PTDefaultBlacklistContact{" +
        "identifier='" + identifier + '\'' +
        ", blacklistId=" + blacklistId +
        '}';
}

public List<PTHistory> getHistory() {
    return history;
}

public void setHistory(List<PTHistory> history) {
    this.history = history;
}

public String getIdentifier() {
    return identifier;
}

public void setIdentifier(String identifier) {
    this.identifier = identifier;
}

@Deprecated
public PTDefaultBlacklist getBlacklist() {
    return blacklist;
}

@Deprecated
public void setBlacklist(PTDefaultBlacklist blacklist) {
    this.blacklist = blacklist;
}

public ObjectId getBlacklistId() {
    if (blacklist != null) {
        blacklistId = blacklist.getId();
    }
    return blacklistId;
}

public void setBlacklistId(ObjectId blacklistId) {
    this.blacklistId = blacklistId;
}

}

PT历史

public class PTHistory {

private Long       date;
@DBRef
private PTCampaign campaign;

public Long getDate() {
    return date;
}

public void setDate(Long date) {
    this.date = date;
}

public PTCampaign getCampaign() {
    return campaign;
}

public void setCampaign(PTCampaign campaign) {
    this.campaign = campaign;
}


}

【问题讨论】:

  • 这很奇怪。还有其他代码差异吗? PTDefaultBlacklistContact 类是什么样的?有@DBRef 注释吗?
  • 您实际上是针对同一个数据源还是两个不同的数据源运行它?我之所以这么问,是因为时间差异会发出“索引”,其中一个来源有字段索引,而另一个没有。
  • 嗨,感谢 cmets。我已经用一些课程编辑了第一篇文章。 @BlakesSeven 这是同一个数据源,只是一个不同的库:morphia vs spring data。
  • 复制完整的“最小”示例的任何机会,作为“两种”实现,作为 spring-mongo 和 morphia 一个。我确实注意到,如前所述,您确实在使用@DBRef,因此我怀疑在较慢的示例中发生了链接引用的自动“扩展”,而在另一个示例中不会自动发生。 DBRef 真的很“邪恶”,因此通常最好使用其他方法来引用其他集合中的数据。
  • 感谢@BlakesSeven。我已经尝试了一些有和没有参考的样本,没有参考会好很多!我将继续努力,并尝试用另一个对象的经典 ID 替换引用。

标签: java mongodb spring-data spring-data-mongodb morphia


【解决方案1】:

使用上面的 DBRef 配置,您将在默认情况下使用 Spring Data 急切地解决所有这些问题。这将导致在读取文档时遇到的每个 DBRef 都会发出额外的查询。

我们通常建议使用@DBRef(lazy = true) 来避免这些调用,而是只在它们被访问时读取它们。

【讨论】:

  • 谢谢奥利弗。我添加了一些细节。你知道为什么 Morphia 速度很快(引用和惰性 = false),而 Spring Data 速度很慢吗? (相同的配置,带引用和lazy = false)
  • 在我的情况下也是如此,使用 Spring Data 访问文档相对较慢。 @BkSouX 您是否找到任何解决方法或更好的解决方案?
  • 如果你有很多 @DbRef,Spring Data 可能会很慢。它需要大量的数据库请求来加载所有引用的数据。您可能必须断开两个集合之间的链接以提高性能
【解决方案2】:

感谢布雷克七号,这是我对同一个系列的一些测试的调查。我只是添加或删除了引用。

Morphia 和参考文献:

% Total % Received % Xferd 平均速度 时间 时间 时间 当前 下载上传总花费剩余速度 100 1472k 0 1472k 0 0 1970k 0 --:--:-- --:--:-- --:--:-- 1968k

真实0m0.752s 用户 0m0.008s 系统 0m0.000s

没有参考文献的 Morphia:

% Total % Received % Xferd 平均速度 时间 时间 时间 当前 下载上传总花费剩余速度 100 1472k 0 1472k 0 0 3022k 0 --:--:-- --:--:-- --:--:-- 3016k

真正的0m0.492s 用户 0m0.012s 系统 0m0.000s

使用带有引用的 Spring Data:

% Total % Received % Xferd 平均速度 时间 时间 时间 当前 下载上传总花费剩余速度 100 1472k 0 1472k 0 0 96901 0 --:--:-- 0:00:15 --:--:-- 338k

真正的0m15.567s 用户 0m0.008s 系统 0m0.004s

使用带有 LAZY 引用的 Spring Data:

% Total % Received % Xferd 平均速度 时间 时间 时间 当前 下载上传总花费剩余速度 100 1472k 0 1472k 0 0 703k 0 --:--:-- 0:00:02 --:--:-- 703k

真正的0m2.111s 用户 0m0.016s 系统 0m0.000s

使用没有引用的 Spring Data:

% Total % Received % Xferd 平均速度 时间 时间 时间 当前 下载上传总花费剩余速度 100 1472k 0 1472k 0 0 887k 0 --:--:-- 0:00:01 --:--:-- 887k

真正的0m1.722s 用户 0m0.008s 系统 0m0.012s

我真的不明白为什么在不使用惰性引用的情况下使用 Morphia 会这么快。或者使用带有引用的 Spring Data 太慢了。有人有想法吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    • 2020-01-10
    相关资源
    最近更新 更多