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 存储的同一个时间值,在不同的时区查询时会显示不同的时间