色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

MySQL用limit為什么會影響性能

Linux愛好者 ? 來源:簡書 ? 作者:Muscleape ? 2022-06-20 16:31 ? 次閱讀

有一張財務流水表,未分庫分表,目前的數據量為9555695,分頁查詢使用到了limit,優化之前的查詢耗時16 s 938 ms(execution: 16 s 831 ms, fetching: 107 ms),按照下文的方式調整SQL后,耗時347 ms(execution: 163 ms, fetching: 184 ms);

操作:查詢條件放到子查詢中,子查詢只查主鍵ID,然后使用子查詢中確定的主鍵關聯查詢其他的屬性字段;

原理:減少回表操作,利用延遲關聯或者子查詢優化超多分頁場景。

--優化前SQL
SELECT各種字段
FROM`table_name`
WHERE各種條件
LIMIT0,10;
--優化后SQL
SELECT各種字段
FROM`table_name`main_tale
RIGHTJOIN
(
SELECT子查詢只查主鍵
FROM`table_name`
WHERE各種條件
LIMIT0,10;
)temp_tableONtemp_table.主鍵=main_table.主鍵

找到的原理分析:MySQL 用 limit 為什么會影響性能?

前言

首先說明一下MySQL的版本:

mysql>selectversion();
+-----------+
|version()|
+-----------+
|5.7.17|
+-----------+
1rowinset(0.00sec)

表結構:

mysql>desctest;
+--------+---------------------+------+-----+---------+----------------+
|Field|Type|Null|Key|Default|Extra|
+--------+---------------------+------+-----+---------+----------------+
|id|bigint(20)unsigned|NO|PRI|NULL|auto_increment|
|val|int(10)unsigned|NO|MUL|0||
|source|int(10)unsigned|NO||0||
+--------+---------------------+------+-----+---------+----------------+
3rowsinset(0.00sec)

id為自增主鍵,val為非唯一索引

灌入大量數據,共500萬:

mysql>selectcount(*)fromtest;
+----------+
|count(*)|
+----------+
|5242882|
+----------+
1rowinset(4.25sec)

我們知道,當limit offset rows中的offset很大時,會出現效率問題:

mysql>select*fromtestwhereval=4limit300000,5;
+---------+-----+--------+
|id|val|source|
+---------+-----+--------+
|3327622|4|4|
|3327632|4|4|
|3327642|4|4|
|3327652|4|4|
|3327662|4|4|
+---------+-----+--------+
5rowsinset(15.98sec)

為了達到相同的目的,我們一般會改寫成如下語句:

mysql>select*fromtestainnerjoin(selectidfromtestwhereval=4limit300000,5)bona.id=b.id;
+---------+-----+--------+---------+
|id|val|source|id|
+---------+-----+--------+---------+
|3327622|4|4|3327622|
|3327632|4|4|3327632|
|3327642|4|4|3327642|
|3327652|4|4|3327652|
|3327662|4|4|3327662|
+---------+-----+--------+---------+
5rowsinset(0.38sec)

時間相差很明顯。

為什么會出現上面的結果?我們看一下select * from test where val=4 limit 300000,5;的查詢過程:

查詢到索引葉子節點數據。根據葉子節點上的主鍵值去聚簇索引上查詢需要的全部字段值。

類似于下面這張圖:fdbcabee-efc7-11ec-ba43-dac502259ad0.jpg

像上面這樣,需要查詢300005次索引節點,查詢300005次聚簇索引的數據,最后再將結果過濾掉前300000條,取出最后5條。MySQL耗費了大量隨機I/O在查詢聚簇索引的數據上,而有300000次隨機I/O查詢到的數據是不會出現在結果集當中的。

肯定會有人問:既然一開始是利用索引的,為什么不先沿著索引葉子節點查詢到最后需要的5個節點,然后再去聚簇索引中查詢實際數據。這樣只需要5次隨機I/O,類似于下面圖片的過程:

fdd667fa-efc7-11ec-ba43-dac502259ad0.jpg

