精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

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

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

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

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

數(shù)據(jù)分析與開發(fā) ? 來源:未知 ? 2023-04-14 14:27 ? 次閱讀

有一張財(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)化超多分頁場(chǎng)景。

--優(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 為什么會(huì)影響性能?

前言

首先說明一下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í),會(huì)出現(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á)到相同的目的,我們一般會(huì)改寫成如下語句:

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í)間相差很明顯。

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

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

類似于下面這張圖:45d781ce-d8f7-11ed-bfe3-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ù)是不會(huì)出現(xiàn)在結(jié)果集當(dāng)中的。

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

45ed9680-d8f7-11ed-bfe3-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ù)測(cè)結(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;對(duì)應(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ù)測(cè)。也證實(shí)了為什么第一個(gè)sql會(huì)慢:讀取大量的無用數(shù)據(jù)行(300000),最后卻拋棄掉。而且這會(huì)造成一個(gè)問題:加載了很多熱點(diǎn)不是很高的數(shù)據(jù)頁到buffer pool,會(huì)造成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ù)。

審核編輯 :李倩


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

    關(guān)注

    8

    文章

    6898

    瀏覽量

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

    關(guān)注

    1

    文章

    760

    瀏覽量

    44079
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    3766

    瀏覽量

    64278

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

文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    文了解MyBatis的查詢原理

    本文通過MyBatis個(gè)低版本的bug(3.4.5之前的版本)入手,分析MyBatis的一次完整的查詢流程,配置文件的解析
    的頭像 發(fā)表于 10-10 11:42 ?1402次閱讀

    基于索引的SQL語句優(yōu)化之降龍十八掌

    的范圍信息會(huì)放入Oracle的數(shù)據(jù)字典中。Oracle可以利用這個(gè)信息來提取出那些只與SQL查詢相關(guān)的數(shù)據(jù)分區(qū)。例如,假設(shè)你已經(jīng)定義了個(gè)分
    發(fā)表于 09-25 13:24

    2017雙11技術(shù)揭秘—TDDL/DRDS 的類 KV 查詢優(yōu)化實(shí)踐

    僅在SQL層面進(jìn)行進(jìn)優(yōu)化會(huì)非常困難,因此針對(duì)這類場(chǎng)景,TDDL/DRDS 配合 AliSQL 提出了全新的解決方案。作者:勵(lì)強(qiáng)(君瑜)場(chǎng)景介紹性能優(yōu)化是企業(yè)級(jí)應(yīng)用永恒的話題,關(guān)系型
    發(fā)表于 12-29 14:29

    阿里云大數(shù)據(jù)MaxCompute計(jì)算資源分布以及LogView分析優(yōu)化

    查詢的執(zhí)行狀態(tài)返回給客戶端。這里主要說下計(jì)算層的MR Job和SQL Job,因?yàn)镺DPS有對(duì)外提供MapReduce編程接口,來訪問ODPS上的數(shù)據(jù),其中MR Job就是用來跑那些
    發(fā)表于 04-26 14:53

    CC2530 廣播 300ms以下就會(huì)產(chǎn)生發(fā)送失敗問題,失敗原因:zBufferFull

    多次測(cè)試發(fā)現(xiàn)芯片在廣播的時(shí)候發(fā)送時(shí)間短于300ms一次的話就會(huì)產(chǎn)生發(fā)送失敗的現(xiàn)象,每9失敗幾次,失敗的原因?yàn)閦BufferFull,而采用單播發(fā)送頻率在30ms以下才會(huì)產(chǎn)生丟包問題,
    發(fā)表于 06-01 00:38

    SQL查詢慢的原因分析總結(jié)

    sql 查詢慢的48個(gè)原因分析 1、沒有索引或者沒有用到索引(這是查詢慢最常見的問題,是程序設(shè)計(jì)的缺陷)。 2、I/O吞吐量小,形成了瓶頸效應(yīng)。 3、沒有創(chuàng)建計(jì)算列導(dǎo)致
    發(fā)表于 03-08 11:58 ?0次下載

    基于關(guān)系代數(shù)樹的查詢優(yōu)化方法實(shí)例分析

    提出了基于關(guān)系代數(shù)樹結(jié)構(gòu)的SQL查詢優(yōu)化策略。利用改進(jìn)查詢計(jì)劃的代數(shù)定律,分析基于關(guān)系代數(shù)樹的關(guān)系代數(shù)式
    發(fā)表于 05-07 10:11 ?21次下載
    基于關(guān)系代數(shù)樹的<b class='flag-5'>查詢</b><b class='flag-5'>優(yōu)化</b>方法實(shí)例<b class='flag-5'>分析</b>

    基于KingView的SQL數(shù)據(jù)查詢設(shè)計(jì)_楊洋

    基于KingView的SQL數(shù)據(jù)查詢設(shè)計(jì)_楊洋
    發(fā)表于 01-17 19:57 ?0次下載

    企業(yè)海量數(shù)據(jù)查詢優(yōu)化

    查詢分析、統(tǒng)計(jì)操作所基于的SELECT語句在SQL語句中又是付出資源代價(jià)最大的語句。舉個(gè)具體的例子,比如個(gè)數(shù)據(jù)庫表有上百萬甚至上千萬條記
    發(fā)表于 12-14 16:40 ?8次下載

    SQL優(yōu)化器原理 - 查詢優(yōu)化器綜述

    摘要:?本文主要是對(duì)數(shù)據(jù)查詢優(yōu)化器的個(gè)綜述,包括查詢優(yōu)化器分類、
    發(fā)表于 07-24 17:38 ?315次閱讀
    <b class='flag-5'>SQL</b><b class='flag-5'>優(yōu)化</b>器原理 - <b class='flag-5'>查詢</b><b class='flag-5'>優(yōu)化</b>器綜述

    SQL查詢優(yōu)化是怎么回事

    查詢 (Subquery)的優(yōu)化直以來都是 SQL 查詢優(yōu)化中的難點(diǎn)之
    的頭像 發(fā)表于 02-01 13:55 ?2012次閱讀
    <b class='flag-5'>SQL</b>子<b class='flag-5'>查詢</b><b class='flag-5'>優(yōu)化</b>是怎么回事

    SQL優(yōu)化思路與經(jīng)典案例分析

    如何定位慢SQL呢、我們可以通過慢查詢日志來查看慢SQL。默認(rèn)的情況下呢,MySQL數(shù)據(jù)庫是不開啟慢查詢日志(slow query log)
    的頭像 發(fā)表于 10-27 13:16 ?890次閱讀

    文終結(jié)SQL查詢優(yōu)化

    查詢(Subquery)的優(yōu)化直以來都是 SQL 查詢優(yōu)化中的難點(diǎn)之
    的頭像 發(fā)表于 04-28 14:19 ?723次閱讀
    <b class='flag-5'>一</b>文終結(jié)<b class='flag-5'>SQL</b>子<b class='flag-5'>查詢</b><b class='flag-5'>優(yōu)化</b>

    Oracle長(zhǎng)耗時(shí)SQL優(yōu)化案例

    最近在生產(chǎn)客服平臺(tái),運(yùn)營(yíng)崗老師反饋,個(gè)2w人的企業(yè),在信息詳情查詢時(shí),加載時(shí)間過長(zhǎng),越70s左右出結(jié)果,需要后臺(tái)優(yōu)化
    的頭像 發(fā)表于 05-19 15:02 ?986次閱讀

    oracle執(zhí)行sql查詢語句的步驟是什么

    Oracle數(shù)據(jù)庫是種常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),具有強(qiáng)大的SQL查詢功能。Oracle執(zhí)行SQL
    的頭像 發(fā)表于 12-06 10:49 ?898次閱讀