JPA + spring 启动 - 当数据库很大时 findBy <field> 非常慢(20M 行 Table )
JPA + spring boot - findBy <field> extremely slow when Database is huge ( 20M lines Table )
我需要关于 JPA spring 数据的关联。
我有使用 MySQL 和 20GB 数据(20 米行)的数据库。
当我执行 findByID (String id) - (不是唯一标识符)。
需要10多分钟...
什么是性能问题??
我的对象实体:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long rootId;
private String address;
private String check_in_time;
private String check_out_time;
@OneToMany(mappedBy = "data" , fetch = FetchType.LAZY)
private Set<DescriptionStruct> description_struct;
private String id;
@ElementCollection(fetch = FetchType.LAZY)
private Set<String> images;
private String kind;
private double latitude;
private double longitude;
private String name;
private String phone;
@Embedded
private Star_certificate star_certificate;
private String postal_code;
@AttributeOverrides({ @AttributeOverride(name = "id", column = @Column(name = "R_ID")),
@AttributeOverride(name = "name", column = @Column(name = "R_NAME")) })
@Embedded
private Region region;
private int star_rating;
private String email;
private int semantic_version;
@ElementCollection(fetch = FetchType.LAZY)
private Set<String> serp_filters;
private boolean is_closed;
@Embedded
private MetapolicyStruct metapolicy_struct;
private String metapolicy_extra_info;
@Embedded
private Facts facts;
@ElementCollection(fetch = FetchType.LAZY)
private Set<String> payment_methods;
private String hotel_chain;
@OneToMany(mappedBy = "data", fetch = FetchType.LAZY)
private Set<AmenityGroup> amenity_groups;
@OneToMany(mappedBy = "data", fetch = FetchType.LAZY)
private Set<RoomGroup> room_groups;
@OneToMany(mappedBy = "data", fetch = FetchType.LAZY)
private Set<PolicyStruct> policy_struct;
我的函数:
@Autowired
私有数据存储库数据存储库;
public regionSearchData returnFullData(regionSearchResponseRH response) {
regionSearchData data = new regionSearchData();
response.getData().getHotels().forEach(H -> {
Data hotelD = dataRepository.findById(H.getId());
if (hotelD != null) {
RatesSearch R = H.getRates().get(0);
R.setAddress(hotelD.getAddress());
R.setImages(hotelD.getImages());
R.setStar_certificate(hotelD.getStar_certificate());
R.setStar_rating(hotelD.getStar_rating());
R.setName(hotelD.getName());
}
});
data.setTotal_hotels(response.getData().getTotal_hotels());
data.setHotels(response.getData().getHotels());
return data;
}
Hibernate 统计数据:
16893585 nanoseconds spent preparing 42 JDBC statements;
347535215661 nanoseconds spent executing 42 JDBC statements;
656641754926 nanoseconds spent executing 82 JDBC statements;
如果我删除 findBy 需要 10 秒...
谢谢,
伊丹
肯定有不止一种你可以尝试的事情。您的代码需要十多分钟,可能是因为它通过网络对数据库进行了多次往返。
请记住,不仅数据库搜索需要更多时间,从您的应用程序到网络的数据库往返也需要更多时间,我怀疑这里就是这种情况。
根据您的用例,您可以做的第一件事是最小化到 DB 的往返行程并在 for 循环中调用 findById () 是最糟糕的事情。
以下是我的建议
- 正在为您搜索的字段添加索引
- 避免在 for 循环中调用 findById (),您可以使用其他一些存储库方法,或者您可以编写 findByIdsIn(ids 列表),具体取决于此 for 循环的大小 - 您可以一次传递所有 id或使用批处理方法,例如一次获取 20-30 个实体并执行您的业务逻辑。
- 您有许多表使用@oneToMany 或@ElementCollection 连接到您的实体,您需要检查hibernate 是否正在为此执行N+1 查询,如果是,请先解决该问题。
我需要关于 JPA spring 数据的关联。 我有使用 MySQL 和 20GB 数据(20 米行)的数据库。 当我执行 findByID (String id) - (不是唯一标识符)。 需要10多分钟...
什么是性能问题??
我的对象实体:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long rootId;
private String address;
private String check_in_time;
private String check_out_time;
@OneToMany(mappedBy = "data" , fetch = FetchType.LAZY)
private Set<DescriptionStruct> description_struct;
private String id;
@ElementCollection(fetch = FetchType.LAZY)
private Set<String> images;
private String kind;
private double latitude;
private double longitude;
private String name;
private String phone;
@Embedded
private Star_certificate star_certificate;
private String postal_code;
@AttributeOverrides({ @AttributeOverride(name = "id", column = @Column(name = "R_ID")),
@AttributeOverride(name = "name", column = @Column(name = "R_NAME")) })
@Embedded
private Region region;
private int star_rating;
private String email;
private int semantic_version;
@ElementCollection(fetch = FetchType.LAZY)
private Set<String> serp_filters;
private boolean is_closed;
@Embedded
private MetapolicyStruct metapolicy_struct;
private String metapolicy_extra_info;
@Embedded
private Facts facts;
@ElementCollection(fetch = FetchType.LAZY)
private Set<String> payment_methods;
private String hotel_chain;
@OneToMany(mappedBy = "data", fetch = FetchType.LAZY)
private Set<AmenityGroup> amenity_groups;
@OneToMany(mappedBy = "data", fetch = FetchType.LAZY)
private Set<RoomGroup> room_groups;
@OneToMany(mappedBy = "data", fetch = FetchType.LAZY)
private Set<PolicyStruct> policy_struct;
我的函数:
@Autowired 私有数据存储库数据存储库;
public regionSearchData returnFullData(regionSearchResponseRH response) {
regionSearchData data = new regionSearchData();
response.getData().getHotels().forEach(H -> {
Data hotelD = dataRepository.findById(H.getId());
if (hotelD != null) {
RatesSearch R = H.getRates().get(0);
R.setAddress(hotelD.getAddress());
R.setImages(hotelD.getImages());
R.setStar_certificate(hotelD.getStar_certificate());
R.setStar_rating(hotelD.getStar_rating());
R.setName(hotelD.getName());
}
});
data.setTotal_hotels(response.getData().getTotal_hotels());
data.setHotels(response.getData().getHotels());
return data;
}
Hibernate 统计数据:
16893585 nanoseconds spent preparing 42 JDBC statements;
347535215661 nanoseconds spent executing 42 JDBC statements;
656641754926 nanoseconds spent executing 82 JDBC statements;
如果我删除 findBy 需要 10 秒...
谢谢, 伊丹
肯定有不止一种你可以尝试的事情。您的代码需要十多分钟,可能是因为它通过网络对数据库进行了多次往返。 请记住,不仅数据库搜索需要更多时间,从您的应用程序到网络的数据库往返也需要更多时间,我怀疑这里就是这种情况。
根据您的用例,您可以做的第一件事是最小化到 DB 的往返行程并在 for 循环中调用 findById () 是最糟糕的事情。 以下是我的建议
- 正在为您搜索的字段添加索引
- 避免在 for 循环中调用 findById (),您可以使用其他一些存储库方法,或者您可以编写 findByIdsIn(ids 列表),具体取决于此 for 循环的大小 - 您可以一次传递所有 id或使用批处理方法,例如一次获取 20-30 个实体并执行您的业务逻辑。
- 您有许多表使用@oneToMany 或@ElementCollection 连接到您的实体,您需要检查hibernate 是否正在为此执行N+1 查询,如果是,请先解决该问题。