MySQL的insert into select 引发锁表
上周五HaC我要上線,有一個(gè)腳本需要執(zhí)行,執(zhí)行前需要備份一個(gè)表。
運(yùn)維大佬:“這個(gè)表的備份為什么要這么久,,??”
1秒過去了……2秒過去了……
期間運(yùn)營反饋系統(tǒng)出現(xiàn)大量訂單超時(shí)情況。
大佬找到我,問:“你怎么備份的?”
我:“insert into select * from 呀!”
大佬:“??你是不是不想混了?”
又是被大佬嫌棄的一天,為了不卷鋪蓋走人,我決定去學(xué)習(xí)一下表備份的常見方法。
MySQL一般我們在生產(chǎn)上備份數(shù)據(jù)通常會(huì)用到 這兩種方法:
INSERT INTO SELECT
CREATE TABLE AS SELECT
注:本文僅針對MySQL innodb引擎,事務(wù)是可重復(fù)讀RR,數(shù)據(jù)庫版本為5.5
1.INSERT INTO SELECT
insert?into?Table2(field1,field2,...)?select?value1,value2,...?from?Table1注意
(1)要求目標(biāo)表Table2必須存在,并且字段field,field2…也必須存在
(2)注意Table2的主鍵約束,如果Table2有主鍵而且不為空,則 field1, field2…中必須包括主鍵
在執(zhí)行語句的時(shí)候,MySQL是逐行加鎖的(掃描一個(gè)鎖一個(gè)),直至鎖住所有符合條件的數(shù)據(jù),執(zhí)行完畢才釋放鎖。所以當(dāng)業(yè)務(wù)在進(jìn)行的時(shí)候,切忌使用這種方法。
在RR隔離級別下,還會(huì)加行鎖和間隙鎖
舉個(gè)栗子吧:
CREATE?TABLE?`t`?(`id`?int(11)?NOT?NULL?AUTO_INCREMENT,`c`?int(11)?DEFAULT?NULL,`d`?int(11)?DEFAULT?NULL,PRIMARY?KEY?(`id`),UNIQUE?KEY?`c`?(`c`) )?ENGINE=InnoDB;insert?into?t?values(null,?1,1); insert?into?t?values(null,?2,2); insert?into?t?values(null,?3,3); insert?into?t?values(null,?4,4);create?table?t2?like?t;執(zhí)行
begin; insert?into?t2(c,d)?select?c,d?from?t;先不commit;這個(gè)語句對表 t 主鍵索引加了 (-∞,1] 這個(gè) next-key lock
新開一個(gè)Navicat窗口,模擬新事務(wù)進(jìn)入,此時(shí)執(zhí)行下面這句sql就需要等待
insert?into?t?values(-1,-1,-1); 鎖住了真就鎖表了~無法寫進(jìn)去了,我終于知道為什么訂單超時(shí)了。
背鍋背鍋。
如果實(shí)在要使用 INSERT INTO SELECT 這種方法,可以使用下面的方法進(jìn)行優(yōu)化:
加條件,強(qiáng)制走索引,不要全表掃描,例如
加上limit 100,100 這種,限制數(shù)量
2. CREATE TABLE AS SELECT
create table as select ?會(huì)創(chuàng)建一個(gè)不存在的表,也可以用來復(fù)制一個(gè)表。
1.?create?table?t3?as?select?*?from?t?where?1=2; --?創(chuàng)建一個(gè)表結(jié)構(gòu)與t一模一樣的表,只復(fù)制結(jié)構(gòu)不復(fù)制數(shù)據(jù);2.create?table?t3?as?select?*?from?t?; --?創(chuàng)建一個(gè)表結(jié)構(gòu)與t一模一樣的表,復(fù)制結(jié)構(gòu)同時(shí)也復(fù)制數(shù)據(jù);(索引不會(huì)創(chuàng)建)3.create?table?t3(`id`,`a`)??as?select?`id`,`c`?from?t; --?創(chuàng)建一個(gè)表結(jié)構(gòu)與t一模一樣的表,復(fù)制結(jié)構(gòu)同時(shí)也復(fù)制數(shù)據(jù),但是指定新表的列名;后面兩種格式,如果后面跟上合適的查詢條件,可以只復(fù)制符合條件的數(shù)據(jù)到新的表中。比如:
create??table?table1??as??select?*?from?table2??where?columns1>=1;針對大表多字段的表復(fù)制,考慮是否每一個(gè)字段都是必需的,如果不是必需的,可以自定義選擇字段嗎,這樣復(fù)制的時(shí)間會(huì)大大提升。
CREATE?table?table1?as?SELECT?id?FROM?table2;?--?只復(fù)制id這一列注意此建表過程全程鎖表。語句執(zhí)行完畢,才釋放元數(shù)據(jù)鎖。
MDL全稱為metadata lock,即元數(shù)據(jù)鎖。MDL鎖主要作用是維護(hù)表元數(shù)據(jù)的數(shù)據(jù)一致性,在表上有活動(dòng)事務(wù)(顯式或隱式)的時(shí)候,不可以對元數(shù)據(jù)進(jìn)行寫入操作。因此從MySQL5.5版本開始引入了MDL鎖,來保護(hù)表的元數(shù)據(jù)信息,用于解決或者保證DDL操作與DML操作之間的一致性。
注意:
新表不會(huì)自動(dòng)創(chuàng)建創(chuàng)建和原表相同的索引。(即復(fù)制表的索引會(huì)消失)
3 .區(qū)別
-
首先,最大的區(qū)別是二者屬于不同類型的語句,INSERT INTO SELECT 是DML語句(數(shù)據(jù)操作語言,SQL中處理數(shù)據(jù)等操作統(tǒng)稱為數(shù)據(jù)操縱語言),完成后需要提交才能生效,CREATE TABLE AS SELECT 是DDL語句(數(shù)據(jù)定義語言,用于定義和管理 SQL 數(shù)據(jù)庫中的所有對象的語言 ),執(zhí)行完直接生效,不提供回滾,效率比較高。
-
其次,功能不同,INSERT INTO SELECT只是插入數(shù)據(jù),必須先建表;CREATE TABLE AS SELECT 則建表和插入數(shù)據(jù)一塊完成。
-
當(dāng)有大量數(shù)據(jù)的時(shí)候不推薦使用Insert into as,因?yàn)樵撜Z句的插入的效率很慢。
4.總結(jié)
以上對復(fù)制表來說,都不是很好的選擇,分享幾種平時(shí)常用的方法:
導(dǎo)出成excel,然后拼sql 成 insert into values(),(),()的形式。
定時(shí)任務(wù),任務(wù)的邏輯是查詢100條記錄,然后多個(gè)線程分到幾個(gè)任務(wù)執(zhí)行,比如是個(gè)線程,每個(gè)線程10條記錄,插入后,在查詢新的100條記錄處理。
mysqldumb方法,例如
mysqldump?-h<span?class="katex-html"?aria-hidden="true" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;"><span?class="strut"?style="height:0.69444em;vertical-align:0em;" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;"><span?class="mord?mathit" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">h<span?class="mord?mathit" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">o<span?class="mord?mathit" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">s<span?class="mord?mathit" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">t<span?class="mord?mathit"?style="margin-right:0.05764em;" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">E<span?class="mord?mathit"?style="margin-right:0.05764em;" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">E<span?class="mord?mathit"?style="margin-right:0.13889em;" style="font-size: inherit;color: inherit;line-height: inherit;margin: 1px;overflow-wrap: inherit !important;word-break: inherit !important;">Pport?-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 </span?class="mord?mathit"?style="margin-right:0.13889em;"></span?class="mord?mathit"?style="margin-right:0.05764em;"></span?class="mord?mathit"?style="margin-right:0.05764em;"></span?class="mord?mathit"></span?class="mord?mathit"></span?class="mord?mathit"></span?class="mord?mathit"></span?class="strut"?style="height:0.69444em;vertical-align:0em;"></span?class="katex-html"?aria-hidden="true">導(dǎo)出 CSV 文件
第3、4兩種方法適合整個(gè)表導(dǎo)出。
5. 業(yè)務(wù)少的情況(深夜什么的)下,可以使用 create table as select ?。
知識又增加了。
原創(chuàng)電子書歷時(shí)整整一年總結(jié)的?Java 面試 + Java 后端技術(shù)學(xué)習(xí)指南,這是本人這幾年及校招的總結(jié),各種高頻面試題已經(jīng)全部進(jìn)行總結(jié),按照章節(jié)復(fù)習(xí)即可,已經(jīng)拿到了大廠offer。 原創(chuàng)思維導(dǎo)圖掃碼或者微信搜?程序員的技術(shù)圈子?回復(fù)?面試?領(lǐng)取原創(chuàng)電子書和思維導(dǎo)圖。總結(jié)
以上是生活随笔為你收集整理的MySQL的insert into select 引发锁表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于Spring+SpringMVC+M
- 下一篇: 面试中又被问到Redis如何实现抢购,赶