簡體   English   中英

使用 Hibernate/Oracle 的 ScrollableResults 將所有內容拉入內存

[英]ScrollableResults with Hibernate/Oracle pulling everything into memory

我想要一頁來自 Oracle 數據庫表的過濾數據,但我有一個可能返回數千萬條記錄的查詢,因此將其全部拉入內存是不可行的。 我需要以一種無法通過 SQL 完成的方式過濾記錄,並返回一頁記錄。 換句話說,分頁部分必須在過濾之后完成。

因此,我嘗試使用 Hibernate 的ScrollableResults ,認為這將是一種一次只提取塊並遍歷它們的方法。 所以,我創建了它:

ScrollableResults results = query.setReadOnly(true)
    .setFetchSize(500)
    .setCacheable(false)
    .scroll();

...然而,它似乎將所有內容都拉入內存(每個查詢拉入 2.5GB)。 我已經看到另一個問題,我已經嘗試了一些建議,但大多數似乎是特定於 MySQL 的,並且我使用的是 Oracle 19 驅動程序(例如Integer.MIN_VALUE被完全拒絕作為 Oracle 驅動程序中的提取大小)。

有人建議使用無狀態會話(我使用的是沒有無狀態選項的EntityManager ),但我的想法是,如果我們不獲取很多記錄(因為我們只想要 200 條過濾記錄的第一頁),為什么 Hibernate 會在內存中存儲數百萬條記錄,即使我們從未滾動過它們?

我很清楚,我不明白 Hibernate 如何/為什么將事情拉入內存,或者如何讓它停止這樣做。 鑒於上述限制,有關如何防止它這樣做的任何建議?

我要嘗試的一些事情:

  • 不同的滾動模式。 也許不敏感或前進只會阻止 Hibernate 需要將所有東西都拉進來?
  • 在我們擁有頁面后清除會話。 我正在關閉會話(在ScrollableResultsEntityManager都使用close() ),但也許明確的clear()會有所幫助?

我們滾動整個ScrollableResults以獲得總數。 這導致了兩件事:

  1. Hibernate 會話緩存實體。
  2. 驅動程序中的ResultSet保留了它滾動過去的行。

解決這個問題確實針對我的情況,但我做了兩件事:

  1. 當我們滾動時,定期清除 Hibernate 會話。 由於我們使用EntityManager ,我必須執行entityManager.unwrap(Session.class).clear() 不確定entityManager.clear()是否會完成這項工作。
  2. 使ScrollableResults僅向前,以便 Oracle 驅動程序在ScrollableResults不必在內存中保留記錄。 這就像執行.scroll(ScrollMode.FORWARD_ONLY)一樣簡單。 不過,這只是可能,因為我們只是在向前邁進。

這使我們能夠保持較小的內存占用,即使在滾動瀏覽每條記錄(數千萬條)時也是如此。

為什么要滾動瀏覽所有結果只是為了得到計數? 為什么不直接執行計數查詢?

暫無
暫無

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

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