成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

完蛋,公司被一條 update 語句干趴了!

wendux / 1348人閱讀

摘要:假設(shè)有兩個事務(wù)的執(zhí)行順序如下可以看到,這次事務(wù)的語句被阻塞了。這是因為事務(wù)的語句中條件沒有索引列,所有記錄都會被加鎖,也就是這條語句產(chǎn)生了個記錄鎖和個間隙鎖,相當(dāng)于鎖住了全表。

昨晚在群劃水的時候,看到有位讀者說了這么一件事。

大概就是,在線上執(zhí)行一條 update 語句修改數(shù)據(jù)庫數(shù)據(jù)的時候,where 條件沒有帶上索引,導(dǎo)致業(yè)務(wù)直接崩了,被老板教訓(xùn)了一波

這次我們就來看看:

  • 為什么會發(fā)生這種的事故?
  • 又該如何避免這種事故的發(fā)生?

說個前提,接下來說的案例都是基于 InnoDB 存儲引擎,且事務(wù)的隔離級別是可重復(fù)讀。

為什么會發(fā)生這種的事故?

InnoDB 存儲引擎的默認(rèn)事務(wù)隔離級別是「可重復(fù)讀」,但是在這個隔離級別下,在多個事務(wù)并發(fā)的時候,會出現(xiàn)幻讀的問題,所謂的幻讀是指在同一事務(wù)下,連續(xù)執(zhí)行兩次同樣的查詢語句,第二次的查詢語句可能會返回之前不存在的行。

因此 InnoDB 存儲引擎自己實現(xiàn)了行鎖,通過 next-key 鎖(記錄鎖和間隙鎖的組合)來鎖住記錄本身和記錄之間的“間隙”,防止其他事務(wù)在這個記錄之間插入新的記錄,從而避免了幻讀現(xiàn)象。

當(dāng)我們執(zhí)行 update 語句時,實際上是會對記錄加獨占鎖(X 鎖)的,如果其他事務(wù)對持有獨占鎖的記錄進行修改時是會被阻塞的。另外,這個鎖并不是執(zhí)行完 update 語句就會釋放的,而是會等事務(wù)結(jié)束時才會釋放。

在 InnoDB 事務(wù)中,對記錄加鎖帶基本單位是 next-key 鎖,但是會因為一些條件會退化成間隙鎖,或者記錄鎖。加鎖的位置準(zhǔn)確的說,鎖是加在索引上的而非行上。

比如,在 update 語句的 where 條件使用了唯一索引,那么 next-key 鎖會退化成記錄鎖,也就是只會給一行記錄加鎖。

這里舉個例子,這里有一張數(shù)據(jù)庫表,其中 id 為主鍵索引。

假設(shè)有兩個事務(wù)的執(zhí)行順序如下:

在這里插入圖片描述

可以看到,事務(wù) A 的 update 語句中 where 是等值查詢,并且 id 是唯一索引,所以只會對 id = 1 這條記錄加鎖,因此,事務(wù) B 的更新操作并不會阻塞。

但是,在 update 語句的 where 條件沒有使用索引,就會全表掃描,于是就會對所有記錄加上 next-key 鎖(記錄鎖 + 間隙鎖),相當(dāng)于把整個表鎖住了。

假設(shè)有兩個事務(wù)的執(zhí)行順序如下:

可以看到,這次事務(wù) B 的 update 語句被阻塞了。

這是因為事務(wù) A的 update 語句中 where 條件沒有索引列,所有記錄都會被加鎖,也就是這條 update 語句產(chǎn)生了 4 個記錄鎖和 5 個間隙鎖,相當(dāng)于鎖住了全表。

因此,當(dāng)在數(shù)據(jù)量非常大的數(shù)據(jù)庫表執(zhí)行 update 語句時,如果沒有使用索引,就會給全表的加上 next-key 鎖, 那么鎖就會持續(xù)很長一段時間,直到事務(wù)結(jié)束,而這期間除了 select ... from語句,其他語句都會被鎖住不能執(zhí)行,業(yè)務(wù)會因此停滯,接下來等著你的,就是老板的挨罵。

