SQL 标准支持多种固有类型。
每种类型都可能包含一个被称作空值的特殊值。空值表示一个缺失的值,该值可能存在但并不为人所知,或者可能根本不存在。在可能的情况下,我们希望禁止加入空值,正如我们马上将看到的那样。
文本字符串类型 | 大小(Bytes) | 用途 |
---|---|---|
CHAR | 0-255 | 定长字符串 |
VARCHAR | 0-65535 | 可变长字符串 |
TINYTEXT | 0-255 | 短文本字符串 |
TEXT | 0-65535 | 长文本数据 |
MEDIUMTEXT | 0-16777215 | 中等长度文本数据 |
LONGTEXT | 0-4294967295 | 极大文本数据 |
TINYBLOB | 0-255 | 不超过 255 个字符的二进制字符串 |
BLOB | 0-65535 | 二进制形式的长文本数据 |
MEDIUMBLOB | 0-16777215 | 二进制形式的中等长度文本数据 |
LONGBLOB | 0-4294967295 | 二进制形式的极大文本数据 |
Q: CHAR 和 VARCHAR 的区别?
对于 CHAR(M) 类型:
CHAR(M)
类型一半需要预先定义字符串长度,如果不指定 (M)
,则表示长度默认是 1 个字符CHAR
类型声明的长度小,则会在 右侧填充 空格以达到指定的长度。当 MySQL 检索 CHAR
类型的数据时,CHAR
类型的字段会去除尾部的空格CHAR
类型字段时,声明的字段长度即为 CHAR
类型字段所占的存储空间的字节数对于 VARCHAR(M) 类型:
VARCHAR(M)
定义时,必须指定长度 M
,否则报错VARCHAR(20)
指的是 20 字节,如果存放 UTF8 汉字时,只能存 6 个(每个汉字 3 字节);MySQL5.0 版本以上,VARCHAR(20)
指的是 20 字符VARCHAR
类型的字段数据时,会保留数据尾部的空格。VARCHAR
类型的字段所占用的存储空间为字符串实际长度加 1 个字节两者相同点:
CHAR(n)
、VARCHAR(n)
中的 n
都代表字符的个数CHAR(n)
、VARCHAR(n)
最大长度 n 的限制后,字符串会被截断不同点:
CHAR(n)
不论实际存储的字符数多少都会占用 n 个字符的空间,而 VARCHAR(n)
只会占用实际字符应该占用的字节空间加 1(实际长度 length,0<=length<255)或加 2(length>255)。因为 VARCHAR(n)
保存数据时除了要保存字符串之外还会加一个字节来记录长度(如果列声明长度大于 255 则使用两个字节来保存长度)。CHAR(n)
的存储上限为 255 字节。CHAR(n)
在存储时会截断尾部的空格,而 VARCHAR(n)
不会。CHAR(n)
是适合存储很短的、一般固定长度的字符串。例如,CHAR(n)
非常适合存储密码的 MD5 值,因为这是一个定长的值。对于非常短的列,CHAR(n)
比 VARCHAR(n)
在存储空间上也更有效率。
哪些情况适用
CHAR
或VARCHAR
更好?
101
、201
...这样很短的信息应该用 CAHR
,因为 VARCHAR
还要占用 Byte 用于存储信息长度, 本来打算节约存储的,结果得不偿失CHAR
应该更合适。因为他固定长度,VARCHAR
动态根据长度的特性就消失了,而且还要占个长度信息VARCHAR
每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的列,那就要有很多的精力用于计算,而这些对于 CHAR
来说是不需要的MyISAM
数据引擎和数据列:MyISAM 数据表,最好使用固定长度(CHAR)的数据列代替可变长度(VARCHAR)的数据列,这样使得整个表静态化,从而使数据检索更快,用空间换时间MEMORY
存储引擎和数据列:MEMORY 数据表目前都使用固定长度的数据行存储,因此无论是用 CHAR 或 VARCHAR 列都没有关系,两者都是作为 CHAR 类型处理InnoDB
存储引擎,建议使用 VARCHAR 类型,因为对于 InnoDB 数据表,内部的行存储格式并没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),而且主要影响性能的因素时数据行使用的存储总量,由于 CHAR 平均占用的空间多余 VARCHAR,所以除了间断并且固定长度的,其他考虑 VARCHAR,这样节省空间,对磁盘 I/O 和数据存储总量比较好CHAR(M)
或者 VARCHAR(M)
TEXT 文本类型,可以存比较大的文本段,搜索速度稍慢,因此如果不是特别大的内容,建议使用 CHAR 或 VARCHAR 代替。还有 TEXT 类型不用加默认值,加了也没用。而且 TEXT 和 BLOB 类型的数据删除后容易导致“空洞”,使得文件碎片比较多,所以频繁使用的表不建议包含 TEXT 类型字段,建议单独分出去,单独使用一个表。
编码字符 | 一个字母 | 一个中文字符 | 字母标点 | 中文标点 |
---|---|---|---|---|
ASCII 码 | 1 字节 | |||
UTF-8 编码 | 1 字节 | 3 字节 | 1 字节 | 3 字节 |
Unicdoe 编码 | 2 字节 | 2 字节 | 2 字节 | 2 字节 |
GB 2312 编码或 GBK 编码 | 1 字节 | 2 字节 | 1 字节 | 2 字节 |
UTF-16 | 2 字节 | 2 字节 | 2 字节 | 2 字节 |
UTF-32 | 4 字节 | 4 字节 | 4 字节 | 4 字节 |
Latin1 | 1 字节 | 1 字节 |
类型 | 有符号 | 无符号 | 大小(Bytes) | 用途 |
---|---|---|---|---|
TINYINT | (-128, 127) | [0, 255] | 1 | 非常小的整数值 |
SMALLINT | (-32768, 32767) | [0, 65535] | 2 | 较小的整数值 |
MEDIUMINT | -8388608, 8388607 | [0, 2^24-1] | 3 | 中等大小整数值 |
INT 或 INTEGER | (-2 147 483 648,2 147 483 647) | [0, 2^32-1] | 4 | 标准整数 |
BIGINT | [0, 2^64-1] | 8 | 较大整数值 |
适用场景:
TINYINT
:一般用于枚举数据,例如系统设定取值范围很小且固定场景SMALLINT
:可以用于较小范围的统计数据,例如统计工厂的固定资产库存数量等MEDIUMINT
:用于较大整数的计算,例如车展每日的客流量等INT
/ INTEGER
:取值范围足够大,一般情况下不用考虑超限问题,例如商品编号BIGINT
:只有当你处理特别巨大的整数时才会用到,例如双十一的交易量、大型门户网站点击量、证券公司衍生产品持仓等类型 | 有符号 | 无符号 | 大小(Bytes) | 用途 |
---|---|---|---|---|
FLOAT | 4 | 单精度 浮点数值 | ||
DOUBLE | 8 | 双精度 浮点数值 | ||
DECIMAL(M, D) | 依赖于 M 和 D 的值 | m | 可以存储大整数或高精度,可以理解为字符串处理 |
UNSIGNED
属性只针对整数类型,表示无符号的意思(相当于禁用负值)。
取值范围如果加了 UNSIGNED
,则最大值翻倍,例如,TINYINT
类型最大是 127,那 TINYINT UNSIGNED
最大就可以到 127 * 2 => 255
。
ZEROFILL
表示令填充(如果某列为 ZEROFILL,那么 MySQL 会自动为当前列添加 UNSIGNED 属性),如果指定了 ZEROFILL 只是表示不够 M 位时,用 0 在左边填充,如果超过 M 位,只要不超过数据存储范围即可。
原来,在 int(M)
中,M 的值跟 int(M)
所占多少存储空间并无任何关系。int(3)
、int(4)
、int(8)
在磁盘上都是占用 4 bytes 的存储空间,也就是说,int(M)
必须和 UNSINGED 和 ZEROFILL 一起使用才有意义,如果整数值超过 M 位,就按实际位数存储,只是无须再用字符 0 进行填充。
每个时间类型有一个有效值范围和一个”零“值,当指定不合法的 MySQL 不能表示的值时使用”零“值。
类型 | 大小(Bytes) | 范围 | 格式 | 用途 |
---|---|---|---|---|
YEAR | 1 | 1901 / 2155 | YYYY | 年份值 |
TIME | 3 | -838:59:59 / 838:59:59 | HH:MM:SS | 时间值或持续时间 |
DATE | 3 | 1000-01-01 / 9999-12-31 | YYYY-MM-DD | 日期值 |
DATETIME | 8 | 1000-01-01 00:00:00 / 9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP | 4 | 1970-01-01 00:00:00 / 2038 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
注意事项:
TIMESTAMP
:存储数据的时候需要对当前时间所在的时区进行转换,查询数据的时候再将时间转换回当前的时区。因此,使用 TIMSTAMP
存储的同一个时间值,在不同的时区查询时会显示不同的时间