Проблема производительности при запросе отношения многие-к-одному с помощью jpa - PullRequest
0 голосов
/ 22 октября 2019

Я использую spring-boot-data-jpa-2.0 для получения данных из БД. Таблица имеет отношение «многие-к-одному», а скорость запроса слишком низкая, 1000 строк данных с внешним ключом будут стоить 15 с, но для нативного sql это будет стоить всего 0,07 с. Я искал проблему и обнаружил, что это потому, что проблема 1 + n.

Может решить какое-то решение, которое гласит использование 'join fetch' в hql. Когда я использую 'join fetch' в hql, скорость запроса не меняется.

Система, спроектированная как сервис чистого отдыха с инфраструктурой весенней загрузки.

Контрактная сущность


import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "MA_CONTRACTINFO_B")

public class MaContractinfoB implements java.io.Serializable {

    // Fields

    private String contractcd;
    private MaDepartmentB maDepartmentB;
    private Double contractid;
    private String contractnm;
    private String partya;
    private String deputycontract;
    private String prjtype;
    private Double fundt;
    private String bustype;
    private String contractstatus;
    private Double contractyear;
    private String fundratio;
    private LocalDateTime signdate;
    private String prj;
    private LocalDateTime loaddate;
    private String udep;
    private Double fundaccont;
    private Double receipt;
    private Double fundacctot;
    private Double receiptot;
    private String loc;
    private String riskasscd;
    private String rm;
    private String pm;
    private Double fundaccrec;
    private String adminleader;
    private String techleader;
    private String leader;
    private String progress;
    private String cashadmin;
    private String timetask;
    private String contracttp;

    // Constructors

    /** default constructor */
    public MaContractinfoB() {
    }

    /** minimal constructor */
    public MaContractinfoB(String contractcd) {
        this.contractcd = contractcd;
    }

    /** full constructor */
    public MaContractinfoB(String contractcd, MaDepartmentB maDepartmentB, Double contractid, String contractnm,
            String partya, String deputycontract, String prjtype, Double fundt, String bustype, String contractstatus,
            Double contractyear, String fundratio, LocalDateTime signdate, String prj, LocalDateTime loaddate,
            String udep, Double fundaccont, Double receipt, Double fundacctot, Double receiptot, String loc,
            String riskasscd, String rm, String pm, Double fundaccrec, String adminleader, String techleader,
            String leader, String progress, String cashadmin, String timetask, String contracttp) {
        this.contractcd = contractcd;
        this.maDepartmentB = maDepartmentB;
        this.contractid = contractid;
        this.contractnm = contractnm;
        this.partya = partya;
        this.deputycontract = deputycontract;
        this.prjtype = prjtype;
        this.fundt = fundt;
        this.bustype = bustype;
        this.contractstatus = contractstatus;
        this.contractyear = contractyear;
        this.fundratio = fundratio;
        this.signdate = signdate;
        this.prj = prj;
        this.loaddate = loaddate;
        this.udep = udep;
        this.fundaccont = fundaccont;
        this.receipt = receipt;
        this.fundacctot = fundacctot;
        this.receiptot = receiptot;
        this.loc = loc;
        this.riskasscd = riskasscd;
        this.rm = rm;
        this.pm = pm;
        this.fundaccrec = fundaccrec;
        this.adminleader = adminleader;
        this.techleader = techleader;
        this.leader = leader;
        this.progress = progress;
        this.cashadmin = cashadmin;
        this.timetask = timetask;
        this.contracttp = contracttp;
    }

    // Property accessors
    @Id

    @Column(name = "CONTRACTCD", unique = true, nullable = false)

    public String getContractcd() {
        return this.contractcd;
    }

    public void setContractcd(String contractcd) {
        this.contractcd = contractcd;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "DEPID")

    public MaDepartmentB getMaDepartmentB() {
        return this.maDepartmentB;
    }

    public void setMaDepartmentB(MaDepartmentB maDepartmentB) {
        this.maDepartmentB = maDepartmentB;
    }

    @Column(name = "CONTRACTID", precision = 38, scale = 8)

    public Double getContractid() {
        return this.contractid;
    }

    public void setContractid(Double contractid) {
        this.contractid = contractid;
    }

    @Column(name = "CONTRACTNM")

