----MySQL導入數據的時候,總是報錯,本地測試都沒辦法測試---- 導出SQL文件正常, 在導入SQL文件的時候, 報錯-----大部分數據表導入成功, 個別的失敗
在網上看到很多建議:
- 建議別直接運行sql文件,你可以嘗試打開sql文件自己選取sql執行
- Navicat運行SQL文件時, 去掉第二個√(每個運行中運行多重查詢這個選項去掉√)
- 確認下字段類型跟內容是否一致,主鍵是否重復插入?可以單獨執行出錯的語句看下報錯提示
- SQL文件分批次執行, 排查哪里出問題了.
我看了一下我的兩個數據庫的版本, 線上的MySQL是5.7.24, 本地的MySQL是5.5.53, 不過我感覺版本應該沒什么問題, 因為5.5已經支持utfmb4編碼了. 我這里導入失敗的原因也不是版本的問題(個人感覺). 記錄一下解決的過程:
- 按照上面第二個建議, 去掉Navicat第二個√, 大部分可以導入成功, 然后檢查有那些導入失敗的. 我是用瀏覽器運行項目,根據項目報錯 然后看那些數據表不存在, 來確定有哪些數據表沒導入成功.
Base table or view not found: 1146 Table 'txsj_fdqs.hjmallind_goods' doesn't exist The SQL being executed was: SELECT (case when g.cat_id=0 then c2.name else c.name end) name FROM `hjmallind_goods` `g` LEFT JOIN `hjmallind_cat` `c` ON c.id=g.cat_id LEFT JOIN `hjmallind_goods_cat` `gc` ON gc.goods_id=g.id LEFT JOIN `hjmallind_cat` `c2` ON gc.cat_id=c2.id WHERE ((`g`.`store_id`=5) AND (`g`.`is_delete`=0) AND (`g`.`mch_id`=0)) AND (`g`.`type`=0) AND (((`gc`.`is_delete`=0) AND (`gc`.`store_id`=5)) OR (isnull(gc.id))) GROUP BY `name` ORDER BY `g`.`cat_id`
- 說明數據庫剛剛沒有導入成功這張表, 那么現在單獨導入這張表, 報錯: Specified key was too long; max key length is 767 bytes ,針對這個問題, 又上網查了半天, 解決辦法是, 打開這個表的SQL文件, 修改了聯合主鍵, 把varchar(255)改成了varchar(60). 導入成功.
- 新的問題: 是什么導致的上面的問題呢?
- 猜測是編碼問題, 因為utf8mb4編碼是4字節的, 4×255>757 , 但是我去查看導入成功的表, 發現對應的字段也是utf8mb4編碼. 那應該就不是編碼導致的問題了.(因為這兩個版本的都支持utf8mb4,怎么說也不應該是編碼問題吧.)
- 猜測可能是本地PHPstudy默認設置了禁用innodb_large_prefix , 然后導致索引鍵前綴限制為767字節 (需要去研究一下) .如果禁用innodb_large_prefix,不管是什么表,索引鍵前綴限制為767字節。----參考
- 新建mysql庫或者表的時候還有一個排序規則: (之前一直沒去想)
utf8_unicode_ci比較准確,utf8_general_ci速度比較快。通常情況下 utf8_general_ci的准確性就夠我們用的了, 如果是utf8mb4那么對應的就是 utf8mb4_general_ci utf8mb4_unicode_ci - utf8和utf8mb4的區別: mb4就是most bytes 4的意思,專門用來兼容四字節的unicode. utf8mb4是utf8的超集,除了將編碼改為utf8mb4外不需要做其他轉換, 當然,為了節省空間,一般情況下使用utf8也就夠了. 原來mysql支持的 utf8 編碼最大字符長度為 3 字節,如果遇到 4 字節的寬字符就會插入異常了.
-
系統變量innodb_large_prefix開啟了,則對於使用DYNAMIC或COMPRESSED行格式的InnoDB表,索引鍵前綴限制為3072字節。如果禁用innodb_large_prefix,不管是什么表,索引鍵前綴限制為767字節。
上述的bug很明顯是索引超出了限制的長度767(我司生產上innodb_large_prefix禁用了):
我發現報錯的那張表建立了一個varchar類型的索引,varchar(255),覺得沒什么問題,其實不然,上述的767是字節,而varchar類型是字符,同時我發現我使用的字符集為(utf8mb4),這個指每個字符最大的字節數為4,所以很明顯 4*255 > 767
所以就報上述錯了(Specified key was too long; max key length is 767 bytes)。
解決方法:
改變varchar的字符數,我改成了64就可以了。varchar(64)
或者啟用innodb_large_prefix,那么限制值會增加到3072 ----------------------------https://blog.csdn.net/chenjianhuideyueding/article/details/88426021
- 終於找到了原因, 去本地MySQL查看是否開啟了innodb_large_prefix, 這個參數是限制索引列長度的
show variables like 'innodb_large_prefix'; //查看是否開啟innodb_large_prefix 的命令
發現本地的MySQL默認是沒有開啟的. 線上的是開啟了的(不過不知道是之前有人開啟的, 還是5.7版本默認開啟的. 應該是默認開啟的! 反正不用管這些~無所謂) 每個人的MySQL配置不同, 要看具體什么情況了.....
- 關於如何開啟innodb_large_prefix,解決方案也在這里: 可參考https://www.cnblogs.com/kerrycode/p/9680881.html
- mysql uses 1 or 2 extra bytes to record the values length: 1 byte if the column's max length is 255 bytes or less, 2 if it's longer than 255 bytes. the utf8_general_ci encoding needs 3 bytes per character so varchar(20) uses 61 bytes, varchar(500) uses 1502 bytes in total 1563 bytes。引自--https://stackoverflow.com/questions/1814532/1071-specified-key-was-too-long-max-key-length-is-767-bytes