其實我也想問這個問題。

證實

下面我們實際操作一下來證實上述的推論:

為了證實select * from test where val=4 limit 300000,5是掃描300005個索引節點和300005個聚簇索引上的數據節點,我們需要知道MySQL有沒有辦法統計在一個sql中通過索引節點查詢數據節點的次數。我先試了Handler_read_*系列,很遺憾沒有一個變量能滿足條件。

我只能通過間接的方式來證實:

InnoDB中有buffer pool。里面存有最近訪問過的數據頁,包括數據頁和索引頁。所以我們需要運行兩個sql,來比較buffer pool中的數據頁的數量。

預測結果是運行select * from test a inner join (select id from test where val=4 limit 300000,5);之后,buffer pool中的數據頁的數量遠遠少于select * from test where val=4 limit 300000,5;對應的數量,因為前一個sql只訪問5次數據頁,而后一個sql訪問300005次數據頁。

select*fromtestwhereval=4limit300000,5
mysql>selectindex_name,count(*)frominformation_schema.INNODB_BUFFER_PAGEwhereINDEX_NAMEin('val','primary')andTABLE_NAMElike'%test%'groupbyindex_name;Emptyset(0.04sec)

可以看出,目前buffer pool中沒有關于test表的數據頁。

mysql>select*fromtestwhereval=4limit300000,5;
+---------+-----+--------+
|id|val|source|
+---------+-----+--------+|
3327622|4|4|
|3327632|4|4|
|3327642|4|4|
|3327652|4|4|
|3327662|4|4|
+---------+-----+--------+
5rowsinset(26.19sec)

mysql>selectindex_name,count(*)frominformation_schema.INNODB_BUFFER_PAGEwhereINDEX_NAMEin('val','primary')andTABLE_NAMElike'%test%'groupbyindex_name;
+------------+----------+
|index_name|count(*)|
+------------+----------+
|PRIMARY|4098|
|val|208|
+------------+----------+2rowsinset(0.04sec)

可以看出,此時buffer pool中關于test表有4098個數據頁,208個索引頁。

select * from test a inner join (select id from test where val=4 limit 300000,5) ;為了防止上次試驗的影響,我們需要清空buffer pool,重啟mysql。

mysqladminshutdown
/usr/local/bin/mysqld_safe&
mysql>selectindex_name,count(*)frominformation_schema.INNODB_BUFFER_PAGEwhereINDEX_NAMEin('val','primary')andTABLE_NAMElike'%test%'groupbyindex_name;

Emptyset(0.03sec)

運行sql:

mysql>select*fromtestainnerjoin(selectidfromtestwhereval=4limit300000,5)bona.id=b.id;
+---------+-----+--------+---------+
|id|val|source|id|
+---------+-----+--------+---------+
|3327622|4|4|3327622|
|3327632|4|4|3327632|
|3327642|4|4|3327642|
|3327652|4|4|3327652|
|3327662|4|4|3327662|
+---------+-----+--------+---------+
5rowsinset(0.09sec)

mysql>selectindex_name,count(*)frominformation_schema.INNODB_BUFFER_PAGEwhereINDEX_NAMEin('val','primary')andTABLE_NAMElike'%test%'groupbyindex_name;
+------------+----------+
|index_name|count(*)|
+------------+----------+
|PRIMARY|5|
|val|390|
+------------+----------+
2rowsinset(0.03sec)

我們可以看明顯的看出兩者的差別:第一個sql加載了4098個數據頁到buffer pool,而第二個sql只加載了5個數據頁到buffer pool。符合我們的預測。也證實了為什么第一個sql會慢:讀取大量的無用數據行(300000),最后卻拋棄掉。而且這會造成一個問題:加載了很多熱點不是很高的數據頁到buffer pool,會造成buffer pool的污染,占用buffer pool的空間。

遇到的問題