    public String getContractnm() {
        return this.contractnm;
    }

    public void setContractnm(String contractnm) {
        this.contractnm = contractnm;
    }

    @Column(name = "PARTYA")

    public String getPartya() {
        return this.partya;
    }

    public void setPartya(String partya) {
        this.partya = partya;
    }

    @Column(name = "DEPUTYCONTRACT")

    public String getDeputycontract() {
        return this.deputycontract;
    }

    public void setDeputycontract(String deputycontract) {
        this.deputycontract = deputycontract;
    }

    @Column(name = "PRJTYPE")

    public String getPrjtype() {
        return this.prjtype;
    }

    public void setPrjtype(String prjtype) {
        this.prjtype = prjtype;
    }

    @Column(name = "FUNDT", precision = 38, scale = 8)

    public Double getFundt() {
        return this.fundt;
    }

    public void setFundt(Double fundt) {
        this.fundt = fundt;
    }

    @Column(name = "BUSTYPE")

    public String getBustype() {
        return this.bustype;
    }

    public void setBustype(String bustype) {
        this.bustype = bustype;
    }

    @Column(name = "CONTRACTSTATUS")

    public String getContractstatus() {
        return this.contractstatus;
    }

    public void setContractstatus(String contractstatus) {
        this.contractstatus = contractstatus;
    }

    @Column(name = "CONTRACTYEAR", precision = 38, scale = 8)

    public Double getContractyear() {
        return this.contractyear;
    }

    public void setContractyear(Double contractyear) {
        this.contractyear = contractyear;
    }

    @Column(name = "FUNDRATIO")

    public String getFundratio() {
        return this.fundratio;
    }

    public void setFundratio(String fundratio) {
        this.fundratio = fundratio;
    }

    @Column(name = "SIGNDATE", length = 11)

    public LocalDateTime getSigndate() {
        return this.signdate;
    }

    public void setSigndate(LocalDateTime signdate) {
        this.signdate = signdate;
    }

    @Column(name = "PRJ")

    public String getPrj() {
        return this.prj;
    }

    public void setPrj(String prj) {
        this.prj = prj;
    }

    @Column(name = "LOADDATE", length = 11)

    public LocalDateTime getLoaddate() {
        return this.loaddate;
    }

    public void setLoaddate(LocalDateTime loaddate) {
        this.loaddate = loaddate;
    }

    @Column(name = "UDEP")

    public String getUdep() {
        return this.udep;
    }

    public void setUdep(String udep) {
        this.udep = udep;
    }

    @Column(name = "FUNDACCONT", precision = 38, scale = 8)

    public Double getFundaccont() {
        return this.fundaccont;
    }

    public void setFundaccont(Double fundaccont) {
        this.fundaccont = fundaccont;
    }

    @Column(name = "RECEIPT", precision = 38, scale = 8)

    public Double getReceipt() {
        return this.receipt;
    }

    public void setReceipt(Double receipt) {
        this.receipt = receipt;
    }

    @Column(name = "FUNDACCTOT", precision = 38, scale = 8)

    public Double getFundacctot() {
        return this.fundacctot;
    }

    public void setFundacctot(Double fundacctot) {
        this.fundacctot = fundacctot;
    }

    @Column(name = "RECEIPTOT", precision = 38, scale = 8)

    public Double getReceiptot() {
        return this.receiptot;
    }

    public void setReceiptot(Double receiptot) {
        this.receiptot = receiptot;
    }

    @Column(name = "LOC")

