問題描述 新建表或者修改表varchar欄位長度的時候,出現這個錯誤 Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes stora ...
問題描述
新建表或者修改表varchar欄位長度的時候,出現這個錯誤
Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
大概意思就是行大小太大,不能超過65535
長度改為21842就正常了,這是為什麼?
分析
最終我們執行正確的SQL語句
CREATE TABLE `all_type_forlan` (
`id` int(20) NOT NULL COMMENT 'id',
`base_info` varchar(21842) DEFAULT NULL COMMENT '基本詳細',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這裡的21842長度是怎麼來的?
首先它是什麼意思?表示21842字元
首先來瞭解幾個規則,對我們的字元數有影響的規則
1、MySQL規則
編碼規則
不同字元集下,占用空間不一樣
gbk編碼中,1個字元占用2個位元組
utf8編碼(預設)中,1個字元占用3個位元組
utf8mb4編碼中,1個字元占用4個位元組
存儲規則
varchar除了存儲字元,還需要額外的空間來存儲長度和是否為NULL,分別占用1-2位元組和1位元組
行大小限制
MySQL 表的內部表示具有 65,535 位元組的最大行大小限制,即使存儲引擎能夠支持更大的行。 BLOB 和 TEXT列僅對行大小限制貢獻 9 到 12 個位元組,因為它們的內容與行的其餘部分分開存儲
2、驗證
根據行最大65535位元組,我們選擇utf8編碼,那我們最多可以設置的字元數為65535/3=21845
還是報錯了,因為我們還需要減去額外的存儲(長度和是否為NULL),65535-3=65532/2=21844,設置成21844就成功了
驗證NULL占用1個位元組
65535-1-3=65531/3=21,843.66666666667,向下取整,最多只能21843,所以報錯啦,看下圖說明:tinyint占用1個位元組、varchar的長度和是否為NULL占用3個位元組
我們把varchar欄位設為不是null,此時21844可以設置成功說明:65535-1-2=65532/3=21844
3、結論
所以,至此,我們就知道為什麼21842才可以了
計算規則=(65535-4-2-1)/3=21,842.66666666667,向下取整,就是21842說明:int占用4個位元組,varchar的長度和是否為NULL占用3個位元組,使用了utf8編碼,1個字元占用3個位元組
解決方案
如果長度需要加長,將欄位類型改為TEXT或BLOB
如果只是想設置一個最大值,那可以根據計算規則進行調整
拓展
為什麼我們經常使用varchar(255),不使用varchar(256)?
首先我們使用的varchar,除了存儲字元內容,還需要額外存儲長度和是否為NULL
因為varchar類型的欄位長度在超過255後,需要2個位元組來存儲長度,因為1個位元組=8位,可以表示的長度為255,2個位元組=16位,可以表示的長度為65535
所以varchar(256)會比varchar(255)多占用1個位元組來存儲長度
MySQL列數限制
MySQL 對每個表有 4096 列的硬性限制,但對於給定的表,有效最大值可能會更少,因為表的最大行大小限制了列的數量