从Hibernate加载30k行20秒,是否缓慢?

时间:2017-09-12 15:29:26

标签: java spring hibernate

我使用Spring + hibernate对我的数据库进行查询。数据库大小约为101k行。

我做了以下规范

Predicate predicate = cb.notEqual(root.get("trscnStatus").as(String.class), 
TradeTransactionStatus.DELETED.name());

predicate = cb.and(predicate, cb.equal(root.get("portfolioName"), 
searchCriteria.getPortfolioName()));

我做了

transactionRepository.findAll(transactionsSearchCriteria, sort);

其中是transactionsSearchCriteria我的规范与上面提到的谓词!

我的域名模型是下一个:

@Entity(name="TradeTransactional")
@Table(name="TRANSACTIONS")
public class TradeTransaction implements Serializable, Cloneable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

/**
 * The id.
 */
@Id
@GeneratedValue
private long id;

/**
 * The description.
 */
private String description = "";

/**
 * The comments.
 */
private String comments = "";

/**
 * The mv inv ccy.
 */
@Column(name="mv_inv_ccy")
private double mvInvCcy;

/**
 * The mv inv ccy eur.
 */
@Column(name="mv_inv_ccy_eur")
private double mvInvCcyEur;

/**
 * The mv inv ccy usd.
 */
@Column(name="mv_inv_ccy_usd")
private double mvInvCcyUsd;

/**
 * The portfolio name.
 */
@Column(name="portfolio_name")
private String portfolioName = "";

/**
 * The bbticker.
 */
@Column(name="ticker")
private String ticker = "";

/**
 * The pershing ref.
 */
@Column(name="brg_ref")
private String portfolioRef = "";

/**
 * The trade ref.
 */
@Column(name="trade_ref")
private String uniqueRef = "";

/**
 * The b2b ref.
 */
@Column(name="b2b_ref")
private String b2bRef = "";

/**
 * The sedol ticker.
 */
@Column(name="sedol_ticker")
private String sedolTicker = "";

/**
 * The security number.
 */
@Column(name="id_isin")
private String securityNumber="";

/**
 * Aggregate
 */
@Column(name="aggregate")
private boolean aggregate = false;

/**
 * The purchase date.
 */
@Column(name="purchase_date")
private Date purchaseDate;

/**
 * The settl date.
 */
@Column(name="settl_date")
private Date settlDate;

@Column(name="effect_date")
private Date effectDate;

private Date timestamp = new Date();

@Column(name="conf_timestamp")
private Date conftimestamp = new Date();

/**
 * The purchase price.
 */
@Column(name="purchase_price")
private double purchasePrice;

/**
 * The number of shares.
 */
@Column(name="number_of_shares")
private double numberOfShares;

/**
 * The number of shares nominal
 */ 
@Column(name="number_of_shares_nominal")
private double numberOfSharesNominal=0;

/**
 * The pdf confirmation link.
 */
@Column(name="pdf_confirmation_link")
private String confirmationFileName;

/**
 * The reference number.
 */
@Column(name="reference_number")
private String referenceNumber;

@Transient
private double contractSize = 1;

@Transient
private String globalId;

/**
 * The name.
 */
private String name = "";

/**
 * The ccy.
 */
@Column(name="crncy")
private String ccy = "";

/**
 * The ccy settl.
 */
@Column(name="crncy_settl")
private String ccySettl = "";

/**
 * The custody.
 */
private String custody="";

/**
 * The exch code.
 */
@Column(name="exch_code")
private String exchCode="";

/**
 * The country of risk.
 */
@Column(name="cntry_of_risk")
private String countryOfRisk="";

/**
 * The stl sts.
 */
@Column(name="stl_sts")
private String stlSts;

/**
 * The stl amt base.
 */
@Column(name="stl_amt_base")
private double stlAmtBase;

private double accrued;

@Column(name="reconciled")
private boolean reconciled = false;

@Column(name="cntrprty")
private String counterpartyName = "";

@Enumerated(EnumType.STRING)
@Column(name="trscn_status")
private TradeTransactionStatus trscnStatus = TradeTransactionStatus.ACTIVE;

@Column(name="cash_account")
private String cashAccount;

@Column(name="counterparty")
private String counterpartyAccount="";

@Enumerated(EnumType.STRING)
@Column(name="trade_type")
private TradeTransactionType tradeType = TradeTransactionType.UNKNOWN;

@Column(name="allocated")
private boolean allocated = true;

@Column(name="market_sector_des")
private String marketSectorDes = "";

@Column(name = "trader_uuid")
private String traderUUID;

/* (non-Javadoc)
     * @see com.meritservus.domain.TradeTransaction#getDescription()
     */