    public String getLoc() {
        return this.loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    @Column(name = "RISKASSCD")

    public String getRiskasscd() {
        return this.riskasscd;
    }

    public void setRiskasscd(String riskasscd) {
        this.riskasscd = riskasscd;
    }

    @Column(name = "RM")

    public String getRm() {
        return this.rm;
    }

    public void setRm(String rm) {
        this.rm = rm;
    }

    @Column(name = "PM")

    public String getPm() {
        return this.pm;
    }

    public void setPm(String pm) {
        this.pm = pm;
    }

    @Column(name = "FUNDACCREC", precision = 38, scale = 8)

    public Double getFundaccrec() {
        return this.fundaccrec;
    }

    public void setFundaccrec(Double fundaccrec) {
        this.fundaccrec = fundaccrec;
    }

    @Column(name = "ADMINLEADER")

    public String getAdminleader() {
        return this.adminleader;
    }

    public void setAdminleader(String adminleader) {
        this.adminleader = adminleader;
    }

    @Column(name = "TECHLEADER")

    public String getTechleader() {
        return this.techleader;
    }

    public void setTechleader(String techleader) {
        this.techleader = techleader;
    }

    @Column(name = "LEADER", length = 20)

    public String getLeader() {
        return this.leader;
    }

    public void setLeader(String leader) {
        this.leader = leader;
    }

    @Column(name = "PROGRESS", length = 1000)

    public String getProgress() {
        return this.progress;
    }

    public void setProgress(String progress) {
        this.progress = progress;
    }

    @Column(name = "CASHADMIN", length = 20)

    public String getCashadmin() {
        return this.cashadmin;
    }

    public void setCashadmin(String cashadmin) {
        this.cashadmin = cashadmin;
    }

    @Column(name = "TIMETASK", length = 2000)

    public String getTimetask() {
        return this.timetask;
    }

    public void setTimetask(String timetask) {
        this.timetask = timetask;
    }

    @Column(name = "CONTRACTTP", length = 50)

    public String getContracttp() {
        return this.contracttp;
    }

    public void setContracttp(String contracttp) {
        this.contracttp = contracttp;
    }

    /**
     * toString
     *
     * @return String
     */
    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();

        buffer.append(getClass().getName()).append("@").append(Integer.toHexString(hashCode())).append(" [");
        buffer.append("contractcd").append("='").append(getContractcd()).append("' ");
        buffer.append("maDepartmentB").append("='").append(getMaDepartmentB()).append("' ");
        buffer.append("contractid").append("='").append(getContractid()).append("' ");
        buffer.append("contractnm").append("='").append(getContractnm()).append("' ");
        buffer.append("partya").append("='").append(getPartya()).append("' ");
        buffer.append("deputycontract").append("='").append(getDeputycontract()).append("' ");
        buffer.append("prjtype").append("='").append(getPrjtype()).append("' ");
        buffer.append("fundt").append("='").append(getFundt()).append("' ");
        buffer.append("bustype").append("='").append(getBustype()).append("' ");
        buffer.append("contractstatus").append("='").append(getContractstatus()).append("' ");
        buffer.append("contractyear").append("='").append(getContractyear()).append("' ");
        buffer.append("fundratio").append("='").append(getFundratio()).append("' ");
        buffer.append("signdate").append("='").append(getSigndate()).append("' ");
        buffer.append("prj").append("='").append(getPrj()).append("' ");
        buffer.append("loaddate").append("='").append(getLoaddate()).append("' ");
        buffer.append("udep").append("='").append(getUdep()).append("' ");
        buffer.append("fundaccont").append("='").append(getFundaccont()).append("' ");
        buffer.append("receipt").append("='").append(getReceipt()).append("' ");
        buffer.append("fundacctot").append("='").append(getFundacctot()).append("' ");
        buffer.append("receiptot").append("='").append(getReceiptot()).append("' ");
        buffer.append("loc").append("='").append(getLoc()).append("' ");
        buffer.append("riskasscd").append("='").append(getRiskasscd()).append("' ");
        buffer.append("rm").append("='").append(getRm()).append("' ");
        buffer.append("pm").append("='").append(getPm()).append("' ");
        buffer.append("fundaccrec").append("='").append(getFundaccrec()).append("' ");
        buffer.append("adminleader").append("='").append(getAdminleader()).append("' ");
        buffer.append("techleader").append("='").append(getTechleader()).append("' ");
        buffer.append("leader").append("='").append(getLeader()).append("' ");
        buffer.append("progress").append("='").append(getProgress()).append("' ");
        buffer.append("cashadmin").append("='").append(getCashadmin()).append("' ");
        buffer.append("timetask").append("='").append(getTimetask()).append("' ");
        buffer.append("contracttp").append("='").append(getContracttp()).append("' ");
        buffer.append("]");

        return buffer.toString();
    }

}

сущность отдела


import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "MA_DEPARTMENT_B")

public class MaDepartmentB implements java.io.Serializable {

    // Fields

