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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

数据库

mysql 复制表耗时_聊一下mysql的表复制

發(fā)布時(shí)間:2024/8/5 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 复制表耗时_聊一下mysql的表复制 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 insert...from的問(wèn)題

insert … select 是很常見(jiàn)的在兩個(gè)表之間拷貝數(shù)據(jù)的方法。需要注意,在可重復(fù)讀隔離級(jí)別下,這個(gè)語(yǔ)句會(huì)給

select的表里掃描到的記錄和間隙加讀鎖。

以下對(duì)insert...select 進(jìn)行一下測(cè)試

全表讀或主鍵排序讀

sessionA

mysql> insert into trajectory_min_section_0511_copy select * from trajectory_min_section_0511;

sessionB

mysql> show engine innodb status;

1451 lock struct(s), heap size 155856, 121231 row lock(s), undo log entries 119783

mysql> show engine innodb status;

3088 lock struct(s), heap size 303312, 258340 row lock(s), undo log entries 255254

mysql> show engine innodb status;

15004 lock struct(s), heap size 1466576, 1256305 row lock(s), undo log entries 1241304

終止sessionA后

sessionB

mysql> show engine innodb status;

ROLLING BACK 23737 lock struct(s), heap size 2302160, 1987628 row lock(s), undo log entries 471818

mysql> show engine innodb status;

ROLLING BACK 23737 lock struct(s), heap size 2302160, 1987628 row lock(s), undo log entries 20019

通過(guò)測(cè)試可以看到row locks是一個(gè)慢慢增長(zhǎng)的過(guò)程。undo log entries也在一直增長(zhǎng),這個(gè)的作用是為了rollback恢復(fù)。

用主鍵升序插入以及用主鍵降序插入:

select * from trajectory_min_section_0511 order id(PK) ASC

select * from trajectory_min_section_0511 order id(PK) DESC

也是一樣的效果,感興趣的可以測(cè)試一下。

從上面測(cè)試可知:通過(guò)主鍵排序或則不加排序字段的導(dǎo)入操作"insert into A select * from B",是會(huì)鎖B表,但他的鎖是逐步地鎖定已經(jīng)掃描過(guò)的記錄。

當(dāng)終止后可以看到undo log entries數(shù)量慢慢降下去

非主鍵排序讀

sessionA

mysql> insert into trajectory_min_section_0511_copy select * from trajectory_min_section_0511 order by t_distance desc;

sessionB

sessionA執(zhí)行過(guò)程中執(zhí)行n次

mysql> show engine innodb status;

63595 lock struct(s), heap size 6168784, 5325513 row lock(s), undo log entries 5118624

從上面測(cè)試可知:非主鍵排序的導(dǎo)入操作,是會(huì)鎖表,而且糟糕的是,鎖是一開(kāi)始就會(huì)鎖定整張表。

讀寫(xiě)驗(yàn)證

sessionA

mysql> insert into trajectory_min_section_0511_copy select * from trajectory_min_section_0511;

sessionB

mysql> select * from trajectory_min_section_0511 where id=1715

搜索靠前主鍵數(shù)據(jù)可以正常返回

mysql> update trajectory_min_section_0511 set direction=2 where id=1715

更新靠前主鍵數(shù)據(jù)超時(shí)無(wú)法返回

sessionA

mysql> insert into trajectory_min_section_0511_copy select * from trajectory_min_section_0511 order by id desc;

sessionB

mysql> select * from trajectory_min_section_0511 where id=9999

搜索靠后主鍵數(shù)據(jù)可以正常返回

mysql> update trajectory_min_section_0511 set direction=2 where id=1715

更新靠后主鍵數(shù)據(jù)超時(shí)無(wú)法返回

以上測(cè)試在上鎖過(guò)程中,不能dml操作任何被上鎖的行,直到鎖釋放。

如果已知對(duì)源表的掃描行數(shù)和加鎖范圍很小的話(huà),簡(jiǎn)單地使用insert … select 語(yǔ)句即可實(shí)現(xiàn)。如果對(duì)線上重點(diǎn)表遷移,為了避免對(duì)源表加讀鎖,更穩(wěn)妥

