本文摘自開源中國,原文:https://my.oschina.net/u/1581846/blog/4283365
業務場景
最近的一個項目最開始由於資源問題,mysql 數據庫是部署在一台雲服務器上的,這兩天客戶提供了雲數據庫,所以原來在部署在 ECS 服務器上的數據庫,需要遷移到雲數據庫。在雲數據庫上的優勢很多,它自動是分配了一主二從,自動備份等。所以這兩天的任務就是要將原來的數據庫遷移。 mysql 版本 mysql5.7.17
遷移步驟
遷移數據庫是一項需要很謹慎的任務。整個遷移過程大概分成以下幾步:
備份原數據庫數據
//備份數據庫,並指定日期
mysqldump -uadmin -p****** databaseName | gzip > /databak/databaseName_$(date +%Y%m%d).sql.gz
雲數據庫上初始化數據庫、編碼、用戶名、數據庫等基礎信息 先通過騰訊雲平台創建用戶,以及相關權限
//連接數據庫
mysql -h172.16.0.1 -uUserName -p******
//創建數據庫,並指定編碼
CREATE DATABASE databaseName DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
執行還原操作
//解壓備份好的.sql文件
gunzip -v /databak/databaseName_20200517.sql.gz
//還原數據庫
source /databak/databaseName_20200517.sql
產生的問題
正常情況下,按照以上遷移數據的步驟,應該等還原操作完成即可,但是事情往往不會那么順利,如果很順利可能我們對數據庫遷移的認知就到這里就可以了。
實際上在執行還原操作時出現了錯誤。 主要出現兩次問題
沒有主鍵
ERROR 1173 (42000): This table type requires a primary key
表的存儲引擎不對
Can not create tables in myisam storage engine in user databases, controled by reject_create_table_myisam variable.
看到這兩個問題,感覺比較奇怪,因為最開始在測試數據庫自動備份時,已經對備份的sql文件還原過,沒有發現有什么錯誤。為什么這一次遷移就出現這兩個問題呢?
排查方法
建表缺少主鍵
針對問題1,看日志比較容易明白意思,就是表需要主鍵,這個時候就想先看看數據庫中有哪些沒有主鍵的表,看看能否直接指定。
查詢沒有主鍵的表的sql如下:
SELECT table_schema, table_name,TABLE_ROWS
FROM information_schema.tables
WHERE (table_schema, table_name) NOT IN (
SELECT DISTINCT table_schema, table_name
FROM information_schema.columns
WHERE COLUMN_KEY = 'PRI'
)
AND table_schema NOT IN ('sys', 'mysql', 'information_schema', 'performance_schema');
查詢結果分析發現這些表和錯誤日志中的表匹配。然后查看了兩張表發現的確都是沒有指定主鍵的。正常 mysql 的設計中,如果在創建表時沒有顯式地定義主鍵,則 InnoDB 存儲引擎會按如下方式選擇或創建主鍵:
首先判斷表中是否有非空的唯一索引,如果有,則該列即為主鍵。
如果不符合上述條件,InnoDB存儲引擎自動創建一個6字節大小的指針。
但是還是報那個錯。這時在想是否和數據庫的版本有關系。經過 google 搜索大部分的結果都是定位到數據庫的參數設置了表一定要指定主鍵。
解決辦法如下:
//查詢變量查看是否開啟了強制主鍵,也就是建表必須有主鍵約束,
show global variables like 'innodb_force_primary_key';
//如果是ON則設置成OFF即可
set global innodb_force_primary_key=off;
當然我也找找這個方法去嘗試了,但我執行第一句時,發現沒有找到結果。然后也經過了解這個參數是mysql8.0以及MariaDB中才有這個參數。強制執行
set global innodb_force_primary_key=off;
出現如下錯誤:
ERROR 1193 (HY000): Unknown system variable 'innodb_force_primary_key'
所以這種方法行不通。但通過這個解決方法,我猜測問題可能就是和變量設置有關系,於是我查看了所有的 mysql 全局變量,最后找到了問題所在。
問題定位:原來騰訊雲上的分布式數據庫tdsql中,設置建表需要主鍵的參數為 reject_table_no_pk 這個時候就能定位到問題所在了。
表的存儲引擎不對
通過如下sql可以查詢一個庫中所有使用MyISAM存儲引擎創建的表
SELECT * FROM information_schema.tables where engine='MyISAM' and TABLE_SCHEMA='databaseName'
查出來的表和還原錯誤日志報錯的表也匹配了。
通過分析問題1時,在查找全局變量時存在如下變量。
reject_create_table_myisam 意思就是拒絕使用 myisam 存儲引擎建表。所以問題2也定位到了問題源頭。
解決方案
通過上面一步一步分析問題,已經找到了問題的源頭,找到了問題的產生原因。對於問題的解決就比較好處理了。
方法1
登錄超級管理員,對這兩個參數進行設置
set global reject_table_no_pk 0;
set global reject_create_table_myisam OFF;
設置完成之后,重新執行還原操作,發現問題解決。但是分布式數據庫新增了的這兩個參數其實是有他的用處的,這種默認值最好不要輕易調整,因為雲數據庫還有一個優勢就是大部分的參數都調成了最佳。
通過資料搜索發現原來這兩個參數是有重要作用的。 TDSQL 內核使用 row 格式的 binlog 復制。根據目前 MariaDB/MySQL 的實現方式,如果一個 update/delete 語句更新或者刪除了很多行,那么到了備機上面,更新或者刪除每個行時候,需要使用索引掃描或者全表掃描來找到這個行,導致備機復制變得非常慢,這是非常嚴重的問題。 在 TDSQL 的告警平台上面就有用戶出現過主備延遲因此變得非常大的告警。為了避免這些致命問題的出現,所以才有“自動增加主鍵”和“禁止 create table/alter table 語句產生無主鍵的表”
方法2
方法1能夠解決還原問題,也能夠解決一般數據量不大的應用。但是如果后面業務增長,可能還是需要將參數調整回來。此時方法1的解決方案就行不通了。
方法2實際就是針對沒有主鍵的表設置主鍵,沒有主鍵的表新增主鍵。以符合分布式數據庫要求。
而對於數據庫存儲引擎為myisam的表通過sql語句直接調整。
//修改表的存儲引擎
alter table table_name engine=innodb;
總結
數據庫內容很多,很深,我們在處理工作中實際問題時,需要多多思考。從解決實際問題的過程中去深入知識點,擴展知識點。這樣才能提高。