為了在每次重啟時確保清空buffer pool,我們需要關閉innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup,這兩個選項能夠控制數據庫關閉時dump出buffer pool中的數據和在數據庫開啟時載入在磁盤上備份buffer pool的數據。

原文標題:一次 SQL 查詢優化原理分析:900W+ 數據,從 17s 到 300ms

文章出處:【微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據
    +關注

    關注

    8

    文章

    7085

    瀏覽量

    89214
  • SQL
    SQL
    +關注

    關注

    1

    文章

    768

    瀏覽量

    44177
  • MySQL
    +關注

    關注

    1

    文章

    817

    瀏覽量

    26629

原文標題:一次 SQL 查詢優化原理分析:900W+ 數據,從 17s 到 300ms

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    華為云 Flexus X 實例 MySQL 性能加速評測及對比

    基于 sysbench 構造測試表和測試數據 12 3.5 數據庫讀寫性能測試 13 四、業界 U?系列無加速 MySQL
    的頭像 發表于 12-25 17:10 ?196次閱讀
    華為云 Flexus X 實例 <b class='flag-5'>MySQL</b> <b class='flag-5'>性能</b>加速評測及對比

    云服務器 Flexus X 實例 MySQL 應用加速測試

    文章目錄 目錄 文章目錄 ? 購買配置 ? 基本配置參考如下: ? 連接服務器 ? 查詢MySQL狀態 ? 啟動MySQL ? 添加配置 ? 添加密碼并修改權限 ? 性能測試 ? C#插入數據測試
    的頭像 發表于 12-24 12:19 ?181次閱讀
    云服務器 Flexus X 實例 <b class='flag-5'>MySQL</b> 應用加速測試

    MySQL還能跟上PostgreSQL的步伐嗎

    Percona 的老板 Peter Zaitsev最近發表一篇博客,討論了MySQL是否還能跟上PostgreSQL的腳步。Percona 作為MySQL 生態扛旗者,Percona 開發了知名
    的頭像 發表于 11-18 10:16 ?229次閱讀
    <b class='flag-5'>MySQL</b>還能跟上PostgreSQL的步伐嗎

    詳解MySQL多實例部署

    詳解MySQL多實例部署
    的頭像 發表于 11-11 11:10 ?287次閱讀

    MySQL編碼機制原理

    前言 一位讀者在本地部署 MySQL 測試環境時碰到一個問題,我覺得挺有代表性的,所以寫篇文章介紹一下,看完相信你會對 MySQL 的編碼機制有最本質的了解,本文的目錄結構如下 讀者問題簡介
    的頭像 發表于 11-09 11:01 ?262次閱讀

    適用于MySQL的dbForge架構比較

    dbForge Schema Compare for MySQL 是一種工具,用于輕松有效地比較和部署 MySQL 數據庫結構和腳本文件夾差異。該工具提供了 MySQL 數據庫架構中所有差異的全面視圖。
    的頭像 發表于 10-28 09:41 ?227次閱讀
    適用于<b class='flag-5'>MySQL</b>的dbForge架構比較

    labview與西門子SMART通訊并上傳至MYSQL數據庫在什么情況下導致PLC觸點抖動

    labview與西門子SMART通訊并上傳至MYSQL數據庫,smart200觸點抖動,并且運行時間越久越嚴重。 抖動出現時監控PLC程序沒有信號的變化,但是輸出輸入觸點快速閃爍,所控制的繼電器
    發表于 10-22 17:41

    Jtti:MySQL初始化操作如何設置root密碼

    MySQL初始化時,可以通過以下步驟設置root密碼: 打開命令行工具,使用以下命令啟動MySQL服務: ? sudo service mysql start ? 使用以下命令登錄MySQL
    的頭像 發表于 08-08 16:45 ?399次閱讀

    MySQL知識點匯總

    大家好,這部分被稱為DQL部分,是每個學習MySQL必須要學會的部分,下面就讓我來介紹MySQL中的其他部分。
    的頭像 發表于 08-05 15:27 ?416次閱讀
    <b class='flag-5'>MySQL</b>知識點匯總

    華納云:如何修改MySQL的默認端口

    MySQL是世界上最流行的開源關系型數據庫管理系統之一。在某些情況下,由于安全性、網絡策略或端口沖突的原因,數據庫管理員可能需要更改MySQL服務的默認監聽端口。本文將指導您如何在不同的操作系統上
    的頭像 發表于 07-22 14:56 ?332次閱讀
    華納云:如何修改<b class='flag-5'>MySQL</b>的默認端口

    請問stm32cubeide怎么取ImageER_IROM1Limit?

    MDK的時候取image大小是\"ImageER_IROM1Limit\"這樣的,但是stm32cubeide用不了,大家有什么辦法嗎?謝謝
    發表于 05-29 06:03

    MySQL的整體邏輯架構

    支持多種存儲引擎是眾所周知的MySQL特性,也是MySQL架構的關鍵優勢之一。如果能夠理解MySQL Server與存儲引擎之間是怎樣通過API交互的,將大大有利于理解MySQL的核心
    的頭像 發表于 04-30 11:14 ?466次閱讀
    <b class='flag-5'>MySQL</b>的整體邏輯架構

    MySQL忘記root密碼解決方案

    mysql登錄密碼為password()算法加密,解密成本太高,以下為通用方案; 原理:mysql提供了特殊啟動方式,即跳過權限表驗證,啟動后,登錄不需要提供密碼; 登錄后,即可修改mysql數據庫的user表,重置
    的頭像 發表于 04-23 16:08 ?733次閱讀

    Redis與MySQL協同升級企業緩存

    傳統的MySQL數據庫在處理大規模應用時已經到了瓶頸,RedisEnterprise怎樣助力突破這一瓶頸?RedisEnterprise與MYSQL共同用作企業級緩存或副本數據庫,產生什么樣的火花
    的頭像 發表于 02-19 13:18 ?388次閱讀
    Redis與<b class='flag-5'>MySQL</b>協同升級企業緩存

    MySQL密碼忘記了怎么辦?MySQL密碼快速重置方法步驟命令示例!

    MySQL密碼忘記了怎么辦?MySQL密碼快速重置方法步驟命令示例! MySQL是一種常用的關系型數據庫管理系統,如果你忘記了MySQL的密碼,不必擔心,可以通過一些簡單的步驟來快速重
    的頭像 發表于 01-12 16:06 ?773次閱讀
    主站蜘蛛池模板: 91交换论坛| 真实国产精品视频国产网| 久久久97丨国产人妻熟女| 粉嫩国产14xxxxx0000| 91夫妻交友论坛| 亚洲精品嫩草研究院久久| 天美传媒在线观看完整高清 | 沈芯语麻豆0076 视频| 欧美97色伦影院在线观看| 浪荡女天天不停挨CAO日常视| 九九热精品免费观看| 黄色片软件大全| 好紧的小嫩嫩17p| 国产午夜精品鲁丝片| 国产精品欧美久久久久天天影视| 国产99久久久国产精品成人| 成人无码在线超碰视频| 不分昼夜H1V3| 亚洲一区二区影院| 亚洲性夜夜色综合网站| 亚洲欧洲日韩视频在钱| 亚洲精品视频在线播放| 亚洲AV无码乱码国产精品品麻豆 | 日日操夜夜操狠狠操| 日韩精品久久久久久久电影| 桃色园社区| 亚洲成人综合在线| 亚洲蜜桃AV永久无码精品放毛片| 小SAO货水真多把你CAO烂| 亚洲高清无在码在线电影| 亚洲视频不卡| 2020亚洲色噜噜狠狠网站| freehd另类xxxx喷水| 成人在免费视频手机观看网站| 国产AV精品久久久毛片| 国产精品视频一区二区猎奇| 果冻传媒视频在线播放| 老师小扫货水能么多叫出来| 欧美视频毛片在线播放| 思思re热免费精品视频66| 小雪奶水涨翁工帮吸的推荐语录 |