的方案是先將數(shù)據(jù)寫(xiě)到外部文本文件,然后再寫(xiě)回目標(biāo)表。

2 高效加載數(shù)據(jù)

提高寫(xiě)入、加載速度的幾個(gè)原則,這些原則在任何數(shù)據(jù)庫(kù)上都是通用的:

把數(shù)據(jù)從緩存刷新到磁盤(pán)次數(shù)越少,數(shù)據(jù)加載的越快。因此,批量加載一定是比單條加載效率更高,因?yàn)榕坎迦氲男锌梢韵刃芯彺?#xff0c;然后在

加載操作時(shí)候一次性刷到磁盤(pán)上,減少磁盤(pán)的隨機(jī)讀操作。

表的索引越少,加載速度越快,如果表有多個(gè)列存在索引,每次插入都需要更新所有索引完后才會(huì)識(shí)別到新的行加入。所以不要建無(wú)謂的索引。

短sql比長(zhǎng)sql加載速度更快,因?yàn)樵诜?wù)器上解析操作耗時(shí)更少,并且可以更快的通過(guò)網(wǎng)絡(luò)發(fā)送到服務(wù)器。

加載數(shù)據(jù)一般有insert和load兩種,接下來(lái)詳細(xì)解讀一下底層實(shí)現(xiàn)的不同。

2.1 load主備同步流程

主庫(kù)執(zhí)行完成后,將/root/table.txt文件的內(nèi)容直接寫(xiě)到一個(gè)外部文件中。

往binlog文件中寫(xiě)入語(yǔ)句load data local infile ‘/tmp/SQL_LOAD_MB-1-0’ INTO TABLE db2.t。

讀取本地文件

把這個(gè)binlog日志傳到備庫(kù)。

備庫(kù)的apply線程在執(zhí)行這個(gè)事務(wù)日志時(shí):

先將binlog中t.csv文件的內(nèi)容讀出來(lái),寫(xiě)入到本地臨時(shí)目錄/tmp/SQL_LOAD_MB-1-0 中;

再執(zhí)行l(wèi)oad data語(yǔ)句,往備庫(kù)的db2.t表中插入跟主庫(kù)相同的數(shù)據(jù)。

147d3f6f.png

2.2 總結(jié)

總的來(lái)說(shuō),根據(jù)官方介紹load可以快出insert 20多倍

load 的底層實(shí)現(xiàn)的優(yōu)化:

1 跳過(guò)sql解析,直接生成數(shù)據(jù)文件;

2 在導(dǎo)入之前會(huì)關(guān)掉索引,導(dǎo)入完成后更新索引;而與之對(duì)比的Insert的處理機(jī)制是:每插入一條則更新一次數(shù)據(jù)庫(kù),更新一次索引。

官網(wǎng)的一些解答

f01fa40b.png

4 數(shù)據(jù)拷貝方法

介紹三種mysql數(shù)據(jù)拷貝的主流方法,分別是mysqldump(sql語(yǔ)句拷貝)、load(csv文件拷貝)、以及物理文件拷貝。

4.1 mysql dump

mysqldump -h$host -P$port -u$user --add-locks=0 --no-create-info --single-transaction --set-gtid-purged=OFF db1 t --where="a>900" --result-file=/client_tmp/t.sql

主要參數(shù)含義如下:

–single-transaction的作用是,在導(dǎo)出數(shù)據(jù)的時(shí)候不需要對(duì)表db1.t加表鎖,而是使用START TRANSACTION WITH CONSISTENT SNAPSHOT的方法;

–add-locks設(shè)置為0,表示在輸出的文件結(jié)果里,不增加" LOCK TABLES t WRITE;" ;

–no-create-info的意思是,不需要導(dǎo)出表結(jié)構(gòu);

–set-gtid-purged=off表示的是,不輸出跟GTID相關(guān)的信息;

–result-file指定了輸出文件的路徑,其中client表示生成的文件是在客戶(hù)端機(jī)器上的。

