91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

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

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

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

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

數(shù)據(jù)分析與開發(fā) ? 來源:未知 ? 2023-04-14 14:27 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

操作:查詢條件放到子查詢中,子查詢只查主鍵ID,然后使用子查詢中確定的主鍵關聯(liá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)

表結構:

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)

我們知道,當limit offset rows中的offset很大時,會出現(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)

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

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)

時間相差很明顯。

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

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

類似于下面這張圖:45d781ce-d8f7-11ed-bfe3-dac502259ad0.jpg

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

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

45ed9680-d8f7-11ed-bfe3-dac502259ad0.jpg

其實我也想問這個問題。

證實

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

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

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

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

預測結果是運行select * from test a inner join (select id from test where val=4 limit 300000,5);之后,buffer pool中的數(shù)據(jù)頁的數(shù)量遠遠少于select * from test where val=4 limit 300000,5;對應的數(shù)量,因為前一個sql只訪問5次數(shù)據(jù)頁,而后一個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中沒有關于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)

可以看出,此時buffer pool中關于test表有4098個數(shù)據(jù)頁,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個數(shù)據(jù)頁到buffer pool,而第二個sql只加載了5個數(shù)據(jù)頁到buffer pool。符合我們的預測。也證實了為什么第一個sql會慢:讀取大量的無用數(shù)據(jù)行(300000),最后卻拋棄掉。而且這會造成一個問題:加載了很多熱點不是很高的數(shù)據(jù)頁到buffer pool,會造成buffer pool的污染,占用buffer pool的空間。遇到的問題

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

審核編輯 :李倩


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

    關注

    8

    文章

    7335

    瀏覽量

    94754
  • SQL
    SQL
    +關注

    關注

    1

    文章

    789

    瀏覽量

    46695
  • 數(shù)據(jù)庫

    關注

    7

    文章

    4019

    瀏覽量

    68337

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

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

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    文了解MyBatis的查詢原理

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

    ADS1232信號輸入零點滿度兩點變化,其數(shù)據(jù)建立過程需要兩轉(zhuǎn)換,為什么?

    ADS1232信號輸入零點滿度兩點變化(用的是信號模擬器),發(fā)現(xiàn)其數(shù)據(jù)建立過程需要兩
    發(fā)表于 01-10 08:02

    鴻蒙5開發(fā)寶藏案例分享---優(yōu)化應用時延問題

    ;gt; this.data = result) } 效果 : 4000條數(shù)據(jù) 780ms → 172ms ! 注意 :小于1000條數(shù)據(jù)
    發(fā)表于 06-13 10:08

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

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

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

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

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

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

    SQL查詢慢的原因分析總結

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

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

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

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

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

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

    摘要:?本文主要是對數(shù)據(jù)查詢優(yōu)化器的個綜述,包括查詢優(yōu)化器分類、
    發(fā)表于 07-24 17:38 ?550次閱讀
    <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)化中的難點之
    的頭像 發(fā)表于 02-01 13:55 ?2739次閱讀
    <b class='flag-5'>SQL</b>子<b class='flag-5'>查詢</b><b class='flag-5'>優(yōu)化</b>是怎么回事

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

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

    Oracle長耗時SQL優(yōu)化案例

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

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

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

    數(shù)據(jù)庫慢查詢分析SQL優(yōu)化實戰(zhàn)技巧

    今天,我將分享我在處理數(shù)千次數(shù)據(jù)庫性能問題中積累的實戰(zhàn)經(jīng)驗,幫助你系統(tǒng)掌握慢查詢分析SQL優(yōu)化的核心技巧。無論你是剛入門的運維新手,還是有
    的頭像 發(fā)表于 09-08 09:34 ?974次閱讀