簡體   English   中英

微服務架構和MySQL數據庫分頁

[英]Microservices architecture and MySQL database pagination

想象一下,我想檢索一系列客戶的所有訂單。 下面的示例中的arrayList將具有一個客戶ID數組。

該數組將傳遞到下面的get方法中,並異步處理以獲取數組中每個客戶ID的訂單。

這是我迷路的地方。 如何分頁數據庫結果集並一次僅從數據庫中提取一小部分記錄,而不必通過網絡提取所有記錄。

讓我感到困惑的是異步特性,以及我們不知道每個客戶有多少個訂單? 那么如何一次有效地返回設置的頁面大小呢?

service.js

function callToAnotherService(id) {
    return new Promise((resolve, reject) => {
        //calls service passing id
    }
}

exports.get = arrayList => Promise.all(arrayList.map(callToAnotherService))
    .then((result) => result);

在MySQL中,有多種方法可以實現此目的。

您選擇的方法取決於許多變量,例如您的實際分頁方法(您是否只想擁有“上一個”和“下一個”按鈕,或者實際上是要提供1 ... n的范圍,其中n是匹配的總數記錄除以您的每頁記錄數); 以及數據庫設計,計划的增長,分區和/或分片,當前和預測的數據庫負載,可能的硬查詢限制(例如,如果您有多年的記錄價值,則可能需要最終用戶為查詢選擇一個合理的時間范圍(上個月,過去3個月,去年等等),這樣它們就不會因無限制和過於廣泛的查詢而使數據庫超載。


要分頁:

  • 使用簡單的上一個下一個按鈕,可以使用簡單的LIMIT [ START_AT_RECORD ,] NUMBER_OF_RECORDS 方法 ,如上面的Rick James所建議的。
  • 使用(所有)頁碼,您需要知道匹配記錄的數量,因此,根據頁面大小,您將知道總共有多少頁。
  • 結合使用上述兩種方法。 例如,您可以顯示一些可點擊的頁碼(例如,上一個/下一個5),以及第一個最后一個鏈接/按鈕。

如果選擇最后兩個選項之一,則肯定需要知道找到的記錄的總數。

就像我在上面說的,實現同一目標有多種方法。 必須根據情況進行選擇。 下面我將描述一些簡單的想法:

  • 第一:
    如果您的解決方案是基於會話的,並且您可以保留該會話,則可以使用一個臨時表,在該表中 ,您只能選擇order_id (假設它是orders表中的主鍵)。 (可選)如果要獲取每個客戶的計數(或以其他方式過濾),還可以將第二列添加為orders表中order_id旁邊的customer_id

    一旦用最少的數據傳播了臨時表,就可以輕松地計算臨時表中的行並基於該數字創建分頁。 現在,當你開始顯示頁面,你只能選擇這些行(使用上述極限法)的子集,並加入從臨時表的order_id 訂單的相應記錄(列的其余部分)。

    這有兩個好處:
    1)逐頁瀏覽記錄會很快,因為它不再查詢(大概)大訂單表。
    2)您沒有在訂單表上使用聚合查詢,這取決於記錄的數量和設計,這些查詢的性能會非常差,並可能影響其他並發用戶的性能。

    請記住,最初的臨時表創建會稍微慢一些。 但是,如果不將臨時表限制為僅基本列,則肯定會更加慢。
    不過,還是建議您為初始查詢設置一個合理的最大硬限制(臨時表記錄數或某個時間范圍)

  • 第二:這是我的最愛,因為使用這種方法,我已經能夠多次解決客戶的大型數據庫(或特定查詢)性能問題。 我們正在談論將查詢時間從50-55秒降低到毫秒。 此方法尤其不受數據庫可伸縮性下降的影響。

    主要思想是您可以預先計算所有種類的匯總(例如產品的累計總和或每個客戶的訂單數等)。 為此,您可以創建一個附加表來保存匯總(示例中每個客戶的訂單數)。

    現在是最重要的部分:
    必須使用自定義數據庫觸發器 ,即您可以使用ON INSERTON DELETE觸發器,這將更新聚合表並增加/減少特定客戶的訂單數,具體取決於是否添加/刪除了訂單。 觸發器可以在更改觸發表之前或之后觸發,具體取決於您如何設置它們。
    觸發器實際上對數據庫沒有任何開銷,因為它們對每個(插入/刪除)的記錄僅觸發一次(除非您做一些愚蠢的操作,例如從某個大表運行COUNT(...)查詢,否則將完全達不到目的無論如何)

    我通常會更細化,例如每個客戶每月的計數/總和,等等。

    正確完成后,合計計數幾乎不可能與實際記錄不同步。 如果您的應用程序啟用了訂單的customer_id更改,則可能還需要添加ON UPDATE觸發器,因此訂單的客戶ID更改將自動反映在聚合表中。

    當然,您可以使用更多方法。 但是上面的這兩個事實證明非常棒。 這完全取決於情況...

    我希望我的回答有點抽象,可以引導您走上正確的道路,因為我只能根據您提出的問題的少量信息來回答...

在MySQL中,使用ORDER BY ... LIMIT 30, 10跳過30行並獲取10。

最好還記得您離開的地方(假設$ left_off),然后執行

WHERE id > $left_off
ORDER BY id
LIMIT 10

您抓取的最后一行是新的“ left_off”。

更好的是,但使用LIMIT 11 然后,您可以顯示10,但還可以發現是否還有更多(通過從SELECT返回第11行來實現)。

暫無
暫無

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

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