通過(guò)這條mysqldump命令生成的t.sql文件中就包含了如圖1所示的INSERT語(yǔ)句。

ae0f129a.png

可以看到一個(gè)insert中包含多個(gè)value對(duì),這樣插入執(zhí)行速度可以加快。

這也是navicat 上 data transfer功能

148c3bcb.png

4.2 load

show variables like ‘%secure_file_priv%’;

如果設(shè)置為empty,表示不限制文件生成的位置,這是不安全的設(shè)置;

如果設(shè)置為一個(gè)表示路徑的字符串,就要求生成的文件只能放在這個(gè)指定的目錄,或者它的子目錄;

如果設(shè)置為NULL,就表示禁止在這個(gè)MySQL實(shí)例上執(zhí)行select … into outfile 操作。

通過(guò)修改配置文件永久生效

4f4991f4.png

設(shè)置后可以通過(guò)命令導(dǎo)出

select * from db1.t where a>900 into outfile '/server_tmp/t.csv';

導(dǎo)出的csv文件可以用如下命令導(dǎo)入

load data infile '/server_tmp/t.csv' into table db2.t;

拷貝到數(shù)據(jù)庫(kù)本地后,可以用本地導(dǎo)入,比遠(yuǎn)程導(dǎo)入更快,因?yàn)槭∪チ嗽趌oad這個(gè)事務(wù)中網(wǎng)絡(luò)傳輸,減輕數(shù)據(jù)庫(kù)壓力。

load data local infile '/server_tmp/t.csv' into table db2.t;

4.3 物理拷貝

在掌握了邏輯拷貝的方法后,是否有物理導(dǎo)數(shù)據(jù)的方法呢?比如,直接把db1.t表的.frm文件和.ibd文件拷貝到db2目錄下,是否可行呢?

答案是不行的。

因?yàn)?#xff0c;一個(gè)InnoDB表,除了包含這兩個(gè)物理文件外,還需要在數(shù)據(jù)字典中注冊(cè)。直接拷貝這兩個(gè)文件的話(huà),因?yàn)閿?shù)據(jù)字典中沒(méi)有db2.t這個(gè)表,系統(tǒng)是不會(huì)識(shí)別和接受它們的。

不過(guò),在MySQL 5.6版本引入了可傳輸表空間(transportable tablespace)的方法,可以通過(guò)導(dǎo)出+導(dǎo)入表空間的方式,實(shí)現(xiàn)物理拷貝表的功能。

假設(shè)我們現(xiàn)在的目標(biāo)是在db1庫(kù)下,復(fù)制一個(gè)跟表trajectory_min_section_0511相同的表trajectory_min_section_0511_copy,具體的執(zhí)行步驟如下:

-- 源端執(zhí)行

flush table trajectory_min_section_0511 for export

這時(shí)候數(shù)據(jù)庫(kù)目錄下會(huì)生成一個(gè)trajectory_min_section_0511.cfg文件;

cp trajectory_min_section_0511.ibd trajectory_min_section_0511_copy.ibd;

在db1目錄下執(zhí)行cp trajectory_min_section_0511.cfg trajectory_min_section_0511_copy.cfg; 這兩個(gè)命令(

這里需要注意的是,拷貝得到的兩個(gè)文件,MySQL進(jìn)程要有讀寫(xiě)權(quán)限);

unlock tables

trajectory_min_section_0511.cfg文件會(huì)被刪除;

-- 目標(biāo)端執(zhí)行

create table trajectory_min_section_0511_copy like trajectory_min_section_0511;

首先創(chuàng)建一個(gè)相同表結(jié)構(gòu)的空表

alter table trajectory_min_section_0511_copy discard tablespace;

這時(shí)候trajectory_min_section_0511_copy.ibd文件會(huì)被刪除

alter table trajectory_min_section_0511_copy import tablespace

將這個(gè)trajectory_min_section_0511_copy.ibd文件作為表trajectory_min_section_0511_copy的新的表空間,

