日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

遇到上亿(MySQL)大表的优化....

發(fā)布時間:2025/3/20 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 遇到上亿(MySQL)大表的优化.... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

點(diǎn)擊上方?好好學(xué)java?,選擇?星標(biāo)?公眾號

重磅資訊、干貨,第一時間送達(dá)

今日推薦:Nginx 為什么快到根本停不下來?

個人原創(chuàng)100W+訪問量博客:點(diǎn)擊前往,查看更多

前段時間剛?cè)肼氁患夜?#xff0c;就遇上這事!

背景

XX實(shí)例(一主一從)xxx告警中每天凌晨在報SLA報警,該報警的意思是存在一定的主從延遲(若在此時發(fā)生主從切換,需要長時間才可以完成切換,要追延遲來保證主從數(shù)據(jù)的一致性)

XX實(shí)例的慢查詢數(shù)量最多(執(zhí)行時間超過1s的sql會被記錄),XX應(yīng)用那方每天晚上在做刪除一個月前數(shù)據(jù)的任務(wù)

分析

使用pt-query-digest工具分析最近一周的mysql-slow.log

pt-query-digest --since=148h mysql-slow.log?| less

結(jié)果第一部分

最近一個星期內(nèi),總共記錄的慢查詢執(zhí)行花費(fèi)時間為25403s,最大的慢sql執(zhí)行時間為266s,平均每個慢sql執(zhí)行時間5s,平均掃描的行數(shù)為1766萬

結(jié)果第二部分

select arrival_record操作記錄的慢查詢數(shù)量最多有4萬多次,平均響應(yīng)時間為4s,delete arrival_record記錄了6次,平均響應(yīng)時間258s。

select xxx_record語句

select arrival_record 慢查詢語句都類似于如下所示,where語句中的參數(shù)字段是一樣的,傳入的參數(shù)值不一樣
select count(*) from arrival_record where product_id=26 and receive_time between '2019-03-25 14:00:00' and '2019-03-25 15:00:00' and receive_spend_ms>=0\G


select arrival_record 語句在mysql中最多掃描的行數(shù)為5600萬、平均掃描的行數(shù)為172萬,推斷由于掃描的行數(shù)多導(dǎo)致的執(zhí)行時間長

查看執(zhí)行計劃

explain select?count(*) from?arrival_record where?product_id=26?and receive_time between '2019-03-25 14:00:00'?and '2019-03-25 15:00:00'?and receive_spend_ms>=0\G; *************************** 1.?row *************************** id: 1 select_type: SIMPLE table: arrival_record partitions: NULL type: ref possible_keys: IXFK_arrival_record key: IXFK_arrival_record key_len: 8 ref: const rows: 32261320 filtered: 3.70 Extra: Using index condition; Using where 1?row in?set, 1?warning (0.00?sec)

用到了索引IXFK_arrival_record,但預(yù)計掃描的行數(shù)很多有3000多w行

show index from arrival_record; +----------------+------------+---------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table |?Non_unique | Key_name |?Seq_in_index | Column_name |?Collation | Cardinality |?Sub_part | Packed |?Null | Index_type |?Comment | Index_comment | +----------------+------------+---------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | arrival_record |?0?| PRIMARY |?1?| id |?A | 107990720 |?NULL | NULL |?| BTREE |?| | | arrival_record |?1?| IXFK_arrival_record |?1?| product_id |?A | 1344 |?NULL | NULL |?| BTREE |?| | | arrival_record |?1?| IXFK_arrival_record |?2?| station_no |?A | 22161 |?NULL | NULL |?YES | BTREE |?| | | arrival_record |?1?| IXFK_arrival_record |?3?| sequence |?A | 77233384 |?NULL | NULL |?| BTREE |?| | | arrival_record |?1?| IXFK_arrival_record |?4?| receive_time |?A | 65854652 |?NULL | NULL |?YES | BTREE |?| | | arrival_record |?1?| IXFK_arrival_record |?5?| arrival_time |?A | 73861904 |?NULL | NULL |?YES | BTREE |?| | +----------------+------------+---------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ show create table arrival_record; .......... arrival_spend_ms bigint(20) DEFAULT NULL, total_spend_ms bigint(20) DEFAULT NULL, PRIMARY KEY (id), KEY IXFK_arrival_record (product_id,station_no,sequence,receive_time,arrival_time) USING BTREE, CONSTRAINT FK_arrival_record_product FOREIGN KEY (product_id) REFERENCES product (id) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=614538979?DEFAULT CHARSET=utf8 COLLATE=utf8_bin |
  • 該表總記錄數(shù)約1億多條,表上只有一個復(fù)合索引,product_id字段基數(shù)很小,選擇性不好

  • 傳入的過濾條件 where product_id=26 and receive_time between '2019-03-25 14:00:00' and '2019-03-25 15:00:00' and receive_spend_ms>=0 沒有station_nu字段,使用不到復(fù)合索引 IXFK_arrival_record的?product_id,station_no,sequence,receive_time?這幾個字段

  • 根據(jù)最左前綴原則,select arrival_record只用到了復(fù)合索引IXFK_arrival_record的第一個字段product_id,而該字段選擇性很差,導(dǎo)致掃描的行數(shù)很多,執(zhí)行時間長

  • receive_time字段的基數(shù)大,選擇性好,可對該字段單獨(dú)建立索引,select arrival_record sql就會使用到該索引

