簡體   English   中英

Spring JPA Hibernate:緩慢的SELECT查詢

[英]Spring JPA Hibernate : slow SELECT query

我遇到優化問題,無法弄清楚為什么查詢這么慢。

這是我的實體:

@Entity
@Table(name = "CLIENT")
public class Client {

private static final long serialVersionUID = 1L;
@Id
@Column(name = "CLIENT_ID")
@SequenceGenerator(name = "ID_GENERATOR", sequenceName = "CLIENT_S", allocationSize = 1, initialValue = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ID_GENERATOR")
private Long id;

@Column(name="LOGIN")
private String login;

@Column(name="PASSWORD")
private String password;

還有DAO

@NoRepositoryBean
public interface ClientDao extends JpaRepository<Client, Long>, JpaSpecificationExecutor<Client> {
    Client findByPasswordAndLogin(@Param("login") String customerLogin,@Param("password") String customerHashedPassword);
}

執行findByPasswordAndLogin方法時,大約需要200毫秒才能完成(通過Junit測試和JProfiler均可看到)。

在這里,Hibernate查詢:休眠:從CLIENT clientx0_中選擇clientx0_.CLIENT_ID作為CLIENT_ID1_4_,clientx0_.LOGIN作為LOGIN9_4_,clientx0_.PASSWORD作為PASSWORD10_4_,clientx0_.STATUT作為STATUT13_4_,其中clientx0_.PASSWORD =? 和clientx0_.LOGIN =?

當我在數據庫上手動執行SQL查詢時,只需要3毫秒:

select * from CLIENT where PASSWORD='xxxxx' and LOGIN='yyyyyyyy'

在我們的開發環境中,我們有4000個客戶。 年生產量超過一百萬。

這里的上下文:

  • JDK 8
  • Spring 4.1.6.RELEASE + JPA + Hibernate
  • Oracle數據庫10

任何想法 ?

我已經測試了不同類型的DAO(因為它太臟了,所以我不在這里發布代碼):

  • 使用休眠模式 :〜200ms
  • 使用(注入的)Spring JDBCTemplate和RowMapper〜70毫秒
  • 使用Java語句 :〜2毫秒
  • 使用Java OracleStatement〜5毫秒
  • 使用Java PreparedStatement :〜100ms
  • 通過將Java PreparedStatement調整為Fetch大小= 5000 :〜50ms
  • 使用Java OraclePreparedStatement〜100ms
  • 使用Java OraclePreparedStatement並通過PreFetch大小 = 5000 調整 :〜170ms

注意事項:

  • Spring注入的DAO而不是新的ClientDao() :+ 30ms丟失​​(-sick-)
  • 與DB的連接時間:46ms

我可以使用:

  • 帶有手動清除字段的Java語句。
  • 啟動應用程序時進行預連接
  • 不要使用彈簧注射

但是:

  • 不是很安全
  • 快速處理少量行,慢速將ResultSet映射到大量行上的實體(我也有這種用例)

因此:

帶有RowMapperSpring JDBCTemplate似乎是提高特定情況下性能的最佳解決方案。 而且我們可以保證SQL查詢的安全性。 但是需要編寫特定的RowMapper才能將ResultSet轉換為Entity。

Spring JDBCTemplate的示例

@Repository
public class ClientJdbcTemplateDao {


    private final Logger logger = LoggerFactory.getLogger(ClientJdbcTemplateDao.class);

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public List<Client> find() {
        List<Client> c = this.jdbcTemplate.query( "SELECT login FROM Client WHERE LOGIN='xxxx' AND PASSWORD='xxx'", new ClientRowMapper());
        return c;
    }
}

客戶端RowMapper的示例

public class ClientRowMapper implements RowMapper<Client> {

    @Override
    public Client mapRow(ResultSet arg0, int arg1) throws SQLException {
        // HERE IMPLEMENTS THE CONVERTER
        // Sample : 
        // String login = arg0.getString("LOGIN")
        // Client client = new Client(login);
        // return client;
    }
}

也許可以更好,任何建議都是值得歡迎的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM