为什么JPA查询这么慢?

时间:2016-09-13 16:35:21

标签: spring hibernate rest jpa-2.0

我正在使用JPA存储库在我的Web应用程序中实现查询。我要查询的两个主要表格是FmReportTbSpecimenTb

以下是两个实体类(仅列出重要属性)。

//FmReportTb.java
@Entity
@Table(name="FM_REPORT_TB")
public class FmReportTb implements Serializable {

    @Column(name="ROW_ID")
    private long rowId;

    @Column(name="FR_BLOCK_ID")
    private String frBlockId;

    @Column(name="FR_FULL_NAME")
    private String frFullName;
    @OneToOne
    @JoinColumn(name="SPECIMEN_ID")
    private SpecimenTb specimenTb;

FmReportTbSpecimenTb有OneToOne关系。

@Entity
@Table(name="SPECIMEN_TB")
public class SpecimenTb implements Serializable {
    private String mrn;
    @OneToOne(mappedBy="specimenTb", cascade=CascadeType.ALL)
    private FmReportTb fmReportTb;

我正在处理的查询是查找FmReportTb中的所有记录,并显示来自FmReportTb的{​​{1}}加mrn的一些属性。 这是SpecimenTb的JPA存储库:

FmReportTb

因为,我只显示@Repository public interface FmReportRepository extends JpaRepository<FmReportTb, Long> { @Query("select f from FmReportTb f where f.deleteTs is not null") public List<FmReportTb> findAllFmReports(); 的部分属性和FmReportTb的一个属性,所以我决定为SpecimenTb创建一个值对象。 VO类的构造函数根据OneToOne关系从FmReportTb分配属性并从FmReportTb获取mrn属性。使用VO的另一个原因是因为表SpecimenTb有很多OneToMany子实体。对于这个特定的查询,我不需要任何查询。

FmReportTb

我在servicebean类中实现了findall方法,以返回public class FmReportVO { private String frBlockId; private Date frCollectionDate; private String frCopiedPhysician; private String frDiagnosis; private String frFacilityName; private String frFullName; private String frReportId; private String filepath; private String mrn; public FmReportVO(FmReportTb fmReport) { this.frBlockId = fmReport.getFrBlockId(); this.frCollectionDate = fmReport.getFrCollectionDate(); this.frCopiedPhysician = fmReport.getFrCopiedPhysician(); this.frDiagnosis = fmReport.getFrDiagnosis(); this.frFacilityName = fmReport.getFrFacilityName(); this.frFullName = fmReport.getFrFullName(); this.frReportId = fmReport.getFrReportId(); this.mrn = fmReport.getSpecimenTb().getMrn(); } VO的列表。

FmReportTb

最后,我的控制器看起来像这样:

//FmReportServiceBean.java
    @Override
    public List<FmReportVO> findAllFmReports() {
        List<FmReportTb> reports = fmReportRepository.findAllFmReports();
        if (reports == null) {
            return null;
        }
        List<FmReportVO> fmReports = new ArrayList<FmReportVO>();
        for (FmReportTb report : reports) {
            FmReportVO reportVo = new FmReportVO(report);
            String filepath = fileLoadRepository.findUriByFileLoadId(report.getFileLoadId().longValue());
            reportVo.setFilepath(filepath);
            fmReports.add(reportVo);
        }
        return fmReports;
    }

数据库中有大约200条记录。令人惊讶的是,用JSON检索所有记录花了差不多2秒钟。即使我没有索引所有表,但这太慢了。类似的查询直接在数据库上花费大约几毫秒。是因为我使用的是Value Objects还是JPA查询往往会这么慢?

编辑1 这可能与FmReportTb具有近20个OneToMany实体的事实有关。虽然这些子实体的fetchmode设置为LAZY,JPA Data repository tends to ignore the fetchmode。所以我最终使用@RequestMapping( value = "/ristore/foundation/", method = RequestMethod.GET, produces = "application/json") public ResponseEntity<List<FmReportVO>> getAllFmReports() { List<FmReportVO> reports = ristoreService.findAllFmReports(); if (reports == null) { return new ResponseEntity<List<FmReportVO>>(HttpStatus.NOT_FOUND); } return new ResponseEntity<List<FmReportVO>>(reports, HttpStatus.OK); } 来指定EAGER属性。下一节将添加到我的FmReportTb实体类的头部。

NamedEntityGraph

然后在JPA存储库查询之前添加@Entity @NamedEntityGraph( name = "FmReportGraph", attributeNodes = { @NamedAttributeNode("fileLoadId"), @NamedAttributeNode("frBlockId"), @NamedAttributeNode("frCollectionDate"), @NamedAttributeNode("frDiagnosis"), @NamedAttributeNode("frFullName"), @NamedAttributeNode("frReportId"), @NamedAttributeNode("specimenTb")}) @Table(name="FM_REPORT_TB") 以查找所有记录。在这之后,性能得到了一点改善。现在获取1500条记录只需要大约10秒钟。但是,鉴于每个json对象相当小,它看起来仍然太慢。

1 个答案:

答案 0 :(得分:0)

JPA查询速度缓慢的其他人正在寻求帮助...

正如@Ken Bekov在评论中暗示的那样,外键对JPA可以有很大帮助。

我有几个具有多对一关系的表-100,000条记录的查询要花几个小时才能执行。无需任何代码更改,我只需添加外键即可将其减少到几秒钟。

在phpMyAdmin中,您可以通过创建从“许多”表到“一个”表的关系来做到这一点。有关详细说明,请参见以下问题:Setting up foreign keys in phpMyAdmin? 还有@Devsi Odedra的答案