日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

MySql深分頁問題解決

瀏覽:365日期:2023-02-18 16:43:11
目錄
  • 1. 問題描述
  • 2. 問題分析
  • 3. 驗證測試
    • 3.1 創(chuàng)建兩個表
    • 3.2 創(chuàng)建兩個函數(shù)
    • 3.3 編寫存儲過程
    • 3.4 編寫存儲過程
    • 3.5 創(chuàng)建索引
    • 3.6 驗證測試
  • 4. 解決方案
    • 4.1 使用索引覆蓋+子查詢優(yōu)化
    • 4.2 起始位置重定義
    • 4.3 降級策略
  • 5. 梳理總結

    1. 問題描述

    日常開發(fā)中經(jīng)常會涉及到數(shù)據(jù)查詢分頁的問題,一般情況下都是根據(jù)前端傳入頁數(shù)與頁碼通過mysql的limit方式實現(xiàn)分頁,對于數(shù)據(jù)量較小的情況下沒有問題,但是如果數(shù)據(jù)量很大,深分頁可能導致查詢效率低下,接口超時的情況。

    2. 問題分析

    其實對于我們的 MySQL 查詢語句來說,整體效率還是可以的,該有的聯(lián)表查詢優(yōu)化都有,該簡略的查詢內(nèi)容也有,關鍵條件字段和排序字段該有的索引也都在,問題在于他一頁一頁的分頁去查詢,查到越后面的頁數(shù),掃描到的數(shù)據(jù)越多,也就越慢。

    我們在查看前幾頁的時候,發(fā)現(xiàn)速度非常快,比如 limit 200,25,瞬間就出來了。但是越往后,速度就越慢,特別是百萬條之后,卡到不行,那這個是什么原理呢。先看一下我們翻頁翻到后面時,查詢的 sql 是怎樣的:

    select * from t_name where c_name1="xxx" order by c_name2 limit 2000000,25;
    

    這種查詢的慢,其實是因為 limit 后面的偏移量太大導致的。
    比如像上面的 limit 2000000,25,這個等同于數(shù)據(jù)庫要掃描出 2000025 條數(shù)據(jù),然后再丟棄前面的 20000000 條數(shù)據(jù),返回剩下 25 條數(shù)據(jù)給用戶,這種取法明顯不合理。

    3. 驗證測試

    3.1 創(chuàng)建兩個表

    -- 創(chuàng)建兩個表:員工表和部門表
    -- 部門表,存在則進行刪除
    drop table if EXISTS dep;
    create table dep(
    ? ? id int unsigned primary key auto_increment,
    ? ? depno mediumint unsigned not null default 0,
    ? ? depname varchar(20) not null default "",
    ? ? memo varchar(200) not null default ""
    );
    
    -- 員工表,存在則進行刪除
    drop table if EXISTS emp;
    create table emp(
    ? ? id int unsigned primary key auto_increment,
    ? ? empno mediumint unsigned not null default 0,
    ? ? empname varchar(20) not null default "",
    ? ? job varchar(9) not null default "",
    ? ? mgr mediumint unsigned not null default 0,
    ? ? hiredate datetime not null,
    ? ? sal decimal(7,2) not null,
    ? ? comn decimal(7,2) not null,
    ? ? depno mediumint unsigned not null default 0
    );

    注意說明

    • mediumint是MySQL數(shù)據(jù)庫中的一種整型,比INT小,比SMALLINT大,
    • 取值范圍為:-8388608到8388607,無符號的范圍是0到16777215。
    • 中等大小的整數(shù),一位大小為3個字節(jié)。

    3.2 創(chuàng)建兩個函數(shù)

    -- 創(chuàng)建兩個函數(shù):生成隨機字符串和隨機編號
    -- 產(chǎn)生隨機字符串的函數(shù)
    delimiter $?
    drop FUNCTION if EXISTS rand_string;
    CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
    BEGIN
    ? ? DECLARE chars_str VARCHAR(100) DEFAULT "abcdefghijklmlopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    ? ? DECLARE return_str VARCHAR(255) DEFAULT "";
    ? ? DECLARE i INT DEFAULT 0;
    ? ? WHILE i < n DO
    ? ? SET return_str = CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
    ? ? SET i = i+1;
    ? ? END WHILE;
    ? ? RETURN return_str;
    END $
    delimiter;
    
    -- 產(chǎn)生隨機部門編號的函數(shù)
    delimiter $?
    drop FUNCTION if EXISTS rand_num;
    CREATE FUNCTION rand_num() RETURNS INT(5)
    BEGIN
    ? ? DECLARE i INT DEFAULT 0;
    ? ? SET i = FLOOR(100+RAND()*10);
    ? ? RETURN i;
    END $
    delimiter;
    
    注意說明
    -- 執(zhí)行函數(shù)問題,This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its de
    -- 這是我們開啟了bin-log, 我們就必須指定我們的函數(shù)是否是,DETERMINISTIC 不確定的, NO SQL 沒有SQl語句,當然也不會修改數(shù)據(jù)
    -- 在MySQL中創(chuàng)建函數(shù)時出現(xiàn)這種錯誤的解決方法:set global log_bin_trust_function_creators=TRUE;
    set global log_bin_trust_function_creators=TRUE;

    3.3 編寫存儲過程

    -- 編寫存儲過程,模擬 100W 的員工數(shù)據(jù)。
    -- 建立存儲過程:往emp表中插入數(shù)據(jù)
    ?DELIMITER $
    ?drop PROCEDURE if EXISTS insert_emp;
    ?CREATE PROCEDURE insert_emp(IN START INT(10),IN max_num INT(10))
    ?BEGIN
    ? ? ?DECLARE i INT DEFAULT 0;
    ? ? ?/*set autocommit =0 把autocommit設置成0,把默認提交關閉*/
    ? ? ?SET autocommit = 0;
    ? ? ?REPEAT
    ? ? ?SET i = i + 1;
    ? ? ?INSERT INTO emp(empno,empname,job,mgr,hiredate,sal,comn,depno) VALUES ((START+i),rand_string(6),"SALEMAN",0001,now(),2000,400,rand_num());
    ? ? ?UNTIL i = max_num
    ? ? ?END REPEAT;
    ? ? ?COMMIT;
    ?END $
    ?DELIMITER;
    ?
    -- 插入500W條數(shù)據(jù),時間有點久,耐心等待,1409s
    ?call insert_emp(0,5000000);
    
    -- 查詢部門員工表
    select * from emp LIMIT 1,10;

    3.4 編寫存儲過程

    -- 編寫存儲過程,模擬 120 的部門數(shù)據(jù)
    -- 建立存儲過程:往dep表中插入數(shù)據(jù)
    ?DELIMITER $
    ?drop PROCEDURE if EXISTS insert_dept;
    ?CREATE PROCEDURE insert_dept(IN START INT(10),IN max_num INT(10))
    ?BEGIN
    ? ? ?DECLARE i INT DEFAULT 0;
    ? ? ?SET autocommit = 0;
    ? ? ?REPEAT
    ? ? ?SET i = i+1;
    ? ? ?INSERT ?INTO dep( depno,depname,memo) VALUES((START+i),rand_string(10),rand_string(8));
    ? ? ?UNTIL i = max_num
    ? ? ?END REPEAT;
    ? ? ?COMMIT;
    ?END $
    ?DELIMITER;
    ?
    -- 插入120條數(shù)據(jù)
    ?call insert_dept(1,120);
    
    -- 查詢部門員工表
    select * from dep;

    3.5 創(chuàng)建索引

    -- 建立關鍵字段的索引,這邊是跑完數(shù)據(jù)之后再建索引,會導致建索引耗時長,但是跑數(shù)據(jù)就會快一些。
    -- 建立關鍵字段的索引:排序、條件
    CREATE INDEX idx_emp_id ON emp(id);
    CREATE INDEX idx_emp_depno ON emp(depno);
    CREATE INDEX idx_dep_depno ON dep(depno); 
    

    3.6 驗證測試

    -- 驗證測試
    -- 偏移量為100,取25,Time: 0.011s
    SELECT a.empno,a.empname,a.job,a.sal,b.depno,b.depname
    from emp a left join dep b on a.depno = b.depno order by a.id desc limit 100,25;
    
    -- 偏移量為4800000,取25,Time: 10.242s
    SELECT a.empno,a.empname,a.job,a.sal,b.depno,b.depname
    from emp a left join dep b on a.depno = b.depno order by a.id desc limit 4800000,25;

    4. 解決方案

    4.1 使用索引覆蓋+子查詢優(yōu)化

    因為我們有主鍵 id,并且在上面建了索引,所以可以先在索引樹中找到開始位置的 id 值,再根據(jù)找到的 id 值查詢行數(shù)據(jù)。

    -- 子查詢獲取偏移100條的位置的id,在這個位置上往后取25,Time: 0.04s
    ?SELECT a.empno,a.empname,a.job,a.sal,b.depno,b.depname
    ?from emp a left join dep b on a.depno = b.depno
    ?where a.id >= (select id from emp order by id limit 100,1)
    ?order by a.id limit 25;
    
    -- 子查詢獲取偏移4800000條的位置的id,在這個位置上往后取25,Time: 1.549s
    ?SELECT a.empno,a.empname,a.job,a.sal,b.depno,b.depname
    ?from emp a left join dep b on a.depno = b.depno
    ?where a.id >= (select id from emp order by id limit 4800000,1)
    ?order by a.id limit 25;

    4.2 起始位置重定義

    記住上次查找結果的主鍵位置,避免使用偏移量 offset。

    這個效率是最好的,無論怎么分頁,耗時基本都是一致的,因為他執(zhí)行完條件之后,都只掃描了 25 條數(shù)據(jù)。

    但是有個問題,只適合一頁一頁的分頁,這樣才能記住前一個分頁的最后 id。如果用戶跳著分頁就有問題了,比如剛剛刷完第 25 頁,馬上跳到 35 頁,數(shù)據(jù)就會不對。這種的適合場景是類似百度搜索或者騰訊新聞那種滾輪往下拉,不斷拉取不斷加載的情況。這種延遲加載會保證數(shù)據(jù)不會跳躍著獲取。

    -- 記住了上次的分頁的最后一條數(shù)據(jù)的id是100,這邊就直接跳過100,從101開始掃描表,Time: 0.006s
    ?SELECT a.id,a.empno,a.empname,a.job,a.sal,b.depno,b.depname
    ?from emp a left join dep b on a.depno = b.depno
    ?where a.id > 100 order by a.id limit 25;
    
    -- 記住了上次的分頁的最后一條數(shù)據(jù)的id是4800000,這邊就直接跳過4800000,從4800001開始掃描表,Time: 0.046s
    ?SELECT a.id,a.empno,a.empname,a.job,a.sal,b.depno,b.depname
    ?from emp a left join dep b on a.depno = b.depno
    ?where a.id > 4800000
    ?order by a.id limit 25;

    4.3 降級策略

    看了網(wǎng)上一個阿里的 DBA 同學分享的方案:配置 limit 的偏移量和獲取數(shù)一個最大值,超過這個最大值,就返回空數(shù)據(jù)。
    因為他覺得超過這個值你已經(jīng)不是在分頁了,而是在刷數(shù)據(jù)了,如果確認要找數(shù)據(jù),應該輸入合適條件來縮小范圍,而不是一頁一頁分頁。

    5. 梳理總結

    深分頁問題從理論上來說是存在的場景,但是從實際的業(yè)務場景考慮,深分頁很多情況下缺少具體的業(yè)務場景做支撐,試想哪個業(yè)務會從480W頁面,查詢25條數(shù)據(jù),如果需要搜索某條數(shù)據(jù),使用最多的應該根據(jù)條件類型過濾吧。

    每種方案各有優(yōu)缺點,具體采用那種解決方案需要結合具體的業(yè)務場景,如果根據(jù)實際業(yè)務場景不需要深分頁,可以采用降級策略,設置分頁參數(shù)閾值。如果確實需要深分頁問題可以覆蓋子+子查詢優(yōu)化或者通過偏移量查詢,如果能獲取到偏移量的前提下優(yōu)先選擇偏移量的方案,否則采用覆蓋索引+子查詢。

    無論是否深分頁都應該考慮限流降級的問題,而且要考慮短時間內(nèi)重復調(diào)用的問題,可以限制每秒執(zhí)行次數(shù),避免用戶誤點以及調(diào)用頻繁帶來的數(shù)據(jù)安全問題。

    到此這篇關于MySql深分頁問題解決的文章就介紹到這了,更多相關MySql深分頁內(nèi)容請搜索以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持!

    標簽: MySQL
    相關文章:
    日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
    精品精品99| 国产精品免费看| 美国三级日本三级久久99| 欧美午夜不卡影院在线观看完整版免费| 精品国产免费人成网站| 亚洲最大av| 亚洲精品日本| 青青草91久久久久久久久| 国产欧美亚洲精品a| 国产精品调教| 欧美xxxx中国| 久久精品观看| 蜜臀av亚洲一区中文字幕| 视频一区日韩| 久久伊人国产| 影视先锋久久| 亚洲一区有码| 国产亚洲第一伦理第一区| 国产精品s色| 日本精品不卡| 亚洲aa在线| 精品久久久网| 99pao成人国产永久免费视频 | 97人人精品| 91亚洲人成网污www| 午夜国产精品视频免费体验区| 亚洲久草在线| 精品一区二区三区免费看| 精品丝袜在线| 国产三级一区| jiujiure精品视频播放| 欧美精品三级在线| 伊人精品一区| 国产伦精品一区二区三区千人斩 | 视频一区中文字幕| 国产精品黄网站| 久久都是精品| 日韩欧美在线中字| 国产精品三级| 亚洲精品自拍| 五月天久久777| 97精品国产| 国产精品1区在线| 天堂va欧美ⅴa亚洲va一国产| 99成人超碰| 国产精品天堂蜜av在线播放| 亚洲在线免费| 日韩精品网站| 日本不良网站在线观看| 你懂的亚洲视频| 亚洲一二av| 红桃视频国产精品| 亚洲性色视频| 午夜精品婷婷| 亚洲精品1区2区| 图片区亚洲欧美小说区| 另类中文字幕国产精品| 日韩大片在线播放| 欧美日韩国产v| 久久午夜影院| 久久亚洲国产精品尤物| 97se亚洲| 国产精品久久久久久久久久久久久久久| 欧美日韩国产一区二区在线观看| 午夜国产精品视频免费体验区| 999在线观看精品免费不卡网站| 亚洲啊v在线| 日韩和欧美一区二区三区| 亚洲精品精选| 国产欧美日韩影院| 国产66精品| 1024精品一区二区三区| 亚洲深夜av| 欧美亚洲自偷自偷| 偷拍亚洲精品| 欧美激情麻豆| 蜜桃成人精品| 日韩国产欧美视频| 国产亚洲高清一区| 都市激情国产精品| 午夜在线观看免费一区| 日本精品在线播放| www.51av欧美视频| 午夜一区在线| 精品国产黄a∨片高清在线| 日韩欧美自拍| 日韩欧美中文字幕电影| caoporn视频在线| 另类av一区二区| 国产日韩欧美三区| 秋霞影院一区二区三区 | 狂野欧美性猛交xxxx| 美女性感视频久久| 999久久久国产精品| 五月激激激综合网色播| 日韩免费视频| 777久久精品| 在线精品视频在线观看高清| 国产一精品一av一免费爽爽| 欧美一区二区性| 国产精品1区| 亚洲人成毛片在线播放女女| 麻豆mv在线观看| 日韩动漫一区| 亚洲一区二区三区高清| 国产精品99一区二区三区| 中文字幕中文字幕精品| 亚洲午夜视频| 黑人精品一区| 日本不卡视频在线观看| 激情视频一区二区三区| 激情不卡一区二区三区视频在线| 国产视频一区二| 欧美不卡在线| 日韩高清不卡| 免费高潮视频95在线观看网站| 麻豆精品在线| 亚洲一区成人| 久久久久久免费视频| 久久久久久一区二区| 欧美精品二区| 久久这里只有精品一区二区| 久久国际精品| 国产伦理久久久久久妇女| 五月国产精品| 91精品国产一区二区在线观看| 深夜日韩欧美| 国产偷自视频区视频一区二区| 久久久精品久久久久久96| 久久激情一区| 亚洲成人日韩| 午夜日韩在线| 日本电影久久久| 日韩在线一二三区| 亚洲视频国产精品| 日韩高清在线不卡| 国产精品乱战久久久| 国产精品调教| 国产一区二区三区不卡av| 正在播放日韩精品| 在线一区欧美| 欧美精品国产白浆久久久久| 欧美激情视频一区二区三区在线播放| 天堂√中文最新版在线| 国产欧洲在线| 亚洲一区久久| 国产欧美一区二区色老头| 国产伦精品一区二区三区千人斩| 欧洲一区二区三区精品| 136国产福利精品导航网址| 亚洲一区二区三区高清不卡| 日韩视频精品在线观看| 亚洲精品日本| 成人在线免费观看网站| 国产综合精品一区| 国产日韩高清一区二区三区在线 | 久久99高清| 日本国产一区| 亚洲精品在线a| 久久精品99国产国产精| 欧美国产专区| 青青伊人久久| 日本视频一区二区| 色网在线免费观看| 蜜臀久久久久久久| 欧美激情一区| 午夜精品亚洲| 久久久久亚洲精品中文字幕| 尤物在线精品| 精品视频高潮| 快she精品国产999| 久久av免费| 香蕉成人久久| 日韩在线中文| 国产精品亚洲二区| 日韩精品一级中文字幕精品视频免费观看 | 蜜桃一区二区三区| 国产精品sss在线观看av| 在线精品小视频| 午夜精品成人av| 日本v片在线高清不卡在线观看| 成人精品久久| 亚洲综合专区| 久久九九99| 鲁鲁在线中文| 成人在线视频免费看| 欧美精品中文| 视频一区视频二区在线观看| 精品三级国产| 久久精品xxxxx| 亚洲在线一区| 亚洲欧洲午夜| 欧美日中文字幕| 久久91导航| 久久亚洲精品中文字幕| 日韩av一区二| 国内精品福利| 国产精品久久观看| 欧美日本不卡| 亚洲视频二区|