    private Long id;
    private String name;
    private String leader;
    private Set<MaContractinfoB> maContractinfoBs = new HashSet<MaContractinfoB>(0);
    private Set<MaContraimB> maContraimBs = new HashSet<MaContraimB>(0);

    // Constructors

    /** default constructor */
    public MaDepartmentB() {
    }

    /** minimal constructor */
    public MaDepartmentB(Long id) {
        this.id = id;
    }

    /** full constructor */
    public MaDepartmentB(Long id, String name, String leader, Set<MaContractinfoB> maContractinfoBs,
            Set<MaContraimB> maContraimBs) {
        this.id = id;
        this.name = name;
        this.leader = leader;
        this.maContractinfoBs = maContractinfoBs;
        this.maContraimBs = maContraimBs;
    }

    // Property accessors
    @Id

    @Column(name = "ID", unique = true, nullable = false, precision = 10, scale = 0)

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "NAME")

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name = "LEADER")

    public String getLeader() {
        return this.leader;
    }

    public void setLeader(String leader) {
        this.leader = leader;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "maDepartmentB")

    public Set<MaContractinfoB> getMaContractinfoBs() {
        return this.maContractinfoBs;
    }

    public void setMaContractinfoBs(Set<MaContractinfoB> maContractinfoBs) {
        this.maContractinfoBs = maContractinfoBs;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "maDepartmentB")

    public Set<MaContraimB> getMaContraimBs() {
        return this.maContraimBs;
    }

    public void setMaContraimBs(Set<MaContraimB> maContraimBs) {
        this.maContraimBs = maContraimBs;
    }

    /**
     * toString
     *
     * @return String
     */
    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();

        buffer.append(getClass().getName()).append("@").append(Integer.toHexString(hashCode())).append(" [");
        buffer.append("id").append("='").append(getId()).append("' ");
        buffer.append("name").append("='").append(getName()).append("' ");
        buffer.append("leader").append("='").append(getLeader()).append("' ");
        buffer.append("maContractinfoBs").append("='").append(getMaContractinfoBs()).append("' ");
        buffer.append("maContraimBs").append("='").append(getMaContraimBs()).append("' ");
        buffer.append("]");

        return buffer.toString();
    }

}

jparepository

public interface MaContractinfoBRepository extends JpaRepository<MaContractinfoB, Long> {
    @Query("from MaContractinfoB c join fetch c.maDepartmentB")
    List<MaContractinfoB> findAll();

    @Query("select contractnm from MaContractinfoB")
    List<String> findAllName();

//    @Query("from MaContractinfoB c join fetch c.maDepartmentB")
//    List test();
}

В MaContractinfoBRepository, когда я использую функцию findAllName, она немедленно возвращает 1000 имен контрактов в 0,05 с. Когда я использую findAll, это будет стоить 15 секунд, чтобы получить 1000 данных с сущностью отдела, даже если я добавлю выборку соединения. Но если я получу его с помощью встроенного средства sql в инструменте db, такого как navicat, это будет стоить всего 0,07 с.

Не упущена ли какая-либо ключевая точка? Как сделать запрос к таблице MaContractinfoB не так медленно?

1 Ответ

0 голосов
/ 28 октября 2019

Это происходит потому, что внутренне с помощью команды 'fetch' также hibernate лениво загружает все строки сущности Department для каждого идентификатора Contract каждый раз, когда вы вызываете метод findAll (). Таким образом, если в Департаменте n строк для 1 Контракта, а всего m Контрактов, то общее количество обращений к базе данных будет равно 'm * n'.

Одним из способов решения этой проблемы является использование DTO-проекций. ,Объекты передачи данных - это простой способ определить все необходимые столбцы в одном запросе и один раз обратиться к базе данных.

Я нашел эту статью полезной, которая показывает несколько способов написания DTO-проекций. https://thoughts -on-java.org / dto-projection /

Один из упомянутых способов: Используя JPQL, вы можете использовать выражение конструктора для определения вызова конструктора с ключевым словом newза ним следует полностью классифицированное имя класса вашего DTO и список параметров конструктора в фигурных скобках. Примерно так:

TypedQuery<ContractWithDepartmentDetails> q = em.createQuery(
        "SELECT new com.practice.model.ContractWithDepartmentDetails(c.id, c.name, d.name) FROM contract c JOIN c.department d",
        ContractWithDepartmentDetails.class);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...