系統結構如上圖。通過排查是由於系統B拉取數據時間太長致使的推送超時。
系統B拉取數據的方法是根據_tiemstamp(數據操做時間)分頁查詢系統A的接口,即:前端
1SELECT 字段名2FROM 表名3WHERE _timestamp >= beginTime AND _timestamp <= endTime 4LIMIT n, m;
因爲該數據是從其餘數據源中導入的,因此_timestamp這個字段值幾乎相同,這就致使了在咱們的查詢範圍內存在大約150萬的數據。通常遇到這種狀況,首先想到的就是是否須要給_timestamp添加索引,這張表上是存在_timestamp索引的。那麼爲何還會出現這個問題呢?這就要從分頁查詢自己提及了。sql
首先咱們要了解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.經過鏈表將葉子節點串聯在一塊兒,這樣能夠方便按區間查找。ide
更矮,這就減小了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='測試表'; 9 10 11# 經過存儲過程導入數據 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 ; 24 25call idata();
接着,咱們看一下使用索引的狀況下,分頁查詢語句的耗時狀況。3d
能夠看出,在使用索引的狀況下,不管初始位置是0,仍是145萬,Mysql都會掃描全部符合條件的數據,而後找到初始位置的數據,向後查偏移量個數據,最後返回。code
這兩條語句的執行速度差距很是大,大約3個數量級(0.00sec,10 sec)blog
針對於limit,有不少優化的方法,好比前端加緩存、或者使用分頁加載的方式展現數據。(大部分用戶請求數據的初始開始都不會很大)。在咱們的使用場景中,調大超時時間的閾值也是能夠的。
可是回到問題自己,問題出現的緣由就是分頁語句隨着初始位置的增長,會有性能問題,因此治本的辦法,是對這個語句進行優化,有兩個優化方法:
咱們先查詢出符合要求的主鍵(因爲查詢的字段有索引,該索引的葉子節點就是主鍵,經過索引覆蓋咱們能夠省去一次回表操做。)
而後再經過主鍵索引查詢數據,這就省去了遍歷數據找初始位置數據的過程
經過延遲關聯的方法,咱們將10sec的耗時下降到了1.58sec,優化了將近1個數量級。
若是你的主鍵是自增的,那麼就能夠經過條件推算出符合條件的主鍵最大值&最小值(這裏也是經過索引覆蓋省去了一次回表操做)
而後再根據閾值,取數據便可,一樣省去了遍歷數據找初始位置數據的過程
經過主鍵閾值法的方法,咱們將10sec的耗時下降到了1.12sec,優化了1個數量級
最後對文章作一下補充說明:
1.文中優化效果是僅憑藉調用一次SQL的耗時給出的,並不科學,僅僅是爲了讓你們有一個直觀的概念。
2.不管是延遲關聯法,仍是主鍵閾值法。思想都是同樣的,先把符合條件的主鍵找到,而後經過主鍵去定位符合條件的數據,這裏優化了2個點:1.經過索引覆蓋避免了回表;2.經過主鍵直接定位數據的方法,省去了在數據集中查詢初始位置的過程 3.優化的效果隨數據量增長而加強。萬級別的數據優化效果可能並不明顯。