現(xiàn)在已經(jīng)知道了在慢查詢中記錄的select arrival_record where語句傳入的參數(shù)字段有 product_id,receive_time,receive_spend_ms,還想知道對該表的訪問有沒有通過其它字段來過濾了?


神器tcpdump出場的時候到了

使用tcpdump抓包一段時間對該表的select語句

tcpdump -i bond0 -s 0?-l?-w?- dst port 3316?| strings | grep?select | egrep -i 'arrival_record'?>/tmp/select_arri.log

獲取select 語句中from 后面的where條件語句

IFS_OLD=$IFS IFS=$'\n' for?i in?`cat /tmp/select_arri.log `;do?echo?${i#*'from'}; done?| less IFS=$IFS_OLDarrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=17?and?arrivalrec0_.station_no='56742' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=22?and?arrivalrec0_.station_no='S7100' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=24?and?arrivalrec0_.station_no='V4631' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=22?and?arrivalrec0_.station_no='S9466' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=24?and?arrivalrec0_.station_no='V4205' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=24?and?arrivalrec0_.station_no='V4105' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=24?and?arrivalrec0_.station_no='V4506' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=24?and?arrivalrec0_.station_no='V4617' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=22?and?arrivalrec0_.station_no='S8356' arrival_record arrivalrec0_ where arrivalrec0_.sequence='2019-03-27 08:40'?and?arrivalrec0_.product_id=22?and?arrivalrec0_.station_no='S8356' select 該表 where條件中有product_id,station_no,sequence字段,可以使用到復(fù)合索引IXFK_arrival_record的前三個字段

綜上所示,優(yōu)化方法為,刪除復(fù)合索引IXFK_arrival_record,建立復(fù)合索引idx_sequence_station_no_product_id,并建立單獨(dú)索引indx_receive_time

delete xxx_record語句

該delete操作平均掃描行數(shù)為1.1億行,平均執(zhí)行時間是262s

delete語句如下所示,每次記錄的慢查詢傳入的參數(shù)值不一樣

delete?from?arrival_record where?receive_time < STR_TO_DATE('2019-02-23', '%Y-%m-%d')\G

執(zhí)行計劃

explain?select?* from?arrival_record where?receive_time < STR_TO_DATE('2019-02-23', '%Y-%m-%d')\G *************************** 1.?row?*************************** id: 1 select_type: SIMPLE table: arrival_record partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 109501508 filtered: 33.33 Extra: Using?where 1?row?in?set, 1?warning?(0.00?sec)

該delete語句沒有使用索引(沒有合適的索引可用),走的全表掃描,導(dǎo)致執(zhí)行時間長

優(yōu)化方法也是 建立單獨(dú)索引indx_receive_time(receive_time)

測試

拷貝arrival_record表到測試實(shí)例上進(jìn)行刪除重新索引操作
XX實(shí)例arrival_record表信息

du -sh /datas/mysql/data/3316/cq_new_cimiss/arrival_record* 12K /datas/mysql/data/3316/cq_new_cimiss/arrival_record.frm 48G /datas/mysql/data/3316/cq_new_cimiss/arrival_record.ibd select count() from cq_new_cimiss.arrival_record; +-----------+ | count() | +-----------+ | 112294946 | +-----------+ 1億多記錄數(shù)SELECT table_name, CONCAT(FORMAT(SUM(data_length) / 1024?/ 1024,2),'M') AS dbdata_size, CONCAT(FORMAT(SUM(index_length) / 1024?/ 1024,2),'M') AS dbindex_size, CONCAT(FORMAT(SUM(data_length + index_length) / 1024?/ 1024?/ 1024,2),'G') AS table_size(G), AVG_ROW_LENGTH,table_rows,update_time FROM information_schema.tables WHERE table_schema = 'cq_new_cimiss'?and?table_name='arrival_record'; +----------------+-------------+--------------+------------+----------------+------------+---------------------+ | table_name |?dbdata_size | dbindex_size |?table_size(G) | AVG_ROW_LENGTH |?table_rows | update_time | +----------------+-------------+--------------+------------+----------------+------------+---------------------+ | arrival_record |?18,268.02M | 13,868.05M |?31.38G | 175 |?109155053?| 2019-03-26 12:40:17 | +----------------+-------------+--------------+------------+----------------+------------+---------------------+

磁盤占用空間48G,mysql中該表大小為31G,存在17G左右的碎片,大多由于刪除操作造成的(記錄被刪除了,空間沒有回收)


備份還原該表到新的實(shí)例中,刪除原來的復(fù)合索引,重新添加索引進(jìn)行測試

mydumper并行壓縮備份

user=root passwd=xxxx socket=/datas/mysql/data/3316/mysqld.sock db=cq_new_cimiss table_name=arrival_record backupdir=/datas/dump_$table_name mkdir -p $backupdir?nohup echo `date +%T`?&& mydumper -u $user -p $passwd -S $socket -B $db -c -T $table_name -o $backupdir -t 32?-r 2000000?&& echo `date +%T`?&

并行壓縮備份所花時間(52s)和占用空間(1.2G,實(shí)際該表占用磁盤空間為48G,mydumper并行壓縮備份壓縮比相當(dāng)高!)

Started?dump?at: 2019-03-26?12:46:04 ........Finished?dump?at: 2019-03-26?12:46:56du?-sh???/datas/dump_arrival_record/ 1.2G??/datas/dump_arrival_record/

拷貝dump數(shù)據(jù)到測試節(jié)點(diǎn)

scp -rp /datas/dump_arrival_record root@10.230.124.19:/datas

多線程導(dǎo)入數(shù)據(jù)

time myloader -u root -S /datas/mysql/data/3308/mysqld.sock -P 3308 -p root -B test?-d /datas/dump_arrival_record -t 32

real 126m42.885s
user 1m4.543s
sys 0m4.267s

邏輯導(dǎo)入該表后磁盤占用空間

du -h -d 1 /datas/mysql/data/3308/test/arrival_record.* 12K /datas/mysql/data/3308/test/arrival_record.frm 30G /datas/mysql/data/3308/test/arrival_record.ibd 沒有碎片,和mysql的該表的大小一致cp?-rp /datas/mysql/data/3308?/datas

分別使用online DDL和 pt-osc工具來做刪除重建索引操作
先刪除外鍵,不刪除外鍵,無法刪除復(fù)合索引,外鍵列屬于復(fù)合索引中第一列

nohup bash /tmp/ddl_index.sh & 2019-04-04-10:41:39 begin?stop?mysqld_3308 2019-04-04-10:41:41?begin?rm -rf datadir and?cp -rp datadir_bak 2019-04-04-10:46:53?start?mysqld_3308 2019-04-04-10:46:59?online?ddl?begin 2019-04-04-11:20:34?onlie ddl?stop 2019-04-04-11:20:34?begin?stop?mysqld_3308 2019-04-04-11:20:36?begin?rm -rf datadir and?cp -rp datadir_bak 2019-04-04-11:22:48?start?mysqld_3308 2019-04-04-11:22:53?pt-osc begin 2019-04-04-12:19:15?pt-osc stop online?ddl?花費(fèi)時間為34?分鐘,pt-osc花費(fèi)時間為57?分鐘,使用onlne ddl時間約為pt-osc工具時間的一半

做DDL 參考

實(shí)施

由于是一主一從實(shí)例,應(yīng)用是連接的vip,刪除重建索引采用online ddl來做。停止主從復(fù)制后,先在從實(shí)例上做(不記錄binlog),主從切換,再在新切換的從實(shí)例上做(不記錄binlog)

function red_echo () {local what="$*"echo -e "$(date +%F-%T) ${what}" }function check_las_comm(){if [ "$1" != "0" ];thenred_echo "$2"echo "exit 1"exit 1fi }red_echo "stop slave" mysql -uroot -p$passwd --socket=/datas/mysql/data/${port}/mysqld.sock -e"stop slave" check_las_comm "$?" "stop slave failed"red_echo "online ddl begin"mysql -uroot -p$passwd --socket=/datas/mysql/data/${port}/mysqld.sock -e"set sql_log_bin=0;select now() as ddl_start;ALTER TABLE $db_.\`${table_name}\` DROP FOREIGN KEY FK_arrival_record_product,drop index IXFK_arrival_record,add index idx_product_id_sequence_station_no(product_id,sequence,station_no),add index idx_receive_time(receive_time);select now() as ddl_stop" >>${log_file} 2>& 1red_echo "onlie ddl stop"red_echo "add foreign key"mysql -uroot -p$passwd --socket=/datas/mysql/data/${port}/mysqld.sock -e"set sql_log_bin=0;ALTER TABLE $db_.${table_name} ADD CONSTRAINT _FK_${table_name}_product FOREIGN KEY (product_id) REFERENCES cq_new_cimiss.product (id) ON DELETE NO ACTION ON UPDATE NO ACTION;" >>${log_file} 2>& 1check_las_comm "$?" "add foreign key error"red_echo "add foreign key stop"red_echo "start slave" mysql -uroot -p$passwd --socket=/datas/mysql/data/${port}/mysqld.sock -e"start slave" check_las_comm "$?" "start slave failed"

執(zhí)行時間

2019-04-08-11:17:36 stop slave
mysql: [Warning] Using a password on the command line interface can be insecure.
ddl_start
2019-04-08?11:17:36
ddl_stop
2019-04-08?11:45:13
2019-04-08-11:45:13 onlie ddl stop
2019-04-08-11:45:13?add foreign key
mysql: [Warning] Using a password on the command line interface can be insecure.
2019-04-08-12:33:48 add foreign key stop
2019-04-08-12:33:48?start slave

再次查看delete 和select語句的執(zhí)行計劃

explain select?count(*) from?arrival_record where?receive_time < STR_TO_DATE('2019-03-10', '%Y-%m-%d')\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: arrival_record partitions: NULL type: range possible_keys: idx_receive_time key: idx_receive_time key_len: 6 ref: NULL rows: 7540948 filtered: 100.00 Extra: Using where; Using index explain select?count(*) from?arrival_record where?product_id=26?and receive_time between '2019-03-25 14:00:00'?and '2019-03-25 15:00:00'?and receive_spend_ms>=0\G; *************************** 1.?row *************************** id: 1 select_type: SIMPLE table: arrival_record partitions: NULL type: range possible_keys: idx_product_id_sequence_station_no,idx_receive_time key: idx_receive_time key_len: 6 ref: NULL rows: 291448 filtered: 16.66 Extra: Using index condition; Using where 都使用到了idx_receive_time 索引,掃描的行數(shù)大大降低

索引優(yōu)化后

delete 還是花費(fèi)了77s時間

delete?from?arrival_record where?receive_time < STR_TO_DATE('2019-03-10', '%Y-%m-%d')\G

delete 語句通過receive_time的索引刪除300多萬的記錄花費(fèi)77s時間*

delete大表優(yōu)化為小批量刪除

應(yīng)用端已優(yōu)化成每次刪除10分鐘的數(shù)據(jù)(每次執(zhí)行時間1s左右),xxx中沒在出現(xiàn)SLA(主從延遲告警)

另一個方法是通過主鍵的順序每次刪除20000條記錄

#得到滿足時間條件的最大主鍵ID #通過按照主鍵的順序去 順序掃描小批量刪除數(shù)據(jù) #先執(zhí)行一次以下語句SELECT MAX(id) INTO @need_delete_max_id FROM `arrival_record` WHERE receive_time<'2019-03-01' ;DELETE FROM arrival_record WHERE id<@need_delete_max_id LIMIT 20000;select ROW_COUNT(); #返回20000#執(zhí)行小批量delete后會返回row_count(), 刪除的行數(shù) #程序判斷返回的row_count()是否為0,不為0執(zhí)行以下循環(huán),為0退出循環(huán),刪除操作完成DELETE FROM arrival_record WHERE id<@need_delete_max_id LIMIT 20000;select ROW_COUNT(); #程序睡眠0.5s

總結(jié)

  • 表數(shù)據(jù)量太大時,除了關(guān)注訪問該表的響應(yīng)時間外,還要關(guān)注對該表的維護(hù)成本(如做DDL表更時間太長,delete歷史數(shù)據(jù))。

  • 對大表進(jìn)行DDL操作時,要考慮表的實(shí)際情況(如對該表的并發(fā)表,是否有外鍵)來選擇合適的DDL變更方式。

  • 對大數(shù)據(jù)量表進(jìn)行delete,用小批量刪除的方式,減少對主實(shí)例的壓力和主從延遲。

作者:jia-xin

原文:https://www.cnblogs.com/YangJiaXin/p/10828244.html

最后,再附上我歷時三個月總結(jié)的?Java 面試 + Java 后端技術(shù)學(xué)習(xí)指南,筆者這幾年及春招的總結(jié),github 1.4k star,拿去不謝!下載方式1.?首先掃描下方二維碼 2.?后臺回復(fù)「Java面試」即可獲取

總結(jié)

以上是生活随笔為你收集整理的遇到上亿(MySQL)大表的优化....的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 自拍偷拍色综合 | 美女视频黄的免费 | 爱情岛论坛成人av | 初尝人妻少妇中文字幕 | 国产色中色 | 免费看大片a | 欧美日韩高清丝袜 | 日韩av在线网址 | 超碰成人97 | 视频一区二区三 | 久久久久久久久久久91 | 在线免费精品视频 | 成人高清视频免费观看 | 欧美日韩亚洲国产精品 | 在线观看免费高清视频 | 丰满少妇高潮一区二区 | 黄色一级片国产 | 一级大片儿 | 成人免费版 | 丁香久久婷婷 | 欧美a级免费| 国产最新视频在线 | 日韩伦理大全 | 高清国产一区二区三区四区五区 | 成人国产在线 | 老司机在线看片 | 三级网站免费看 | 性色av一区二区三区 | 国产精品一区二区麻豆 | 午夜影院91 | 色婷婷av一区二区三区之e本道 | 麻豆理论片 | 日韩精品播放 | 色综合社区 | 91看片在线看 | 女人扒开腿免费视频app | 成人区人妻精品一区 | 特级西西人体wwwww | www.777色 | 在线免费 | 91黑人精品一区二区三区 | 成人黄色片网站 | 国产精品综合视频 | 大胸美女啪啪 | 亚洲成人中文 | 欧美色综合色 | 91亚洲视频在线观看 | 国产黄色影院 | 加勒比hezyo黑人专区 | 91插插插插插 | 国产精品成久久久久三级 | a天堂中文网 | 亚洲网站一区 | 艳妇臀荡乳欲伦交换在线播放 | www黄色大片 | 日韩精品一级 | 亚洲欧洲日韩 | 亚洲男人天堂网 | 天堂久久久久久 | 久青草免费视频 | 爱爱小视频网站 | 欧美呦呦 | 成人你懂的 | 久久亚洲精品中文字幕 | 一级黄色片一级黄色片 | 亚洲午夜精品久久久久久浪潮 | 五月激情丁香网 | 中文字幕+乱码+中文乱码91 | 无码人妻aⅴ一区二区三区有奶水 | 日韩精品成人免费观看视频 | 国产一区二区在线免费观看视频 | 爱豆国产剧免费观看大全剧集 | 大香伊人| 少妇闺蜜换浪荡h肉辣文 | 好姑娘在线观看高清完整版电影 | 日本a级片在线播放 | 在线精品一区二区三区 | 国产美女在线精品 | 成人 黄 色 免费播放 | 国产麻豆电影在线观看 | 国产伦精品一区二区三区视频黑人 | 在线观看亚洲网站 | 香蕉伊人网 | 五月婷六月 | 亚洲一卡二卡在线观看 | 国产三级在线播放 | 欧洲美女av | 鲁大师私人影院在线观看 | 九九色网 | 亚洲AV无码AV吞精久久中文版 | 黄色网页免费在线观看 | 波多野结衣不卡 | 午夜激情av在线 | 久久久久久久福利 | 日本一区二区不卡在线 | 欧美性xxxxx极品娇小 | 97福利社| 美国黄色片网站 | 日批黄色 |