Mysql騷操作 優化大分頁查詢

2021-10-04 10:34:06 字數 3456 閱讀 1424

系統結構如上圖。經過排查是因為系統b拉取資料時間太長導致的推送超時。

系統b拉取資料的方法是根據_tiemstamp(資料操作時間)分頁查詢系統a的介面,即:

1select 欄位名2from 表名3where _timestamp >= begintime and _timestamp <= endtime 4limit n, m;
由於該資料是從其他資料來源中匯入的,所以_timestamp這個字段值幾乎相同,這就導致了在我們的查詢範圍內存在大約150萬的資料。一般遇到這種情況,首先想到的就是是否需要給_timestamp新增索引,這張表上是存在_timestamp索引的。那麼為什麼還會出現這個問題呢?這就要從分頁查詢本身說起了。

b+樹簡述

首先我們要了解innodb儲存引擎中的b+數索引。這裡我簡單總結一下:

上圖是一顆b+樹,通過觀察我們可以發現它的一些特點:

1.每個節點中子節點個個數不能少於m/2個,不能大於m個(b+樹是一顆m叉樹,圖中m=3)

2.根節點的節點個數可以超過m/2個,這是乙個例外

上述兩點特性是為了保證b+樹的查詢效率。

節點數超過m越多,在總節點數相同的情況下,樹的高度h就越小,此時m叉數就會向鍊錶退化(o(logn)->o(n))。   節點數小於m/2越多,在總節點數相同的情況下,樹的高度h就越高,此時查詢資料,就需要經歷更多次的io

3.m叉樹非葉子節點只儲存索引,不儲存資料

4.通過鍊錶將葉子節點串聯在一起,這樣可以方便按區間查詢。

b+比起二叉查詢樹,有什麼優勢?

更矮,這就減少了io次數。

由於非葉子節點不儲存資料,上圖查詢任何資料,都需要3次io,查詢效能更穩定

由於葉子節點使用了鍊錶連線,範圍查詢更簡便。

分頁查詢過程

1.首先通過非主鍵索引查詢出所有條件的主鍵

2.通過主鍵索引,定位到資料

3.不斷重複上述操作

4.根據分頁條件,確定返回資料的啟始位置以及資料量

5.返回資料

可以看出,初始位置值越大,定位時需要查詢的資料就越多,查詢效率也會越低

為了測試優化效果,我準備了150萬測試資料(需要跑幾分鐘)。

1# 建表語句

2create table `test`(

3 `id` bigint(20) not null auto_increment comment '主鍵',

4 `name` varchar(512) not null default '無' comment '建立人',

5 `_timestamp` timestamp not null default current_timestamp on update current_timestamp comment '更新時間',

6 primary key (`id`),

7 key `ix_timestamp` (`_timestamp`)

8) engine=innodb default charset=utf8 comment='測試表';

91011# 通過儲存過程匯入資料

12drop procedure idata;

13delimiter ;;

14create procedure idata()

15begin

16 declare i int;

17 set i=1;

18 while(i<=1500000)do

19 insert into test values(i, i, now());

20 set i=i+1;

21 end while;

22end;;

23delimiter ;

2425call idata();

接著,我們看一下使用索引的情況下,分頁查詢語句的耗時情況。

可以看出,在使用索引的情況下,無論初始位置是0,還是145萬,mysql都會掃瞄所有符合條件的資料,然後找到初始位置的資料,向後查偏移量個資料,最後返回。

這兩條語句的執行速度差距非常大,大約3個數量級(0.00sec,10 sec)

針對於limit,有很多優化的方法,比如前端加快取、或者使用分頁載入的方式展示資料。(大部分使用者請求資料的初始開始都不會很大)。在我們的使用場景中,調大超時時間的閾值也是可以的。

但是回到問題本身,問題出現的原因就是分頁語句隨著初始位置的增加,會有效能問題,所以治本的辦法,是對這個語句進行優化,有兩個優化方法:

1 延遲關聯法:

我們先查詢出符合要求的主鍵(由於查詢的字段有索引,該索引的葉子節點就是主鍵,通過索引覆蓋我們可以省去一次回表操作。)

然後再通過主鍵索引查詢資料,這就省去了遍歷資料找初始位置資料的過程

通過延遲關聯的方法,我們將10sec的耗時降低到了1.58sec,優化了將近1個數量級。

2 主鍵閾值法

如果你的主鍵是自增的,那麼就可以通過條件推算出符合條件的主鍵最大值&最小值(這裡也是通過索引覆蓋省去了一次回表操作)

然後再根據閾值,取資料即可,同樣省去了遍歷資料找初始位置資料的過程

通過主鍵閾值法的方法,我們將10sec的耗時降低到了1.12sec,優化了1個數量級

最後對文章做一下補充說明:

1.文中優化效果是僅憑藉呼叫一次sql的耗時給出的,並不科學,僅僅是為了讓大家有乙個直觀的概念。

2.無論是延遲關聯法,還是主鍵閾值法。思想都是一樣的,先把符合條件的主鍵找到,然後通過主鍵去定位符合條件的資料,這裡優化了2個點:1.通過索引覆蓋避免了回表;2.通過主鍵直接定位資料的方法,省去了在資料集中查詢初始位置的過程

3.優化的效果隨資料量增加而增強。萬級別的資料優化效果可能並不明顯。

mysql騷操作 Mysql騷操作 優化大分頁查詢

系統結構如上圖。經過排查是因為系統b拉取資料時間太長導致的推送超時。系統b拉取資料的方法是根據 tiemstamp 資料操作時間 分頁查詢系統a的介面,即 1select?欄位名2from?表名3where?timestamp?begintime?and?timestamp?endtime?4lim...

MySQL優化教程之超大分頁查詢

基本上只要是做後台開發,都會接觸到分頁這個需求或者功能吧。基本上大家都是會用mysql的limit來處理,而且我現在負責的專案也是這樣寫的。但是一旦資料量起來了,其實limit的效率會極其的低,這一篇文章就來講一下limit子句優化的。很多業務場景都需要用到分頁這個功能,基本上都是用limit來實現...

mysql 分頁優化 Mysql 查詢分頁優化

全表掃瞄,速度極慢 limit 語句的查詢時間與起始記錄的位置成正比 mysql 的 limit 語句是很方便,但是對記錄很多的表並不適合直接使用 建立測試表 drop table if exists t user create table test t user id int 10 unsigne...