public String getDescription() {
    return description;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getId()
 */
public long getId() {
    return id;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getMvInvCcy()
 */
public double getMvInvCcy() {
    return mvInvCcy;
}

/**
 * Sets the id.
 * 
 * @param id
 *            the new id
 */
public void setId(long id) {
    this.id = id;
}

/**
 * Sets the description.
 * 
 * @param description
 *            the new description
 */
public void setDescription(String description) {
    this.description = description;
}

/**
 * Sets the mv inv ccy.
 * 
 * @param mvInvCcy
 *            the new mv inv ccy
 */
public void setMvInvCcy(double mvInvCcy) {
    this.mvInvCcy = mvInvCcy;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getPortfolioName()
 */
public String getPortfolioName() {
    return portfolioName;
}

/**
 * Sets the portfolio name.
 * 
 * @param portfolioName
 *            the new portfolio name
 */
public void setPortfolioName(String portfolioName) {
    this.portfolioName = portfolioName;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getBbticker()
 */
public String getTicker() {
    return ticker;
}

/**
 * Sets the bbticker.
 * 
 * @param bbticker
 *            the new bbticker
 */
public void setTicker(String ticker) {
    this.ticker = ticker;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getAggregate()
 */
public boolean getAggregate() {
    return aggregate;
}

/**
 * Sets the index.
 * 
 * @param index
 *            the new aggregate
 */
public void setAggregate(boolean aggregate) {
    this.aggregate = aggregate;
}

/**
 * @return the allocated
 */
public boolean getAllocated() {
    return allocated;
}

/**
 * @param allocated the allocated to set
 */
public void setAllocated(boolean allocated) {
    this.allocated = allocated;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getName()
 */
public String getName() {
    return name;
}

/**
 * Sets the name.
 * 
 * @param name
 *            the new name
 */
public void setName(String name) {
    this.name = name;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getCcy()
 */
public String getCcy() {
    return ccy;
}

/**
 * Sets the ccy.
 * 
 * @param ccy
 *            the new ccy
 */
public void setCcy(String ccy) {
    this.ccy = ccy;
}

/* (non-Javadoc)
 * @see java.lang.Object#toString()
 */
@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getMvInvCcyEur()
 */
public double getMvInvCcyEur() {
    return mvInvCcyEur;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getMvInvCcyUsd()
 */
public double getMvInvCcyUsd() {
    return mvInvCcyUsd;
}

/**
 * Sets the mv inv ccy eur.
 * 
 * @param mvInvCcyEur
 *            the new mv inv ccy eur
 */
public void setMvInvCcyEur(double mvInvCcyEur) {
    this.mvInvCcyEur = mvInvCcyEur;
}

/**
 * Sets the mv inv ccy usd.
 * 
 * @param mvInvCcyUsd
 *            the new mv inv ccy usd
 */
public void setMvInvCcyUsd(double mvInvCcyUsd) {
    this.mvInvCcyUsd = mvInvCcyUsd;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getSecurityNumber()
 */
public String getSecurityNumber() {
    return securityNumber;
}

/**
 * Sets the security number.
 * 
 * @param securityNumber
 *            the new security number
 */
public void setSecurityNumber(String securityNumber) {
    this.securityNumber = securityNumber;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getPershingRef()
 */
public String getPortfolioRef() {
    return portfolioRef;
}

/**
 * Sets the pershing ref.
 * 
 * @param pershingRef
 *            the new pershing ref
 */
public void setPortfolioRef(String portfolioRef) {
    this.portfolioRef = portfolioRef;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getSedolTicker()
 */
public String getSedolTicker() {
    return sedolTicker;
}

/**
 * Sets the sedol ticker.
 * 
 * @param sedolTicker
 *            the new sedol ticker
 */
public void setSedolTicker(String sedolTicker) {
    this.sedolTicker = sedolTicker;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getPurchaseDate()
 */
public Date getPurchaseDate() {
    return purchaseDate;
}

/**
 * Sets the purchase date.
 * 
 * @param purchaseDate
 *            the new purchase date
 */
public void setPurchaseDate(Date purchaseDate) {
    this.purchaseDate = purchaseDate;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getNumberOfShares()
 */
public double getNumberOfShares() {
    return numberOfShares;
}

/**
 * Sets the number of shares.
 * 
 * @param numberOfShares
 *            the new number of shares
 */
public void setNumberOfShares(double numberOfShares) {
    this.numberOfShares = numberOfShares;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getPurchasePrice()
 */
public double getPurchasePrice() {
    return purchasePrice;
}

/**
 * Sets the purchase price.
 * 
 * @param purchasePrice
 *            the new purchase price
 */
public void setPurchasePrice(double purchasePrice) {
    this.purchasePrice = purchasePrice;
}

/**
 * Sets the string purhcase date to date.
 * 
 * @param purchaseDate
 *            the purchase date
 * @param parsePatterns
 *            the parse patterns
 * @throws Exception
 *             the exception
 */
@Transient
public void setStringPurhcaseDateToDate(String purchaseDate, String... parsePatterns) throws Exception{ 
    Date date = DateUtils.parseDate(purchaseDate, parsePatterns);
    setPurchaseDate(date);
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getCustody()
 */
public String getCustody() {
    return custody;
}

/**
 * Sets the custody.
 * 
 * @param custody
 *            the new custody
 */
public void setCustody(String custody) {
    this.custody = custody;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getExchCode()
 */
public String getExchCode() {
    return exchCode;
}

/**
 * Sets the exch code.
 * 
 * @param exchCode
 *            the new exch code
 */
public void setExchCode(String exchCode) {
    this.exchCode = exchCode;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getComments()
 */
public String getComments() {
    return comments;
}

/**
 * Sets the comments.
 * 
 * @param comments
 *            the new comments
 */
public void setComments(String comments) {
    this.comments = comments;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getPdfConfirmationLink()
 */
public String getConfirmationFileName() {
    return this.confirmationFileName;
}

/**
 * Sets the pdf confirmation link.
 * 
 * @param pdfConfirmationLink
 *            the new pdf confirmation link
 */
public void setConfirmationFileName(String confirmationFileName) {
    this.confirmationFileName = confirmationFileName;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getReferenceNumber()
 */
public String getReferenceNumber() {
    return referenceNumber;
}

/**
 * Sets the reference number.
 * 
 * @param referenceNumber
 *            the new reference number
 */
public void setReferenceNumber(String referenceNumber) {
    this.referenceNumber = referenceNumber;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getStlSts()
 */
public String getStlSts() {
    return stlSts;
}

/**
 * Sets the stl sts.
 * 
 * @param stlSts
 *            the new stl sts
 */
public void setStlSts(String stlSts) {
    this.stlSts = stlSts;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getStlAmtBase()
 */
public double getStlAmtBase() {
    return stlAmtBase;
}

/**
 * Sets the stl amt base.
 * 
 * @param stlAmtBase
 *            the new stl amt base
 */
public void setStlAmtBase(double stlAmtBase) {
    this.stlAmtBase = stlAmtBase;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getSettlDate()
 */
public Date getSettlDate() {
    return settlDate;
}

/**
 * Sets the settl date.
 * 
 * @param settlDate
 *            the new settl date
 */
public void setSettlDate(Date settlDate) {
    this.settlDate = settlDate;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getCcySettl()
 */
public String getCcySettl() {
    return ccySettl;
}

/**
 * Sets the ccy settl.
 * 
 * @param ccySettl
 *            the new ccy settl
 */
public void setCcySettl(String ccySettl) {
    this.ccySettl = ccySettl;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getTradeRef()
 */
public String getUniqueRef() {
    return uniqueRef;
}

/**
 * Sets the trade ref.
 * 
 * @param tradeRef
 *            the new trade ref
 */
public void setUniqueRef(String uniqueRef) {
    this.uniqueRef = uniqueRef;
}

/* (non-Javadoc)
 * @see com.meritservus.domain.TradeTransaction#getB2bRef()
 */
public String getB2bRef() {
    return b2bRef;
}

/**
 * Sets the b2b ref.
 * 
 * @param b2bRef
 *            the new b2b ref
 */
public void setB2bRef(String b2bRef) {
    this.b2bRef = b2bRef;
}

public Date getTimestamp() {
    return timestamp;
}

public void setTimestamp(Date timestamp) {
    this.timestamp = timestamp;
}

public TradeTransactionStatus getTrscnStatus() {
    return trscnStatus;
}

public void setTrscnStatus(TradeTransactionStatus trscnStatus) {
    this.trscnStatus = trscnStatus;
}

public String getCashAccount() {
    return cashAccount;
}

public void setCashAccount(String cashAccount) {
    this.cashAccount = cashAccount;
}

/**
 * @return the counterparty
 */
public String getCounterpartyAccount() {
    return counterpartyAccount;
}

/**
 * @param counterparty the counterparty to set
 */
public void setCounterpartyAccount(String counterpartyAccount) {
    this.counterpartyAccount = counterpartyAccount;
}

/**
 * @return the effectDate
 */
public Date getEffectDate() {
    return effectDate;
}

/**
 * @param effectDate the effectDate to set
 */
public void setEffectDate(Date effectDate) {
    this.effectDate = effectDate;
}

public double getNumberOfSharesNominal() {
    return numberOfSharesNominal;
}

public void setNumberOfSharesNominal(double numberOfSharesNominal) {
    this.numberOfSharesNominal = numberOfSharesNominal;
}

/**
 * @return the tradeType
 */
public TradeTransactionType getTradeType() {
    return tradeType;
}

/**
 * @param tradeType the tradeType to set
 */
public void setTradeType(TradeTransactionType tradeType) {
    this.tradeType = tradeType;
}

/**
 * @return the confTimestamp
 */
public Date getConftimestamp() {
    return conftimestamp;
}

/**
 * @param confTimestamp the confTimestamp to set
 */
public void setConftimestamp(Date confTimestamp) {
    this.conftimestamp = confTimestamp;
}

/**
 * @return the countryOfRisk
 */
public String getCountryOfRisk() {
    return countryOfRisk;
}

/**
 * @param countryOfRisk the countryOfRisk to set
 */
public void setCountryOfRisk(String countryOfRisk) {
    this.countryOfRisk = countryOfRisk;
}

/**
 * @return the reconciled
 */
public boolean isReconciled() {
    return reconciled;
}

/**
 * @param reconciled the reconciled to set
 */
public void setReconciled(boolean reconciled) {
    this.reconciled = reconciled;
}

/**
 * @return the cntrprty
 */
public String getCounterpartyName() {
    return counterpartyName;
}

/**
 * @param cntrprty the cntrprty to set
 */
public void setCounterpartyName(String counterpartyName) {
    this.counterpartyName = counterpartyName;
}

public String getMarketSectorDes() {
    return marketSectorDes;
}

public void setMarketSectorDes(String marketSectorDes) {
    this.marketSectorDes = marketSectorDes;
}

public String getTraderUUID() {
    return traderUUID;
}

public void setTraderUUID(String traderUUID) {
    this.traderUUID = traderUUID;
}


/**
 * @return the accrued
 */
public double getAccrued() {
    return accrued;
}

/**
 * @param accrued the accrued to set
 */
public void setAccrued(double accrued) {
    this.accrued = accrued;
}

 public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

public double getContractSize() {
    return contractSize;
}

public void setContractSize(double contractSize) {
    this.contractSize = contractSize;
}

public String getGlobalId() {
    return globalId;
}

public void setGlobalId(String globalId) {
    this.globalId = globalId;
}
}

我的Hibernate配置是下一个:

properties.put("hibernate.dialect","org.hibernate.dialect.MySQL5Dialect" );
properties.put( "hibernate.autocommit", "false" );         
properties.put( "hibernate.jdbc.batch_size", "1000" );
properties.put( "hibernate.jdbc.fetch_size", "1000" );
properties.put( "hibernate.connection.autocommit", "false" );
properties.put( "hibernate.cache.use_second_level_cache", "false" );
properties.put("hibernate.cache.provider_class","org.hibernate.cache.NoCacheProvider");
properties.put( "hibernate.connection.CharSet", "utf8" );
properties.put( "hibernate.connection.characterEncoding", "utf8" );
properties.put( "hibernate.connection.useUnicode", "true" );
properties.put( "hibernate.enable_lazy_load_no_trans", "true" );

当我查询时,我的下一个hibernate统计信息:

09:45:08.694 [http-nio-8182-exec-4] INFO  o.h.e.i.StatisticalLoggingSessionEventListener - Session Metrics {
47217 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
444974 nanoseconds spent preparing 1 JDBC statements;
8947089681 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
8725 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 entities and 0 collections)

}

这个查询带我20SEC!从我的数据库中获取30k行(内部包含20个字段的普通Transaction对象列表)。我认为这太慢了。如何加快查询速度?

2 个答案:

答案 0 :(得分:1)

首先,我必须做出免责声明,Hibernate的性能取决于许多不同的因素,很难给出确切的答案。特别是没有实体模型。

但我可以提出一些建议并分享一些经验。

一旦我不得不优化一个Hibernate查询,它获取了1500个对象,并且需要6秒才能完成。

首先,我通过启用SQL日志记录来检查Hibernate实际运行的查询:

How to print a query string with parameter values when using Hibernate

日志由负载所有与提取对象相关的对象的查询负担。这是因为所有字段都是序列化的,包括相关对象的字段(这是一个报告)。

事实证明这是一个众所周知的情况(虽然不是我那个时候)称为“N + 1问题”。

这是关于这个主题的问题:

What is the solution for the N+1 issue in hibernate?

那里的答案为此提供了不同的解决方案。

我最终将该查询重写为带有连接的本机查询。新查询只用了0.01秒。当然,这种方法不会自动适用于所有情况。

所以,我建议(按顺序):

  1. 启用SQL查询记录
  2. 以某种方式处理N + 1(如果有的话)
  3. 配置数据库查询(即EXPLAIN等)

答案 1 :(得分:0)

您正在查询大约30000行... Hibernate库将实例化对象,加载数据,填充表中的数据并重复此过程30000次。如果每个对象加载0.0005秒,这将是正常时间。

我认为0.0005非常好,但如果您还需要,请阅读有关优化查询的this article