由于這個(gè)文件的數(shù)據(jù)內(nèi)容和trajectory_min_section_0511.ibd是相同的,所以表trajectory_min_section_0511_copy中

就有了和表trajectory_min_section_0511相同的數(shù)據(jù)。

測(cè)試后最后一步導(dǎo)入500w耗時(shí)10s左右,其他操作都是立刻執(zhí)行

7c9e2e74.png

幾點(diǎn)注意:

在第3步執(zhí)行完flush table命令之后,整個(gè)表trajectory_min_section_0511處于只讀狀態(tài),直到執(zhí)行unlock tables命令后才釋放讀鎖;

在執(zhí)行import tablespace的時(shí)候,為了讓文件里的表空間id和數(shù)據(jù)字典中的一致,會(huì)修改trajectory_min_section_0511_copy.ibd的表空間id。

而這個(gè)表空間id存在于每一個(gè)數(shù)據(jù)頁(yè)中。因此,如果是一個(gè)很大的文件(比如TB級(jí)別),每個(gè)數(shù)據(jù)頁(yè)都需要修改,import語(yǔ)句的執(zhí)行是需要一些時(shí)間的。

當(dāng)然,如果是相比于邏輯導(dǎo)入的方法,import語(yǔ)句的耗時(shí)是非常短的。

4.4 三種方式對(duì)比

對(duì)比一下這三種方法的優(yōu)缺點(diǎn)。

物理拷貝的方式速度最快,尤其對(duì)于大表拷貝來(lái)說(shuō)是最快的方法。如果出現(xiàn)誤刪表的情況,用備份恢復(fù)出誤刪之前的臨時(shí)庫(kù),然后再把臨時(shí)庫(kù)中的表拷貝到生產(chǎn)庫(kù)上,是恢復(fù)數(shù)據(jù)最快的方法。但是,這種方法的使用也有一定的局限性:

a) 必須是全表拷貝,不能只拷貝部分?jǐn)?shù)據(jù);

b) 需要到服務(wù)器上拷貝數(shù)據(jù),在用戶(hù)無(wú)法登錄數(shù)據(jù)庫(kù)主機(jī)的場(chǎng)景下無(wú)法使用;

c) 由于是通過(guò)拷貝物理文件實(shí)現(xiàn)的,源表和目標(biāo)表都是使用InnoDB引擎時(shí)才能使用。

用mysqldump生成包含INSERT語(yǔ)句文件的方法,可以在where參數(shù)增加過(guò)濾條件,來(lái)實(shí)現(xiàn)只導(dǎo)出部分?jǐn)?shù)據(jù)。這個(gè)方式的不足之一是,不能使用join這種比較復(fù)雜的where條件寫(xiě)法。

用select … into outfile的方法是最靈活的,支持所有的SQL寫(xiě)法。但,這個(gè)方法的缺點(diǎn)之一就是,每次只能導(dǎo)出一張表的數(shù)據(jù),而且表結(jié)構(gòu)也需要另外的語(yǔ)句單獨(dú)備份。

后兩種方式都是邏輯備份方式,是可以跨引擎使用的。

5 當(dāng)數(shù)據(jù)量很大時(shí)

拋開(kāi)最后一種物理拷貝,因?yàn)樵诰€上時(shí)不一定可以登錄數(shù)據(jù)庫(kù)主機(jī),而且也可能只拷貝部分?jǐn)?shù)據(jù)。那一般就是使用load data infile方式導(dǎo)入。

當(dāng)數(shù)據(jù)量極大(10+G,千萬(wàn)級(jí)別)時(shí),用之前介紹的方式會(huì)有很大問(wèn)題。

load為一個(gè)長(zhǎng)事務(wù),最后commit后才插入數(shù)據(jù)庫(kù)。

undo增長(zhǎng)快速,無(wú)法回收。數(shù)據(jù)庫(kù)性能下降,undo大小大于buffer pool,就會(huì)開(kāi)始內(nèi)存和磁盤(pán)的交換。

可以大文件拆小,監(jiān)控cpu后,在合理的利用率情況下,多線程load。

