<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                本節摘取了MySQL5.6.23的幾個和InnoDB相關的主要bugfix,簡單闡述下問題及解決方案。 **問題一** 當執行FLUSH TABLE..FOR EXPORT命令時,會暫停purge線程的操作。這一步通過設置一個標記purge_sys->state的值為PURGE_STATE_STOP來告訴purge線程該停下來歇歇了。 然而如果Purge線程當前正在函數srv_do_purge中工作,該函數會執行一個while循環,退出條件是當前server shutdown,或者上次purge的page數為0,并沒有檢查purge線程的狀態是否被設置為PURGE_STATE_STOP; 很顯然,如果當前的history list非常長,那么可能需要等待purge完成后,才能退出循環,而在用戶看來,就好像hang了很久一樣。推長history list 很容易:開啟一個打開read view的事務(例如RR級別下執行一個SELECT)不做提交,同時有并發的DML,跑一段時間history list就上去了。 **解決** 在函數srv_do_purge函數的while退出條件中加上purge線程狀態判斷,如果被設置為PURGE_STATE_STOP,就退出循環。 [補丁](https://github.com/mysql/mysql-server/commit/f9a1df899b724d26d7997a49e6403bbe90024bf3) **問題二** 在執行InnoDB crash recovery階段,如果發現不合法的大字段,就會去調用函數ib_warn_row_too_big 去打印一條warning,函數為push_warning_printf。然而這個函數的目的是給客戶端返回一條warning,而這時候系統還在崩潰恢復階段,并沒有合法的thd對象,因此造成系統崩潰。 Tips:這個bug是在升級到新版本5.6出現的,最根本的原因是5.6新版本對大字段長度做的約束。早期版本5.6及之前的版本,我們可以定義非常大的blob字段,但如果字段太長,對這些字段的修改,可能導致redo log的checkpoint點被覆蓋,因為計算redo log 空間是否足夠,并沒有依賴即將插入的redo 記錄長度,而僅僅是保留一定的比例。因此在5.6.22版本中做了限制:如果blob的長度超過innodb_log_file_size * innodb_log_files_in_group的十分之一時,就會更新失敗,給用戶返回DB_TOO_BIG_RECORD的錯誤碼。這個問題在5.7版本里被徹底解決:每寫4個blob外部存儲頁,檢查一次redo log空間是否足夠,如果不夠用,就推進checkpoint點。 **解決** 在函數ib_warn_row_too_big中判斷當前線程thd是否被初始化,如果為NULL,直接返回,不調用push_warning_printf。 [補丁](https://github.com/mysql/mysql-server/commit/901ce5314b6b0d4115b0237491e2afaafe5a274e) **問題三** 當我們通過alter語句修改一個被外鍵約束的列名時,由于沒有從數據詞典cache中將包含老列名的cache項驅逐掉,導致重載外鍵約束時失敗。 舉個簡單的例子: ~~~ root@sb1 12:37:13>CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, INDEX idx(a)) ENGINE=InnoDB; Query OK, 0 rows affected (0.00 sec) ~~~ ~~~ root@sb1 12:37:26>CREATE TABLE t2 (a INT KEY, b INT, INDEX ind(b), FOREIGN KEY (b) REFERENCES t1(a) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB; Query OK, 0 rows affected (0.00 sec) ~~~ ~~~ root@sb1 12:37:41>ALTER TABLE t1 CHANGE a id INT; Query OK, 0 rows affected, 1 warning (0.01 sec) Records: 0 Duplicates: 0 Warnings: 1 ~~~ ~~~ root@sb1 12:37:48>show warnings; +-------+------+-----------------------------------+ | Level | Code | Message | +-------+------+-----------------------------------+ | Error | 1215 | Cannot add foreign key constraint | +-------+------+-----------------------------------+ 1 row in set (0.00 sec) ~~~ ~~~ root@sb1 12:47:39>show create table t1\G *************************** 1\. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL, `b` int(11) NOT NULL, KEY `idx` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) ~~~ ~~~ root@sb1 12:52:08>INSERT INTO t2 VALUES (56, 6); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`sb1`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`) ON DELETE CASCADE ON UPDATE CASCADE) ~~~ 可以看到,盡管t1表的a列已經被rename成 id,但打印出來的信息也并沒有更正。 **解決** 當被外鍵約束的列名被修改時,將對應的外鍵項從數據詞典cache中驅逐,當其被隨后重新加載時就會使用新的對象。 [補丁](https://github.com/mysql/mysql-server/commit/a54364d2d1c147d6c325c818057de470672f8e3d) **問題四** 如上文所提到的,在新版本InnoDB中,對blob字段的數據操作需要保證其不超過總的redo log file大小的十分之一,但是返回的錯誤碼DB_TOO_BIG_RECORD及打印的信息太容易讓人誤解,大概如下: ~~~ ERROR 42000: Row size too large (> ####). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline ~~~ **解決** 輸出更合適、更直觀的錯誤信息,如下: ~~~ ERROR 42000: The size of BLOB/TEXT data inserted in one transaction is greater than 10% of redo log size. Increase the redo log size using innodb_log_file_size. ~~~ [補丁](https://github.com/mysql/mysql-server/commit/4423b9b5633d91e5793ee637ac068059001f85ba) **問題五** FLUSH TABLE操作在某些情況下可能導致實例crash。 例如如下執行序列: ~~~ mysql> CREATE TABLE t1(C TEXT CHARACTER SET UJIS) ENGINE=INNODB; Query OK, 0 rows affected (0.00 sec) mysql> LOCK TABLES t1 WRITE,t1 AS t0 READ,t1 AS t2 READ; Query OK, 0 rows affected (0.00 sec) mysql> FLUSH TABLE t1; ---- 實例CRASH ~~~ 當執行FLUSH TABLE時,在重載表cache時,InnoDB層會針對每個表設置其狀態(ha_innobase::store_lock)。如果執行FLUSH 操作,并且加的是讀鎖時,就會調用函數row_quiesce_set_state將table->quiesce設置為QUIESCE_START。在上例中,表t1的兩個表名表均加讀鎖,造成重復設置狀態為QUIESCE_START,導致斷言失敗。 Tips:在5.6版本中,雖然有明確的FLUSH TABLE..FOR EXPORT命令來協助轉儲ibd文件。但實際上,簡單的FLUSH TABLE操作默認就會產生一個tbname.cfg的配置文件,拷貝該文件和ibd,可以將數據轉移到其他實例上。table->quiesce用于標識操作狀態,例如,如果標識為QUIESCE_START,就會在函數ha_innobase::external_lock中調用row_quiesce_table_start來啟動配置文件的生成。 **解決** 移除斷言 [補丁](https://github.com/mysql/mysql-server/commit/a3f3c2ab7a1b985775f4e58529a4dd563c025b8e) **問題六** 線上實例錯誤日志中偶爾出現 “UNABLE TO PURGE A RECORD”,從官方bug系統來看,很多用戶都遇到了類似的問題。 當change buffer模塊以如下序列來緩存索引操作時可能產生上述錯誤信息: 1. 記錄被標記刪除(IBUF_OP_DELETE_MARK) 2. 隨后插入相同記錄--IBUF_OP_INSERT 3. Purge線程需要物理刪除二級索引記錄,操作被buffer--IBUF_OP_DELETE 當讀入物理頁時,總是需要進行ibuf merge。如果執行到IBUF_OP_DELETE這種類型的change buffer時,發現記錄并沒有被標記刪除,就會導致錯誤日志報錯。 顯然上述的操作序列是不合理的,正確的序列應該是IBUF_OP_DELETE_MARK,IBUF_OP_DELETE,IBUF_OP_INSERT。 為了搞清楚邏輯,我們簡單的理一下相關代碼。 注意IBUF_OP_DELETE是由第一步的標記刪除操作觸發,Purge線程發起;在每個buffer pool的控制結構體中,有一個成員buf_pool->watch[BUF_POOL_WATCH_SIZE],BUF_POOL_WATCH_SIZE的值為purge線程個數,用于輔助Purge操作。 假定內存中沒有對應的Page,Purge線程會做如下幾件事兒: * 首先查詢buffer pool,看看page是否已經讀入內存;如果不在內存中,則將page no等信息存儲到watch數組中,并插入page hash(buf_pool_watch_set)。(如果隨后page被讀入內存,也會刪除watch標記) * 判斷該二級索引記錄是否可以被Purge(row_purge_poss_sec,當該二級索引記錄對應的聚集索引記錄沒有delete mark并且其trx id比當前的purge view還舊時,不可以做Purge操作) * 隨后在插入IBUF_OP_DELETE類型的ibuf記錄時,還會double check下該page是否被設為sentinel (ibuf_insert_low,buf_pool_watch_occurred),如果未被設置,表明已經page已經讀入內存,就可以直接去做purge,而無需緩存了。 * 對于普通的操作類型,例如IBUF_OP_INSERT和IBUF_OP_DELETE_MARK,同樣也會double check page 是否讀入了內存。在函數ibuf_insert中會調用buf_page_hash_get進行檢查,如果page被讀入內存,則不緩存操作,如果請求的Page被設為sentinel,則從buf_page_hash_get返回NULL,因此隨后判定需要緩存該類型的操作。這也正是問題的所在: 1. 標記刪除記錄,寫入IBUF_OP_DELETE_MARK 2. Purge線程設置page對應的sentinel,完成合法性檢查,準備調用ibuf_insert 3. 插入相同記錄,寫入IBUF_OP_INSERT 4. Purge線程寫入IBUF_OP_DELETE **解決** 如果記錄所在的page被設置了一個sentinel,那么對該page的并發插入操作就不應該緩存到change buffer中,而是直接去嘗試讀取物理頁。 [補丁](https://github.com/mysql/mysql-server/commit/ec369cb4f363161dfbbbd662b20763b54808b7d1) **問題七** 對于非windows系統的平臺上,函數os_file_pwrite和os_file_pread在碰到io錯誤時返回-1,并錯誤的作為寫入/讀取的字節數寫在錯誤日志中。 **解決** 單獨記錄失敗的系統調用日志,打印更可讀的日志信息。 [補丁](https://github.com/mysql/mysql-server/commit/ae0f4c17c82d1d3ee89ca5afb64655b4ab1d2552) **問題八** 在崩潰恢復后立刻執行一次slow shutdown (innodb_fast_shutdown = 0) 可能產生斷言失敗crash。原因是當完成crash recovery后,對于需要回滾的事務,會起單獨的線程來執行,這時候如果shutdown實例,會觸發觸發purge線程內部斷言失敗:ut_a(n_pages_purged == 0 || srv_fast_shutdown?!= 0); **解決** 等待trx_rollback_or_clean_all_recovered完成后,再進行slow shutdown [補丁](https://github.com/mysql/mysql-server/commit/8edcc65fcd0c930a902cdf1c41ad0a1aaf21ff90)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看