那 update 語句的 where 帶上索引就能避免全表記錄加鎖了嗎?

并不是。

關(guān)鍵還得看這條語句在執(zhí)行過程種,優(yōu)化器最終選擇的是索引掃描,還是全表掃描,如果走了全表掃描,就會對全表的記錄加鎖了。

又該如何避免這種事故的發(fā)生?

我們可以將 MySQL 里的 sql_safe_updates 參數(shù)設(shè)置為 1,開啟安全更新模式。

官方的解釋:
If set to 1, MySQL aborts UPDATE or DELETE statements that do not use a key in the WHERE clause or a LIMIT clause. (Specifically, UPDATE statements must have a WHERE clause that uses a key or a LIMIT clause, or both. DELETE statements must have both.) This makes it possible to catch UPDATE or DELETE statements where keys are not used properly and that would probably change or delete a large number of rows. The default value is 0.

大致的意思是,當(dāng) sql_safe_updates 設(shè)置為 1 時。

update 語句必須滿足如下條件之一才能執(zhí)行成功:

  • 使用 where,并且 where 條件中必須有索引列;
  • 使用 limit;
  • 同時使用 where 和 limit,此時 where 條件中可以沒有索引列;

delete 語句必須滿足如下條件之一才能執(zhí)行成功:

  • 使用 where,并且 where 條件中必須有索引列;
  • 同時使用 where 和 limit,此時 where 條件中可以沒有索引列;

如果 where 條件帶上了索引列,但是優(yōu)化器最終掃描選擇的是全表,而不是索引的話,我們可以使用 force index([index_name]) 可以告訴優(yōu)化器使用哪個索引,以此避免有幾率鎖全表帶來的隱患。

總結(jié)

不要小看一條 update 語句,在生產(chǎn)機上使用不當(dāng)可能會導(dǎo)致業(yè)務(wù)停滯,甚至崩潰。

當(dāng)我們要執(zhí)行 update 語句的時候,確保 where 條件中帶上了索引列,并且在測試機確認(rèn)該語句是否走的是索引掃描,防止因為掃描全表,而對表中的所有記錄加上鎖。

我們可以打開 MySQL sql_safe_updates 參數(shù),這樣可以預(yù)防 update 操作時 where 條件沒有帶上索引列。

如果發(fā)現(xiàn)即使在 where 條件中帶上了列索引列,優(yōu)化器走的還是全標(biāo)掃描,這時我們就要使用 force index([index_name]) 可以告訴優(yōu)化器使用哪個索引。

這次就說到這啦,下次要小心點,別再被老板挨罵啦。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/121523.html

相關(guān)文章

  • 編寫可維護的JavaScript

    摘要:通用原則嚴(yán)禁使用,只在別無他法時使用。和也是可以使用的,但不用字符串形式而要用函數(shù)。每種類型都代表全局作用域中的一個構(gòu)造函數(shù),并分別表示各自對用的原始值的對象。 語句和表達(dá)式 所有的塊語句都應(yīng)當(dāng)使用花括號。包括: if for while do…while… try…catch…finally //不好的寫法 if (condition) doSomethind(); //...

    yanest 評論0 收藏0
  • 有趣的 Mysql 存儲引擎

    摘要:提供了一套統(tǒng)一的應(yīng)用開發(fā)模型和核心,因此,盡管不同的存儲引擎擁有不同的特性,不過對于開發(fā)人員,應(yīng)用操作都是完全透明的。 Mysql 提供了一套統(tǒng)一的應(yīng)用開發(fā)模型和核心 API,因此,盡管不同的存儲引擎擁有不同的特性,不過對于開發(fā)人員,應(yīng)用操作都是完全透明的。應(yīng)用層的連接并不直接訪問存儲引擎層,而是訪問 Mysql 提供的 Api,也就是說不管所操作的表對象使用什么存儲引擎,讀寫數(shù)據(jù)時執(zhí)...

    lidashuang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<