6 擴(kuò)展知識(shí)點(diǎn)

針對(duì)并發(fā)場(chǎng)景的一致性問(wèn)題,第一個(gè)能想到的是加鎖,但是數(shù)據(jù)庫(kù)中所有操作都上鎖勢(shì)必會(huì)帶來(lái)性能的低下,mysql的隔離級(jí)別(isolation level)最高級(jí)叫串行化,

其設(shè)計(jì)上可以認(rèn)為就是加一把大鎖,讀的時(shí)候加共享鎖,不能寫(xiě),寫(xiě)的時(shí)候,加的是排它鎖,阻塞其它事務(wù)的寫(xiě)入和讀取,若是其它的事務(wù)長(zhǎng)時(shí)間不能寫(xiě)入就會(huì)直接報(bào)超時(shí),所以它的性能也是最差的,對(duì)于它來(lái)就沒(méi)有什么并發(fā)性可言。

在InnoDB 的讀提交和可重復(fù)讀兩種級(jí)別都使用了多版本并發(fā)控制模型(MVCC)

比如在實(shí)現(xiàn)可重復(fù)讀的隔離級(jí)別,只需要在事務(wù)開(kāi)始的時(shí)候創(chuàng)建一致性視圖,也叫做快照,之后的查詢(xún)里都共用這個(gè)一致性視圖,后續(xù)的事務(wù)對(duì)數(shù)據(jù)的更改

是對(duì)當(dāng)前事務(wù)是不可見(jiàn)的,這樣就實(shí)現(xiàn)了可重復(fù)讀。 中每一個(gè)事務(wù)都有一個(gè)自己的事務(wù)id,并且是唯一的,遞增的 。

71a299d8.png

最開(kāi)始數(shù)據(jù)的版本是V0;

T1時(shí)刻發(fā)起了一個(gè)寫(xiě)任務(wù),這是把數(shù)據(jù)clone了一份,進(jìn)行修改,版本變?yōu)閂1,但任務(wù)還未完成;

T2時(shí)刻并發(fā)了一個(gè)讀任務(wù),依然可以讀V0版本的數(shù)據(jù);

T3時(shí)刻又并發(fā)了一個(gè)讀任務(wù),依然不會(huì)阻塞;

對(duì)于Mysql中的每一個(gè)數(shù)據(jù)行都有可能存在多個(gè)版本,在每次事務(wù)更新數(shù)據(jù)的時(shí)候,都會(huì)生成一個(gè)新的數(shù)據(jù)版本,并且把自己的數(shù)據(jù)id賦值給當(dāng)前版本的row trx_id。

e6536994.png

如圖中所示,假如三個(gè)事務(wù)更新了同一行數(shù)據(jù),那么就會(huì)有對(duì)應(yīng)的三個(gè)數(shù)據(jù)版本。

實(shí)際上版本1、版本2并非實(shí)際物理存在的,而圖中的U1和U2實(shí)際就是undo log,這v1和v2版本是根據(jù)當(dāng)前v3和undo log計(jì)算出來(lái)的。

當(dāng)出現(xiàn)事務(wù)回滾的時(shí)候,通過(guò)undo log反向重現(xiàn)redo log的過(guò)程,就可以將當(dāng)前數(shù)據(jù)回退回事務(wù)開(kāi)始前數(shù)據(jù)狀態(tài)。

當(dāng)事務(wù)提交后undo塊就會(huì)慢慢的回收。要避免長(zhǎng)事務(wù),因?yàn)槿绻L(zhǎng)事務(wù)中有更新,就意味著占用著行鎖,導(dǎo)致別的語(yǔ)句更新被鎖。還有讀的事務(wù)會(huì)導(dǎo)致undo log不能回收,導(dǎo)致回滾段空間膨脹。

擴(kuò)展閱讀 萬(wàn)字長(zhǎng)文,幫你梳理存儲(chǔ)引擎之Heap表關(guān)鍵知識(shí)點(diǎn)

總結(jié)

以上是生活随笔為你收集整理的mysql 复制表耗时_聊一下mysql的表复制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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