99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MySQL用limit為什么會影響性能

Linux愛好者 ? 來源:簡書 ? 作者:Muscleape ? 2022-06-20 16:31 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

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

原理:減少回表操作,利用延遲關(guān)聯(lián)或者子查詢優(yōu)化超多分頁場景。

--優(yōu)化前SQL
SELECT各種字段
FROM`table_name`
WHERE各種條件
LIMIT0,10;
--優(yōu)化后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)

表結(jié)構(gòu):

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為非唯一索引。

灌入大量數(shù)據(jù),共500萬:

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

我們知道,當(dāng)limit offset rows中的offset很大時(shí),會出現(xiàn)效率問題:

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)

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

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)

時(shí)間相差很明顯。

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

查詢到索引葉子節(jié)點(diǎn)數(shù)據(jù)。根據(jù)葉子節(jié)點(diǎn)上的主鍵值去聚簇索引上查詢需要的全部字段值。

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

像上面這樣,需要查詢300005次索引節(jié)點(diǎn),查詢300005次聚簇索引的數(shù)據(jù),最后再將結(jié)果過濾掉前300000條,取出最后5條。MySQL耗費(fèi)了大量隨機(jī)I/O在查詢聚簇索引的數(shù)據(jù)上,而有300000次隨機(jī)I/O查詢到的數(shù)據(jù)是不會出現(xiàn)在結(jié)果集當(dāng)中的。

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

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

其實(shí)我也想問這個(gè)問題。

證實(shí)

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

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

我只能通過間接的方式來證實(shí):

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

預(yù)測結(jié)果是運(yùn)行select * from test a inner join (select id from test where val=4 limit 300000,5);之后,buffer pool中的數(shù)據(jù)頁的數(shù)量遠(yuǎn)遠(yuǎn)少于select * from test where val=4 limit 300000,5;對應(yīng)的數(shù)量,因?yàn)榍耙粋€(gè)sql只訪問5次數(shù)據(jù)頁,而后一個(gè)sql訪問300005次數(shù)據(jù)頁。

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中沒有關(guān)于test表的數(shù)據(jù)頁。

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)

可以看出,此時(shí)buffer pool中關(guān)于test表有4098個(gè)數(shù)據(jù)頁,208個(gè)索引頁。

select * from test a inner join (select id from test where val=4 limit 300000,5) ;為了防止上次試驗(yàn)的影響,我們需要清空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)

運(yùn)行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)

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

遇到的問題

為了在每次重啟時(shí)確保清空buffer pool,我們需要關(guān)閉innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup,這兩個(gè)選項(xiàng)能夠控制數(shù)據(jù)庫關(guān)閉時(shí)dump出buffer pool中的數(shù)據(jù)和在數(shù)據(jù)庫開啟時(shí)載入在磁盤上備份buffer pool的數(shù)據(jù)。

原文標(biāo)題:一次 SQL 查詢優(yōu)化原理分析:900W+ 數(shù)據(jù),從 17s 到 300ms

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

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7257

    瀏覽量

    91940
  • SQL
    SQL
    +關(guān)注

    關(guān)注

    1

    文章

    783

    瀏覽量

    45183
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    861

    瀏覽量

    27966

