数据类型
数据值类别
数值:
- 精确值:整数 带小数点的数
- 位域值:
b'1000'
代表8
字符串值:
'cxk' -- 推荐使用单引号
二进制串比较是逐字节比较
非二进制串根据排序规则比较
日期时间值:
'2020-08-25'
'11:47:00'
'2020-08-25 11:47:00'
SELECT '2020-08-25 11:47:00' + INTERVAL 2 DAY;
空间值:(10 20)
布尔值:0会被当成假 非0非NULL会被当成真
NULL值:\N
会被当成NULL
整型
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 32, 64 位存储空间,一般情况下越小的列越好
整数类型可以附带UNSIGNED属性,这可以使它的正数表示范围提高一倍。
同时,在定义数据类型时的INT(11) 这里的11指的是在交互终端下显示的字符个数,INT(1)和INT(20)在存储和计算上都是相同的
浮点数
FLOAT 和 DOUBLE 为浮点类型,DECIMAL 为高精度小数类型,DECIMAL 的计算比浮点类型需要更高的代价
字符串
一种是定长的(char),一种是变长的(varchar)。
变长类型使用额外的1个或两个字节来存储长度,能够节省空间,因为只需要存储必要的内容,但当变长类型发生UPDATE操作后,需要执行额外的操作
存储和检索时,VARCHAR 末尾的空格会保留下来,而会 CHAR 末尾的空格会被删除。
填充和删除空格的行为在所有存储引擎上都一样,这是在MySQL服务器层处理的。
另外两种类型是BLOB和TEXT,都是为了存储很大的数据而设计出来的。当这些数据很大时,一些存储引擎会将这些数据存储在外部,通过指针来引用,这两种类型不能将全部的数据用以建索引,除非不得以,否则不要使用这两种类型。
枚举
MySQL底层将枚举转换为整数来进行处理,所以枚举的性能相较于字符串快,但缺点是一旦是枚举列表发生变化,就必须通过ALTER TABLE来进行添加。
时间和日期
- DATE
- TIME
- YEAR
- DATETIME
能够保存从 1000 年到 9999 年的日期和时间,精度为秒,时区无关
- TIMESTAMP
和 UNIX 时间戳相同,应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高
位数据类型
谨慎使用BIT类型。SET类型类似于枚举。
序列
使用 AUTO_INCREMENT 来生成序列
自增值的行为如下:
- 如果插入数据时 id 字段指定为 0、null 或未指定值,那么就把这个表当前的 AUTO_INCREMENT 值填到自增字段
- 如果插入数据时 id 字段指定了具体的值,就直接使用语句里指定的值
通用
- 每个表只能有一个列具有 AUTO_INCREMENT
- 列必须建立索引
- 列为 NOT NULL
- 使用
LAST_INSERT_ID()
获取最后一个序号 - 插入0或NULL都会生成自增ID
- 某些存储引擎可以复用被删除的序列
存放位置
- MyISAM 引擎的自增值保存在数据文件中
- InnoDB 引擎的自增值在5.7之前存放在内存中,数据库每次启动都会去找自增值的最大值 max(id),然后将 max(id)+1 作为这个表当前的自增值,8.0之后将自增值的变更记录在了 redo log 中,重启的时候依靠 redo log 恢复重启之前的值
存储引擎特有
MyISAM:
- 不会复用被删除的序列
- 默认从1开始
- 使用
ALTER TABLE tb AUTO_INCREMENT = 10
语句更改当前序列的值
InnoDB:
- CREATE TABLE 时可以指定起始值
- 事务被回 序列不会回滚
需要考虑的问题
- AUTO_INCREMENT 只能生成正整数序列 使用 UNSINGED 可以获得双倍的空间
- TRUNCATE TABLE 会重置序列
批量插入批量申请自增 id:
- 语句执行过程中,第一次申请自增 id,会分配 1 个
- 1 个用完以后,这个语句第二次申请自增 id,会分配 2 个
- 2 个用完以后,还是这个语句,第三次申请自增 id,会分配 4 个
- 依此类推,同一个语句去申请自增 id,这样可能就会导致申请的 ID 并不会全部用完,ID会不连续
不使用 AUTO_INCREMENT 生成序列
UPDATE seq SET n = LAST_INSERT_ID(n+1); -- 调用有参方法 下次无参调用就会返回n+1
INSERT INTO tb(..) VALUES(LAST_INSERT_ID()...)
START TRANSACTION;
UPDATE seq SET n = n+1;
COMMIT;
自增锁
MySQL 5.0 版本的时候,自增锁的范围是语句级别。也就是说,如果一个语句申请了一个表自增锁,这个锁会等语句执行结束以后才释放
MySQL 5.1.22 版本引入了一个新策略,新增参数 innodb_autoinc_lock_mode:
- 设置为 0 时,表示采用之前 MySQL 5.0 版本的策略,即语句执行结束后才释放锁
- 设置为 1 时:普通 insert 语句,自增锁在申请之后就马上释放;类似 insert … select 这样的批量插入数据的语句,自增锁还是要等语句结束后才被释放
- 设置为 2 时,所有的申请自增主键的动作都是申请后就释放锁
MySQL 的 ID 及上限
- AUTO_INCREMENT id,取决于数据类型
- InnoDB 系统自增 row_id:InnoDB 表没有指定主键时,InnoDB 创建一个不可见的,长度为 6 个字节的自增 ID,当这个 ID 发生溢出,新写入的行就会覆盖原有的行
- Xid:第一条执行语句的query_id;而query_Id是在每次执行语句时都会自增,这个 ID 的上限是 8 字节
- trx_id:MVCC 所用来隔离不同事务,标志不同事务的ID,由于 trx_id 不会清零,超出上限之后会产生脏读
- thread_id:系统保存了一个全局变量 thread_id_counter,每新建一个连接,就将 thread_id_counter 赋值给这个新连接的线程变量,上限是4个字节
表达式
SELECT (SELECT ...),.. FROM ...; -- 标量子查询提供单个值必须使用括号
运算符
算术:
+ - * / %
- DIV
a DIV b
整除
逻辑:
- AND OR XOR NOT
位运算:
& | ^ << >>
比较运算符:
类型转换
MySQL 会尽量将值转换成表达式所需要的类型
选择
- 具体对应的数据类型
- 考虑值是否在数据类型所对应的区间