天天看點

資料庫核心月報 - 2015 / 09-MySQL · 捉蟲動态 · BUG 幾例

随着rds mysql使用者越來越多,隐藏很久很深的bug也逐漸被挖出來了,下面分享一下最近遇到的三例bug,都是官方版本存在的。

隻有5.6受到影響。

複現步驟

原因分析

function/trigger和procedure不同,不能單獨執行,必須依賴statement才能存在,這樣就決定了 function/trigger 的事務邊界必須由statement來定義,是以<code>create function/trigger</code>的時候,會進行檢測body中是否有事務邊界定義。比如,如果有commit/rollback,或者會引起隐式送出的ddl語句,那麼就會報以下錯誤:

mysql 5.5為什麼會成功?

因為<code>drop temporary table</code>是一個比較特殊的語句,雖然是ddl語句,但不會隐式送出,是以進行了特殊處理,可以使用。

mysql 5.6 為什麼主庫會成功,備庫會失敗呢?

在打開gtid_mode的情況下,gtid有一個特殊的限制,不能在事務的過程中進行<code>drop temporary table</code>。如果要使用,必須為<code>drop temporary table</code>獨立配置設定一個gtid。

複現方法中的function在主庫執行的時候,産生的binlog event如下:

而這樣的event在備庫slave線程執行的時候,不滿足gtid對于<code>drop temproary table</code>的要求,是以報錯。

修複方法

既然gtid_mode=on的時候,<code>drop temproary table</code>必須要配置設定一個gtid,那麼也就意味着它雖然不會隐式送出,但還是定義了事務邊界。修複方法就是就在<code>gtid_pre_statement_checks</code>的時候,對于這樣的情況就拒絕執行。

5.1、5.5、5.6都受影響。

首先環境設定:

牽涉到的字元集如下:

因為<code>drop table</code>的query event是/* generated by server */,在主庫生成的時候使用的字元集為system_charset,而在備庫執行的時候,需要初始化session環境為主庫帶過來是gbk,而event本身是system_charset的,導緻event和session環境的charset不一緻,無法找到表而slave中斷。

對于/* generated by server */的event,不沿用session的字元集,而是使用主庫産生event時用的字元集。

archive是一個歸檔引擎,在寫入的時候,必須按照遞增順序,也就是不能寫入一個比目前pk小的記錄,引擎層做了寫死限制:

而alter的過程中,因為沒有指定<code>auto_increment</code>的值,是以<code>auto_increment</code>會從原表中繼承過來,也就是等于2,而在copy資料的時候,先插入pk=1的記錄,發現比目前<code>auto_increment</code>值小,就報了上面的錯誤。

語句<code>alter table t engine=archive</code>,在轉換成archive引擎的時候,如果沒有指定<code>auto_increment</code>的值的時候,系統預設指定成0, 而不是沿用原表的目前<code>auto_increment</code>值。