成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

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

一次SQL查詢優化原理分析(900W+數據從17s到300ms)

瀏覽:308日期:2023-03-06 14:25:18
目錄
  • 前言
  • 證實
  • 參考資料:

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

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

原理:1、減少回表操作;
2、可參考《阿里巴巴Java開發手冊(泰山版)》第五章-MySQL數據庫、(二)索引規約、第7條:
【推薦】利用延遲關聯或者子查詢優化超多分頁場景。
說明: MySQL并不是挑過offeset行,而是取offset+N行,然后返回放棄前offset行,返回N行,那當offset特別大的時候,效率就非常的底下,要么控制返回的總頁數,要么對超過特定閾值的頁數進行SQL改寫。
正例: 先快速定位需要獲取的id段,然后再關聯:
SELECT a.* FROM 表1 a,(select id from 表1 where 條件 LIMIT 100000,20) b where a.id = b.id;

-- 優化前SQLSELECT  各種字段FROM `table_name`WHERE 各種條件LIMIT 0,10;
-- 優化后SQLSELECT  各種字段FROM `table_name` main_taleRIGHT JOIN (SELECT  子查詢只查主鍵FROM `table_name`WHERE 各種條件LIMIT 0,10;) temp_table ON temp_table.主鍵 = main_table.主鍵

前言

首先說明一下MySQL的版本:

mysql> select version();+-----------+| version() |+-----------+| 5.7.17    |+-----------+1 row in set (0.00 sec)

表結構:

mysql> desc test;+--------+---------------------+------+-----+---------+----------------+| 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       ||+--------+---------------------+------+-----+---------+----------------+3 rows in set (0.00 sec)

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

灌入大量數據,共500萬:

mysql> select count(*) from test;+----------+| count(*) |+----------+|  5242882 |+----------+1 row in set (4.25 sec)

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

mysql> select * from test where val=4 limit 300000,5;+---------+-----+--------+| id      | val | source |+---------+-----+--------+| 3327622 |   4 |      4 || 3327632 |   4 |      4 || 3327642 |   4 |      4 || 3327652 |   4 |      4 || 3327662 |   4 |      4 |+---------+-----+--------+5 rows in set (15.98 sec)

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

mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.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 |+---------+-----+--------+---------+5 rows in set (0.38 sec)

時間相差很明顯。

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

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

類似于下面這張圖:

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

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

其實我也想問這個問題。

證實

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

為了證實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 * from test where val=4 limit 300000,5
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in("val","primary") and TABLE_NAME like "%test%" group by index_name;Empty set (0.04 sec)

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

mysql> select * from test where val=4 limit 300000,5;+---------+-----+--------+| id      | val | source |+---------+-----+--------+| 3327622 |   4 |      4 || 3327632 |   4 |      4 || 3327642 |   4 |      4 || 3327652 |   4 |      4 || 3327662 |   4 |      4 |+---------+-----+--------+5 rows in set (26.19 sec)mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in("val","primary") and TABLE_NAME like "%test%" group by index_name;+------------+----------+| index_name | count(*) |+------------+----------+| PRIMARY    |     4098 || val|      208 |+------------+----------+2 rows in set (0.04 sec)

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

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

mysqladmin shutdown/usr/local/bin/mysqld_safe &
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in("val","primary") and TABLE_NAME like "%test%" group by index_name;Empty set (0.03 sec)

運行sql:

mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.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 |+---------+-----+--------+---------+5 rows in set (0.09 sec)mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in("val","primary") and TABLE_NAME like "%test%" group by index_name;+------------+----------+| index_name | count(*) |+------------+----------+| PRIMARY    |5 || val|      390 |+------------+----------+2 rows in set (0.03 sec)

我們可以看明顯的看出兩者的差別:第一個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的數據。

參考資料:

1.https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/

2.https://dev.mysql.com/doc/refman/5.7/en/innodb-information-schema-buffer-pool-tables.html

到此這篇關于一次SQL查詢優化原理分析(900W+數據從17s到300ms)的文章就介紹到這了,更多相關SQL查詢優化內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持!