原文標(biāo)題:一次 SQL 查詢優(yōu)化原理分析:900W+ 數(shù)據(jù),從 17s 到 300ms

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    除了增刪改查你對MySQL還了解多少

    我們都知道MySQL服務(wù)器的默認(rèn)端口為3306,之后就在這個(gè)端口號上等待客戶端進(jìn)程進(jìn)行連接(MySQL服務(wù)器默認(rèn)監(jiān)聽3306端口)。
    的頭像 發(fā)表于 04-14 17:20 ?256次閱讀

    使用插件將Excel連接到MySQL/MariaDB

    使用插件將 Excel 連接到 MySQL/MariaDB 適用于 MySQL 的 Devart Excel 插件允許您將 Microsoft Excel 連接到 MySQL 或 MariaDB
    的頭像 發(fā)表于 01-20 12:38 ?633次閱讀
    使用插件將Excel連接到<b class='flag-5'>MySQL</b>/MariaDB

    適用于MySQL和MariaDB的.NET連接器

    支持 ORM 的適用于 MySQL 和 MariaDB 的 .NET 連接器 dotConnect for MySQL 是一種高性能 ADO.NET 數(shù)據(jù)提供程序,可在開發(fā) MySQL
    的頭像 發(fā)表于 01-16 14:17 ?496次閱讀
    適用于<b class='flag-5'>MySQL</b>和MariaDB的.NET連接器

    MySQL數(shù)據(jù)庫的安裝

    MySQL數(shù)據(jù)庫的安裝 【一】各種數(shù)據(jù)庫的端口 MySQL :3306 Redis :6379 MongoDB :27017 Django :8000 flask :5000 【二】MySQL 介紹
    的頭像 發(fā)表于 01-14 11:25 ?570次閱讀
    <b class='flag-5'>MySQL</b>數(shù)據(jù)庫的安裝

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

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

    Flexus X 實(shí)例搭配華為云 EulerOS,快速部署 MySQL 并執(zhí)行讀寫性能測試

    社區(qū) openEuler 構(gòu)建的 linux 操作系統(tǒng),提供云原生、高性能、安全穩(wěn)定的執(zhí)行環(huán)境來開發(fā)和運(yùn)行應(yīng)用程序,助力企業(yè)客戶快速上云及開發(fā)者創(chuàng)新 MySQL 安裝與啟動(dòng) 原計(jì)劃是通過指
    的頭像 發(fā)表于 12-24 12:27 ?595次閱讀
    Flexus X 實(shí)例搭配華為云 EulerOS,快速部署 <b class='flag-5'>MySQL</b> 并執(zhí)行讀寫<b class='flag-5'>性能</b>測試

    云服務(wù)器 Flexus X 實(shí)例 MySQL 應(yīng)用加速測試

    文章目錄 目錄 文章目錄 ? 購買配置 ? 基本配置參考如下: ? 連接服務(wù)器 ? 查詢MySQL狀態(tài) ? 啟動(dòng)MySQL ? 添加配置 ? 添加密碼并修改權(quán)限 ? 性能測試 ? C#插入數(shù)據(jù)測試
    的頭像 發(fā)表于 12-24 12:19 ?523次閱讀
    云服務(wù)器 Flexus X 實(shí)例 <b class='flag-5'>MySQL</b> 應(yīng)用加速測試

    MySQL還能跟上PostgreSQL的步伐嗎

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

    詳解MySQL多實(shí)例部署

    詳解MySQL多實(shí)例部署
    的頭像 發(fā)表于 11-11 11:10 ?649次閱讀

    MySQL編碼機(jī)制原理

    前言 一位讀者在本地部署 MySQL 測試環(huán)境時(shí)碰到一個(gè)問題,我覺得挺有代表性的,所以寫篇文章介紹一下,看完相信你會對 MySQL 的編碼機(jī)制有最本質(zhì)的了解,本文的目錄結(jié)構(gòu)如下 讀者問題簡介
    的頭像 發(fā)表于 11-09 11:01 ?587次閱讀

    適用于MySQL的dbForge架構(gòu)比較

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

    labview與西門子SMART通訊并上傳至MYSQL數(shù)據(jù)庫在什么情況下導(dǎo)致PLC觸點(diǎn)抖動(dòng)

    labview與西門子SMART通訊并上傳至MYSQL數(shù)據(jù)庫,smart200觸點(diǎn)抖動(dòng),并且運(yùn)行時(shí)間越久越嚴(yán)重。 抖動(dòng)出現(xiàn)時(shí)監(jiān)控PLC程序沒有信號的變化,但是輸出輸入觸點(diǎn)快速閃爍,所控制的繼電器
    發(fā)表于 10-22 17:41

    Jtti:MySQL初始化操作如何設(shè)置root密碼

    MySQL初始化時(shí),可以通過以下步驟設(shè)置root密碼: 打開命令行工具,使用以下命令啟動(dòng)MySQL服務(wù): ? sudo service mysql start ? 使用以下命令登錄MySQL
    的頭像 發(fā)表于 08-08 16:45 ?851次閱讀

    MySQL知識點(diǎn)匯總

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

    華納云:如何修改MySQL的默認(rèn)端口

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