博客 / 詳情

返回

mysql 大數據表的分頁性能優化

最近的工作中實現了一個定時統計功能:需要按指定順序,從源表中取出數據,經過分組合並,插入目標表。

源表數據量相當大,有幾千萬行,顯然不適合一次性取出(如果是一次性的腳本,在大內存的機器上也是可以考慮的,但定時任務每次啓動都佔用數十GB內存就太誇張了),需要分頁查詢。

但最初的實現中,採用了一個封裝好的分頁庫,單純的全表查詢,純粹依賴limit子句限制結果集窗口,構成的SQL語句類似這樣:

select * from A order by x, y limit 30000, 10000

其中字段 x 和字段 y 是有聯合索引的,每頁返回 10000 條。

結果慘不忍睹,每頁查詢需要40秒才能返回,而這樣的查詢需要循環幾千次,整整半天時間都沒執行完。


解決方案也很簡單,使用自定義的分頁機制,基於字段 x 篩選實現分頁:

select * from A where x > 30000 order by x, y limit 10000
注意:這裏的 30000,只是示例,每次要把上一頁最後一條的 x 值記下來,當做下一頁"x > ?" 的判斷條件。

python + sqlalchemy 的代碼示例如下:

PAGE_SIZE = 10000

last_x = 0    # 這裏假設 x 永遠是大於零的整數,如果不是,初始化一個最小值
while last_x == 0 or len(records > 0):
    # last_x == 0 這個條件,相當於判斷是否第一次循環,這裏其實有 do...while 語句更好,可惜 python 沒有
    records = A.query.filter(A.x > last_x).order_by(A.x, A.y).limit(PAGE_SIZE)
    last_x = records[-1].x
    # do something
    
user avatar sankuaiqian_64e9ce57c9457 頭像 u_17578255 頭像 loading_672b22021e446 頭像 u_16213614 頭像 u_16213562 頭像 u_16213582 頭像
6 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.