標簽: MsSQL
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
一区二区三区鲁丝不卡| 亚洲激情av| 国产一区激情| 久久你懂得1024| 福利一区福利二区| 欧美日本不卡视频| 加勒比av一区二区| 欧美三级午夜理伦三级中视频| 日韩高清国产一区在线| 色综合激情久久| 日韩精品国产精品| 色伊人久久综合中文字幕| 日韩国产一二三区| 在线视频国产一区| 蜜臀av一级做a爰片久久| 91国偷自产一区二区三区观看| 一区二区三国产精华液| 一区二区三区导航| 亚洲一区二区欧美激情| 久久精品国产清高在天天线| 亚洲国产美女搞黄色| 久久福利精品| 亚洲国产精品麻豆| 久久人人97超碰人人澡爱香蕉 | 午夜电影网一区| 久久久久综合| 久久精品国产精品亚洲红杏| 欧美日韩高清在线| 国产激情一区二区三区桃花岛亚洲| 51久久夜色精品国产麻豆| 国产在线一区观看| 精品国产1区二区| 欧美日韩喷水| 日韩理论电影院| 母乳一区在线观看| 免费成人在线网站| 欧美日韩国产大片| www.激情成人| 亚洲女人的天堂| 久久亚洲风情| 国产一区二区三区高清播放| 久久综合色综合88| 亚洲国产综合在线看不卡| 亚洲大片在线观看| 欧美日韩一区二区在线观看| 国产一区二区三区四区五区入口| 日韩精品专区在线| 欧美国产高潮xxxx1819| 亚洲精品少妇30p| 欧美自拍偷拍午夜视频| 成人污污视频在线观看| 中文字幕不卡三区| 国产九区一区在线| 麻豆精品国产传媒mv男同| 日韩午夜在线观看视频| 午夜精品免费| 亚洲成在人线在线播放| 欧美二区乱c少妇| 欧美三级午夜理伦三级中文幕| 一区二区三区在线播放| 日本乱人伦aⅴ精品| 成人激情小说网站| 亚洲欧美日韩在线播放| 欧美午夜精品久久久久久超碰| www.成人网.com| 亚洲一区二区中文在线| 欧美日韩一区国产| 欧美黄污视频| 日本成人在线不卡视频| 精品福利一区二区三区| 亚洲每日在线| 精品系列免费在线观看| 欧美韩国一区二区| 一本在线高清不卡dvd| 99免费精品视频| 一区二区不卡在线播放 | 青青草伊人久久| 精品欧美乱码久久久久久1区2区| 激情婷婷欧美| 精品在线播放午夜| 国产精品乱码一区二三区小蝌蚪| 色婷婷av一区二区三区gif| 99国产精品视频免费观看| 亚洲第一狼人社区| 久久影音资源网| 色婷婷国产精品| 91网站最新地址| 亚洲成人免费视| 日韩精品一区二区三区中文不卡| 99精品国产高清一区二区| 国产专区欧美精品| 亚洲欧洲av一区二区三区久久| 欧美日韩精品二区第二页| 激情综合自拍| 国产精品一区专区| 亚洲欧美日本在线| 欧美一二三在线| 国产精品女主播一区二区三区| 粉嫩一区二区三区在线看| 亚洲一区在线观看免费| 337p粉嫩大胆噜噜噜噜噜91av| 亚洲综合国产| 91在线观看一区二区| 日本亚洲电影天堂| 国产精品高潮呻吟| 欧美一级夜夜爽| 久久国产精品亚洲va麻豆| 91美女蜜桃在线| 久久精品国产精品青草| 亚洲日本va午夜在线电影| 欧美大度的电影原声| 色婷婷综合激情| 亚洲第一精品影视| www.欧美日韩| 久久精工是国产品牌吗| 亚洲免费av观看| 精品卡一卡二卡三卡四在线| 久久99伊人| 国一区二区在线观看| 国产精品 日产精品 欧美精品| 午夜激情久久久| 亚洲乱码中文字幕综合| 久久久噜噜噜久久人人看 | 日韩一区二区三| 久久一区中文字幕| 伊人精品在线| 色综合欧美在线| 国产suv精品一区二区三区| 午夜电影网亚洲视频| 国产精品免费视频一区| 日韩一区二区精品葵司在线| 老司机午夜免费精品视频| 亚洲一二三区精品| 99久久亚洲一区二区三区青草| 精品制服美女丁香| 亚洲国产三级在线| 亚洲人成网站在线| 国产欧美一区二区精品性色超碰 | 亚洲综合久久久| 欧美激情一区二区| 精品国产乱码久久久久久夜甘婷婷| 欧美亚洲动漫另类| 久久午夜av| 国产亚洲一区在线| 在线看片日韩| 欧美一区高清| 成人国产精品免费观看| 国产一区二区免费在线| 青娱乐精品视频| 日韩专区一卡二卡| 亚洲影视在线观看| 亚洲精品国产成人久久av盗摄| 国产精品色噜噜| 国产欧美一区二区精品秋霞影院 | 久久伊99综合婷婷久久伊| 日韩一级片网址| 欧美精品99久久久**| 欧美三级中文字| 欧美日韩视频在线第一区| 色就色 综合激情| 久久综合狠狠| 久久激情一区| 久久久综合香蕉尹人综合网| 小嫩嫩精品导航| 久久久久久色| 色欧美88888久久久久久影院| 久久亚洲不卡| 欧美色区777第一页| 日本高清无吗v一区| 久热这里只精品99re8久| 国产亚洲欧美另类一区二区三区| 亚洲狠狠婷婷| 夜夜爽99久久国产综合精品女不卡| 国内精品美女在线观看| 欧美视频官网| 国模大胆一区二区三区| 影音先锋在线一区| 99精品99| 久久精品二区| 欧美日韩一级片网站| 欧美精品一二三区| 日韩欧美国产精品| 久久久国产精品麻豆| 国产日韩欧美一区二区三区综合| 国产丝袜在线精品| ...xxx性欧美| 亚洲成人av资源| 日韩国产欧美视频| 久久99久久99小草精品免视看| 精东粉嫩av免费一区二区三区| 激情伊人五月天久久综合| 国产福利91精品| 91麻豆免费看| 亚洲福利免费| 久久精品国产清高在天天线 | 亚洲欧洲av另类| 亚洲图片激情小说| 亚洲成人免费视频| 狠狠色综合日日| 北条麻妃国产九九精品视频|