2017-01-30 37 views
2

我們目前正在研究加快我們的應用程序的方法,其中很大一部分與實體列表(實際上是一個表)有關。休眠分頁的數據加入分頁

參數和要求

該列表中的參數和要求如下(我將在這裏只提及相關的):

  • 最多可以有50萬行/列表中的實體。
  • 一次只顯示其中的幾個,我們將在這裏使用分頁。
  • 用戶可以選擇要在列表中顯示哪些列(因此我們無法提供單個「靜態」查詢)。
  • 大多數列表列都是可排序和/或可過濾的。
  • 實體有一對多關係,它們也提供了一些列表列。
  • 其中一些列表中的列可以包含多個值(這些被顯示爲列表中的單個細胞內)
  • 從當前用戶的行爲始發的數據的任何更新(例如編輯,上傳等)應在被反射名單越好(即「immeditately」)

快,使模型更清楚一點考慮以下簡化實體(如JPA)模型:

class Car { 
    String manufacturer; 
    String model; 
    Date dateOfProduction; 
    List<TyreSize> allowedTyreSizes; 
    Set<Date> inspectionDates; 
} 

請不要嘗試因爲它是ju,所以對這個模型有着太多的意義st意在說明問題(我們的數據是不同的,而且更復雜)。然後

「完整的」汽車名單看起來是這樣的:

+==============+=======+=======+===============+=============+ 
| Manufacturer | Model | Prod. | Allowed Tyres | Inspections | 
+==============+=======+=======+===============+=============+ 
| BMW   | 320d |01/2016| - 225/40 R18 | - 01/07/16 | 
|    |  |  | - 225/45 R17 | - 13/12/16 | 
+--------------+-------+-------+---------------+-------------+ 
| Toyota  | Camry |09/2016| - 185/70 R13 | - 31/12/16 | 
+--------------+-------+-------+---------------+-------------+ 

由於用戶可以選擇在運行時顯示的列我們動態地建立必要的查詢。到目前爲止,這一切都工作得很好。

基本問題

排序和過濾時參與我們遇到的問題是性能:我們目前的做法是裝載必需的排序和篩選到內存中的所有數據,做分類和過濾那裏,然後保留這些已排序的ID和頁面的列表。我們知道這有點慢,但迄今爲止表現足以滿足我們的管理。事情發生了變化,因爲我們現在有更多的數據可以操作,性能要求也提高了。

因此,我們正在研究如何改善所有的數據ADN的排序和篩選,而我們目前正在下面做對數據庫的方法,我還是會問這個(邊)問題:

  • 如何最好地接近具有動態列的大量行以及每個單元可能具有多個值的分頁?

目前我們正在使用Postgresql,並希望儘可能繼續使用它,但如果不同的存儲更適合,我們至少會檢查出來。

目前的做法和問題(S)(底部)

正如上文所述,我們目前正在試圖讓數據庫排序,過濾和分頁我們的數據。可以使用2個查詢:一個用於獲取當前頁面的行標識,另一個用於實際加載這些行的數據。

由於面臨的挑戰是,我會集中在第一查詢:

據我所知,我們可以做在SQL這樣的事情(使用上面的車爲例):

SELECT DISTINCT id FROM (
    SELECT id, ... FROM car c 
    LEFT OUTER JOIN allowedtyresizes ats ON c.id = ats.car_id 
    LEFT OUTER JOIN tyresizes ts ON ts.id = ats.tyresize_id 
    ... //additional joins if required 
    ORDER BY ... //apply any user-defined sorts 
    WHERE ... //apply any user-defined filters (or maybe put them into the joins) 
) 
    OFFSET ... //page offset 
    LIMIT ... //page size 

從理論上講這個查詢(它可能不完全正確)應該提供我們需要的結果以確定爲當前頁面加載哪些行。

由於我們使用Hibernate(5.2 atm),我們希望使用HQL或Criteria來實現這一點。但是,好像Hibernate不支持從上面的select語句中選擇,因此這可能不是一個可行的方法。如果我們不得不退回到原生SQL或完全不同的方法,那麼我們寧願讓它適用於當前的基礎架構。

所以問題是:

  • 不休眠5.x的支持,有點像「從選擇中選擇」?
  • 當對多對多關係進行排序和過濾時,如何在單個連接可能導致重複行時使用Hibernate進行分頁?
+0

你運行SQL查詢使用HQL通過傳遞你的查詢到字符串 –

+0

@GauravSrivastav是的,我們知道如何執行SQL查詢,如果沒有更好的方法,我們將使用它。但是,由於查詢可能變得相當複雜並且動態創建,我們寧願不必訪問實體的映射信息來提取構建此類查詢所需的信息 - 而不是如果Hibernate已經提供了我們可以使用的東西。 – Thomas

+0

你的模型有多複雜?通過使用數據庫視圖並將實體與它們綁定,您可能會獲得最佳性能。壞處是你需要手寫數據庫視圖(如果你開始支持新的RDBMS,可能還需要另一個版本)。好的是,實體會變得更簡單,而Hibernate生成性能較差的SQL的機會會更少。 –

回答

2

我在過去的僱主中有過類似的要求,我們也注意到類似的情況是,在較小的數據集中,數據庫能夠做到這一點;然而,即使數據庫會受到影響,也會有一個臨界點。

我的解決方案是引入Hibernate Search並將其與ElasticSearch集成,以便將搜索數據存儲在NoSQL Lucene數據存儲中,這對於基於Unicode的文本查詢和排序來說絕對快速,正如您所描述的。

這使您可以繼續使用已有的Hibernate ORM基礎架構,並以最小的努力將這些附加組件燒入您的架構。整合是無縫的,當然值得投資,尤其是隨着數據集的持續增長。

我們正在處理數以百萬計的行,並且完全沒有性能問題。排序和分頁的查詢平均少於100毫秒。

+0

Thx的信息。我們實際上已經使用Hibernate Search,而直接使用Lucence而不是Elastic。 Elastic會提高性能嗎?或者只是簡化訪問數據?你如何處理更新 - 你是否更新了整個更改過的文檔,或者只更新了哪些字段(如果可能的話)?我也猜測這些更新是異步處理的,不是嗎? – Thomas

+1

我發現使用ES更容易,因爲索引託管在更多的微服務體系結構中,而不是將Lucene直接嵌入到應用程序中。我們在主/從之間也有索引複製的問題,導致我們改用ES。至於更新,他們被複制到ES,就像他們今天覆制到Lucene一樣。我相信這些更新不是異步的,而是在Hibernate引發Search偵聽的各種事件時發生。 – Naros

+0

Afaik Hibernate Search在事務結束時觸發更新,所以是的,默認情況下它們基本上是同步的。儘管(在另一個項目中),我們遇到了一些問題,當大事務需要我們暫時清除第一級緩存時,這會導致HS在分離的實體上窒息。因此,我們在那裏引入了一些異步更新,因此我的問題(如果ES/Lucene不可用,異步更新也會降低事務回滾的風險)。 – Thomas