Java猿社區—ShardingSphere之分組group by過多消耗內存的問題

Java猿社區—ShardingSphere之分組group by過多消耗內存的問題

ss的歸併引擎包括分組歸併,分組歸併的情況最爲複雜,它分爲流式分組歸併和內存分組歸併。 流式分組歸併要求SQL的排序項與分組項的字段以及排序類型(ASC或DESC)必須保持一致,否則只能通過內存歸併才能保證其數據的正確性。

舉例說明,假設根據科目分片,表結構中包含考生的姓名(爲了簡單起見,不考慮重名的情況)和分數。通過SQL獲取每位考生的總分,可通過如下SQL:

SELECT name, SUM(score) FROM t_score GROUP BY name ORDER BY name;

在分組項與排序項完全一致的情況下,取得的數據是連續的,分組所需的數據全數存在於各個數據結果集的當前遊標所指向的數據值,因此可以採用流式歸併。如下圖所示。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2MXroeUG-1584131626740)(evernotecid://6438F78B-FBEF-42D1-A152-F4935CA4BBB8/appyinxiangcom/15654258/ENResource/p11727)]
進行歸併時,邏輯與排序歸併類似。 下圖展現了進行next調用的時候,流式分組歸併是如何進行的。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-bZGklLLL-1584131626741)(evernotecid://6438F78B-FBEF-42D1-A152-F4935CA4BBB8/appyinxiangcom/15654258/ENResource/p11729)]
通過圖中我們可以看到,當進行第一次next調用時,排在隊列首位的t_score_java將會被彈出隊列,並且將分組值同爲“Jetty”的其他結果集中的數據一同彈出隊列。 在獲取了所有的姓名爲“Jetty”的同學的分數之後,進行累加操作,那麼,在第一次next調用結束後,取出的結果集是“Jetty”的分數總和。 與此同時,所有的數據結果集中的遊標都將下移至數據值“Jetty”的下一個不同的數據值,並且根據數據結果集當前遊標指向的值進行重排序。 因此,包含名字順着第二位的“John”的相關數據結果集則排在的隊列的前列。

流式分組歸併與排序歸併的區別僅僅在於兩點:

  • 它會一次性的將多個數據結果集中的分組項相同的數據全數取出。
  • 它需要根據聚合函數的類型進行聚合計算。

對於分組項與排序項不一致的情況,由於需要獲取分組的相關的數據值並非連續的,因此無法使用流式歸併,需要將所有的結果集數據加載至內存中進行分組和聚合。 例如,若通過以下SQL獲取每位考生的總分並按照分數從高至低排序:

SELECT name, SUM(score) FROM t_score GROUP BY name ORDER BY score DESC;

那麼各個數據結果集中取出的數據與排序歸併那張圖的上半部分的表結構的原始數據一致,是無法進行流式歸併的。

當SQL中只包含分組語句時,根據不同數據庫的實現,其排序的順序不一定與分組順序一致。 但由於排序語句的缺失,則表示此SQL並不在意排序順序。 因此,ShardingSphere通過SQL優化的改寫,自動增加與分組項一致的排序項,使其能夠從消耗內存的內存分組歸併方式轉化爲流式分組歸併方案

建議在開發時,使用group by語句時候,儘量排序項與分組項的字段以及排序類型保持一致。如果沒辦法保持,先預估下查詢的數據量可能佔用的內存大小和產品做好業務折衷,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章