mysql 導入SQL文件報錯, Specified key was too long; max key length is 767 bytes


----MySQL導入數據的時候,總是報錯,本地測試都沒辦法測試---- 導出SQL文件正常, 在導入SQL文件的時候, 報錯-----大部分數據表導入成功, 個別的失敗

         在網上看到很多建議: 

  1. 建議別直接運行sql文件,你可以嘗試打開sql文件自己選取sql執行
  2. Navicat運行SQL文件時, 去掉第二個√(每個運行中運行多重查詢這個選項去掉√)
  3. 確認下字段類型跟內容是否一致,主鍵是否重復插入?可以單獨執行出錯的語句看下報錯提示
  4. SQL文件分批次執行, 排查哪里出問題了.

         我看了一下我的兩個數據庫的版本, 線上的MySQL是5.7.24, 本地的MySQL是5.5.53, 不過我感覺版本應該沒什么問題, 因為5.5已經支持utfmb4編碼了. 我這里導入失敗的原因也不是版本的問題(個人感覺). 記錄一下解決的過程:

  1. 按照上面第二個建議, 去掉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`
  2. 說明數據庫剛剛沒有導入成功這張表, 那么現在單獨導入這張表,  報錯:   Specified key was too long; max key length is 767 bytes  ,針對這個問題, 又上網查了半天, 解決辦法是, 打開這個表的SQL文件, 修改了聯合主鍵, 把varchar(255)改成了varchar(60). 導入成功.
  3. 新的問題: 是什么導致的上面的問題呢? 
    1. 猜測是編碼問題, 因為utf8mb4編碼是4字節的, 4×255>757 , 但是我去查看導入成功的表, 發現對應的字段也是utf8mb4編碼. 那應該就不是編碼導致的問題了.(因為這兩個版本的都支持utf8mb4,怎么說也不應該是編碼問題吧.)
    2. 猜測可能是本地PHPstudy默認設置了禁用innodb_large_prefix , 然后導致索引鍵前綴限制為767字節 (需要去研究一下) .如果禁用innodb_large_prefix,不管是什么表,索引鍵前綴限制為767字節。----參考
  4. 新建mysql庫或者表的時候還有一個排序規則: (之前一直沒去想)
    utf8_unicode_ci比較准確,utf8_general_ci速度比較快。通常情況下 utf8_general_ci的准確性就夠我們用的了, 如果是utf8mb4那么對應的就是 utf8mb4_general_ci utf8mb4_unicode_ci
  5. utf8和utf8mb4的區別: mb4就是most bytes 4的意思,專門用來兼容四字節的unicode. utf8mb4是utf8的超集,除了將編碼改為utf8mb4外不需要做其他轉換, 當然,為了節省空間,一般情況下使用utf8也就夠了.  原來mysql支持的 utf8 編碼最大字符長度為 3 字節,如果遇到 4 字節的寬字符就會插入異常了.
  6.        系統變量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

  7. 終於找到了原因, 去本地MySQL查看是否開啟了innodb_large_prefix, 這個參數是限制索引列長度
    show variables like 'innodb_large_prefix';         //查看是否開啟innodb_large_prefix 的命令

    發現本地的MySQL默認是沒有開啟的. 線上的是開啟了的(不過不知道是之前有人開啟的, 還是5.7版本默認開啟的. 應該是默認開啟的! 反正不用管這些~無所謂) 每個人的MySQL配置不同, 要看具體什么情況了.....

  8. 關於如何開啟innodb_large_prefix,解決方案也在這里:  可參考https://www.cnblogs.com/kerrycode/p/9680881.html
  9. 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM