Oracle資料庫與JPA和Hibernate 結合使用時的九個高效能技巧 - vladmihalcea

banq發表於2021-06-24

在本文中,我將向您展示 9 個技巧,它們將幫助您在使用 JPA 和 Hibernate 時加快 Oracle 資料庫應用程式的速度。
為了充分利用正在使用的關聯式資料庫,您需要確保資料訪問層與底層資料庫系統產生共鳴,因此,在本文中,我將向您展示一些可以提高效能的技巧您的 Oracle、JPA 和 Hibernate 應用程式。
 

1. 配置緩衝池和作業系統快取
與任何關聯式資料庫系統一樣,Oracle 旨在儘可能減少磁碟訪問。
當需要一個頁面時,Oracle 會檢查緩衝池以檢視該頁面是否可以從快取中解析。這是一個合乎邏輯的閱讀。如果沒有快取頁面,Oracle 會從磁碟載入它並將其儲存在緩衝池中。那是物理閱讀。這樣,下次您請求相同的頁面時,它將從快取而不是從資料庫載入。
傳統上,資料庫系統使用兩個日誌來標記事務修改:

  • 在撤消日誌用於在回退的情況下恢復未提交的更改。在 Oracle 中,撤消日誌儲存最新未提交的元組與之前狀態之間的差異。
  • 在redo_log保證事務的永續性,並且由於緩衝池每一筆交易修改儲存每一筆交易執行後,不重新整理到磁碟。因此,出於這個原因,緩衝池會在檢查點期間定期重新整理。

由於基於 Unix 的作業系統有自己的頁面快取,因此使用 Direct I/O(例如,O_DIRECT)堆積資料和索引分割槽以避免在作業系統快取和緩衝池中儲存相同的頁面非常重要。
 

2. 瞭解所有支援的 SQL 特性
Oracle 支援許多 SQL:2016 標準特性,例如Window Functions、CTE、Recursive CTE、PIVOTMERGE,甚至MATCH_RECOGNIZE是隻有 Oracle 才新增支援的子句。
除了這些 SQL 標準特性之外,Oracle 還提供了特定於資料庫的特性,例如 MODEL 子句。
Oracle 還提供特定於資料庫的功能,例如 MODEL 子句或閃回查詢
因此,如果您將資料訪問查詢限制為您在大學或W3 Schools 中學到的SQL:92 功能列表,您將錯過許多可以幫助您解決非常複雜的資料訪問需求的功能。
閱讀Oracle 文件並熟悉它提供的所有功能非常重要。
而且,僅僅因為您使用 JPA 和 Hibernate,並不意味著您應該只編寫 JPQL 和Criteria API查詢。JPAEntityManager允許您執行本機 SQL 查詢是有充分理由的,因為任何重要的資料庫應用程式都需要執行本機 SQL。
 

3.最佳化執行計劃快取
與 PostgreSQL 和 MySQL 不同,Oracle 提供了一個執行計劃快取,可以讓您加快 SQL 查詢的執行速度。
執行計劃快取甚至可以為給定的查詢儲存多個計劃,以匹配具有非常傾斜的資料分佈的各種繫結引數值。
瞭解執行計劃快取的工作原理後,您應該配置資料訪問層以利用這一非常有用的功能。因此,您應該:


 

4.開啟JDBC語句快取機制
Oracle JDBC Driver 提供了預設禁用的語句快取機制。因此,為了加快 SQL 查詢速度,您應該透過將oracle.jdbc.implicitStatementCacheSize屬性設定為正整數值來啟用它。
您可以透過JDBC URL 連線字串以宣告方式執行此操作:

jdbc:oracle:thin:@tcp://hpjp:1521/training? oracle.jdbc.implicitStatementCacheSize=100

或者,以程式設計方式,透過 JDBCDataSource屬性:

OracleDataSource dataSource = new OracleDataSource();
dataSource.setDatabaseName("high_performance_java_persistence");
dataSource.setURL(url());
dataSource.setUser(username());
dataSource.setPassword(password());
 
Properties properties = new Properties();
properties.put(
    "oracle.jdbc.implicitStatementCacheSize",
    Integer.toString(cacheSize)
);
dataSource.setConnectionProperties(properties);


 

