日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

mysql 大分页查询优化_Mysql骚操作:优化大分页查询

發(fā)布時(shí)間:2025/3/15 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 大分页查询优化_Mysql骚操作:优化大分页查询 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

背景

系統(tǒng)結(jié)構(gòu)如上圖。經(jīng)過排查是因?yàn)橄到y(tǒng)B拉取數(shù)據(jù)時(shí)間太長導(dǎo)致的推送超時(shí)。

系統(tǒng)B拉取數(shù)據(jù)的方法是根據(jù)_tiemstamp(數(shù)據(jù)操作時(shí)間)分頁查詢系統(tǒng)A的接口,即:

1SELECT?字段名2FROM?表名3WHERE?_timestamp?>=?beginTime?AND?_timestamp?<=?endTime?4LIMIT?n,?m;

由于該數(shù)據(jù)是從其他數(shù)據(jù)源中導(dǎo)入的,所以_timestamp這個(gè)字段值幾乎相同,這就導(dǎo)致了在我們的查詢范圍內(nèi)存在大約150萬的數(shù)據(jù)。一般遇到這種情況,首先想到的就是是否需要給_timestamp添加索引,這張表上是存在_timestamp索引的。那么為什么還會(huì)出現(xiàn)這個(gè)問題呢?這就要從分頁查詢本身說起了。

分頁查詢的性能瓶頸

B+樹簡述

首先我們要了解InnoDB存儲引擎中的B+數(shù)索引。這里我簡單總結(jié)一下:

上圖是一顆B+樹,通過觀察我們可以發(fā)現(xiàn)它的一些特點(diǎn):

1.每個(gè)節(jié)點(diǎn)中子節(jié)點(diǎn)個(gè)個(gè)數(shù)不能少于m/2個(gè),不能大于m個(gè)(B+樹是一顆m叉樹,圖中m=3)

2.根節(jié)點(diǎn)的節(jié)點(diǎn)個(gè)數(shù)可以超過m/2個(gè),這是一個(gè)例外

上述兩點(diǎn)特性是為了保證B+樹的查詢效率。

節(jié)點(diǎn)數(shù)超過m越多,在總節(jié)點(diǎn)數(shù)相同的情況下,樹的高度h就越小,此時(shí)m叉數(shù)就會(huì)向鏈表退化(O(logn)->O(n))。 ??節(jié)點(diǎn)數(shù)小于m/2越多,在總節(jié)點(diǎn)數(shù)相同的情況下,樹的高度h就越高,此時(shí)查詢數(shù)據(jù),就需要經(jīng)歷更多次的IO

3.m叉樹非葉子節(jié)點(diǎn)只存儲索引,不存儲數(shù)據(jù)

4.通過鏈表將葉子節(jié)點(diǎn)串聯(lián)在一起,這樣可以方便按區(qū)間查找。

B+比起二叉查找樹,有什么優(yōu)勢?

更矮,這就減少了IO次數(shù)。

由于非葉子節(jié)點(diǎn)不存儲數(shù)據(jù),上圖查詢?nèi)魏螖?shù)據(jù),都需要3次IO,查詢性能更穩(wěn)定

由于葉子節(jié)點(diǎn)使用了鏈表連接,范圍查詢更簡便。

分頁查詢過程

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

2.通過主鍵索引,定位到數(shù)據(jù)

3.不斷重復(fù)上述操作

4.根據(jù)分頁條件,確定返回?cái)?shù)據(jù)的啟始位置以及數(shù)據(jù)量

5.返回?cái)?shù)據(jù)

可以看出,初始位置值越大,定位時(shí)需要查詢的數(shù)據(jù)就越多,查詢效率也會(huì)越低

測試集

為了測試優(yōu)化效果,我準(zhǔn)備了150萬測試數(shù)據(jù)(需要跑幾分鐘)。

1# 建表語句

2CREATE TABLE `test`(

3 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',

4 `name` varchar(512) NOT NULL DEFAULT '無' COMMENT '創(chuàng)建人',

5 `_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',

6 PRIMARY KEY (`id`),

7 KEY `ix_timestamp` (`_timestamp`)

8) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='測試表';

9

10

11# 通過存儲過程導(dǎo)入數(shù)據(jù)

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();

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

可以看出,在使用索引的情況下,無論初始位置是0,還是145萬,Mysql都會(huì)掃描所有符合條件的數(shù)據(jù),然后找到初始位置的數(shù)據(jù),向后查偏移量個(gè)數(shù)據(jù),最后返回。

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

解決方法

針對于limit,有很多優(yōu)化的方法,比如前端加緩存、或者使用分頁加載的方式展示數(shù)據(jù)。(大部分用戶請求數(shù)據(jù)的初始開始都不會(huì)很大)。在我們的使用場景中,調(diào)大超時(shí)時(shí)間的閾值也是可以的。

但是回到問題本身,問題出現(xiàn)的原因就是分頁語句隨著初始位置的增加,會(huì)有性能問題,所以治本的辦法,是對這個(gè)語句進(jìn)行優(yōu)化,有兩個(gè)優(yōu)化方法:

1 延遲關(guān)聯(lián)法:

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

然后再通過主鍵索引查詢數(shù)據(jù),這就省去了遍歷數(shù)據(jù)找初始位置數(shù)據(jù)的過程

通過延遲關(guān)聯(lián)的方法,我們將10sec的耗時(shí)降低到了1.58sec,優(yōu)化了將近1個(gè)數(shù)量級。

2 主鍵閾值法

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

然后再根據(jù)閾值,取數(shù)據(jù)即可,同樣省去了遍歷數(shù)據(jù)找初始位置數(shù)據(jù)的過程

通過主鍵閾值法的方法,我們將10sec的耗時(shí)降低到了1.12sec,優(yōu)化了1個(gè)數(shù)量級

最后

最后對文章做一下補(bǔ)充說明:

1.文中優(yōu)化效果是僅憑借調(diào)用一次SQL的耗時(shí)給出的,并不科學(xué),僅僅是為了讓大家有一個(gè)直觀的概念。

2.無論是延遲關(guān)聯(lián)法,還是主鍵閾值法。思想都是一樣的,先把符合條件的主鍵找到,然后通過主鍵去定位符合條件的數(shù)據(jù),這里優(yōu)化了2個(gè)點(diǎn):1.通過索引覆蓋避免了回表;2.通過主鍵直接定位數(shù)據(jù)的方法,省去了在數(shù)據(jù)集中查詢初始位置的過程

3.優(yōu)化的效果隨數(shù)據(jù)量增加而增強(qiáng)。萬級別的數(shù)據(jù)優(yōu)化效果可能并不明顯。

總結(jié)

以上是生活随笔為你收集整理的mysql 大分页查询优化_Mysql骚操作:优化大分页查询的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。