5.增加預設的JDBC語句fetch大小
與PostgreSQL 和 MySQL預取整個JDBC 的ResultSet 不同,Oracle 使用的提取大小僅為10. 因此,返回50記錄的查詢需要5次資料庫往返以從資料庫 Executor 中獲取所有資料。
因此,在使用 Oracle 時,您應該始終增加預設提取大小。如果您使用的是 Hibernate,您可以透過hibernate.jdbc.fetch_size配置屬性將此更改全域性應用於所有 SQL 語句。
例如,如果您正在使用 Spring Boot,則可以在application.properties配置檔案中設定此屬性,如下所示:

spring.jpa.properties.hibernate.jdbc.fetch_size=100

而且,如果您使用資料庫遊標來獲取Java 8Stream,那麼您始終可以使用org.hibernate.fetchSizeJPA 查詢提示將提取大小設定為較低的值:

Stream<Post> postStream = entityManager.createQuery("""
    select p
    from Post p
    order by p.createdOn desc
    """, Post.class)
.setHint(QueryHints.HINT_FETCH_SIZE, 10)
.getResultStream();

 

6.啟用自動JDBC批處理
對於寫入資料,JDBC 語句批處理可以幫助您減少事務響應時間。使用 Hibernate 時,啟用批處理只是設定一些配置屬性的問題
因此,您應該始終在 Spring Bootapplication.properties配置檔案中設定以下 Hibernate 設定:

spring.jpa.properties.hibernate.jdbc.batch_size=10
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true

如果您使用的是樂觀鎖定並且您至少沒有使用 Oracle 12c,那麼您應該嘗試將 JDBC 驅動程式升級到至少 12c 版本,因為 JDBC 驅動程式向後和向前相容,並設定以下配置屬性:

spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true

 

7. 優先SEQUENCE而不是IDENTITY
Oracle 12c 新增了對 IDENTITY 列的支援。但是,您應該使用SEQUENCE識別符號生成器來自動增加主鍵,因為這將允許 Hibernate 對 INSERT 語句使用自動批處理。
 

8. 對映 JPA 實體時使用 Hibernate @RowId
使用 Oracle 時,您可以使用Hibernate的@RowId來註釋 JPA 實體,以便 UPDATE 語句可以透過其 ROWID 而不是主鍵值來定位記錄。
 

9. 將非結構化資料儲存在 JSON 列型別中
在關聯式資料庫中,最好按照關係模型的原則來儲存資料。
但是,您可能還需要儲存非結構化資料,在這種情況下,JSON 列可以幫助您處理此類需求。
而 Oracle 21c 將新增一個JSON列型別:

CREATE TABLE book (
  id NUMBER(19, 0) NOT NULL PRIMARY KEY,
  isbn VARCHAR2(15 CHAR),
  properties JSON
)

如果你使用的是Oracle 19C,18C,12C或者,你可以儲存JSON物件VARCHAR2,BLOB或CLOB列型別。建議儲存小型 JSON 物件,以便它們可以放在一 VARCHAR2(4000)列中,從而適合緩衝池頁面。
建立表時,您可以使用 CHECK 約束驗證儲存的 JSON 物件:

CREATE TABLE book (
  id NUMBER(19, 0) NOT NULL PRIMARY KEY,
  isbn VARCHAR2(15 CHAR),
  properties VARCHAR2(4000)
  CONSTRAINT ENSURE_JSON CHECK (properties IS JSON)
)


要索引具有高select的 JSON 屬性,您可以使用 B+Tree 索引:

CREATE INDEX book_properties_title_idx
ON book b (b.properties.title)


要索引具有低select的 JSON 屬性,例如布林值或列舉值,您可以使用BITMAP索引:

CREATE BITMAP INDEX book_properties_reviews_idx
ON book (JSON_EXISTS(properties,'$.reviews'))


您還可以為JSON 列使用通用SEARCH索引,這將允許您匹配鍵/值 JSON 屬性資料:

CREATE SEARCH INDEX book_search_properties_idx
ON book (properties) FOR JSON



 

相關文章