当我们使用 MySQL 进行数据存储时,一般会为一张表设置一个自增主键,当有数据行插入时,该主键字段则会根据步长与偏移量增长(默认每次+1)。
创新互联专注于企业成都营销网站建设、网站重做改版、惠水网站定制设计、自适应品牌网站建设、H5技术、商城网站开发、集团公司官网建设、外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为惠水等各大城市提供网站开发制作服务。
下文以 Innodb 引擎为主进行介绍,使用自增主键的好处有很多,如:索引空间占比小、范围查询与排序都友好、避免像 UUID 这样随机字符串带来的页分裂问题等...
当我们对该表设置了自增主键之后,则会在该表上产生一个计数器,用于为自增列分配 ID 。
自增的值并不是保存在表结构信息内的,对于不同的版本它们有如下的区别:
计数器的值存储在内存中的,重启后丢弃,下一次将读取最大的一个自增ID往后继续发号。
计数器的值将会持久化到磁盘。在每次发号时都将写入 Redolog ,并在每个 Checkpoint 都进行保存,重启时候使用 Redolog 恢复重启之前的值。
可以预先确定插入行数的语句(像简单 insert 的语句包含多个 value 这种情况也是属于简单插入,因为在进行插入时就已经可以确定行数了)
预先不知道要插入的行数的语句(包括 INSERT ... SELECT, REPLACE ... SELECT 和 LOAD DATA 语句,但不包括 plain INSERT )
如果一个事务正在向表中插入值,则会产生表级的共享锁,以便当前事务插入的行接收连续的主键值。
当处于[ 传统模式 ]与[ 连续模式 ]时,每次访问计数器时都会加上一个名为 AUTO-INC 的表级锁
传统模式:锁只持有到该语句执行结束,注意是语句结束,不是事务结束
连续模式:批量插入时锁持有到该语句执行结束,简单插入时锁持有到申请完自增ID后即释放,不直到语句完成
通过调整 innodb_autoinc_lock_mode 配置项,可以定义 AUTO-INC 锁的模式,不同的模式对应的策略与锁的粒度也将不同。
当使用基于 Binlog 的复制场景时,对于 statement(SBR)同步模式下只有[ 传统模式 ]与[ 连续模式 ]能保证语句的正确性。
基于 row(RBR)行复制的情况下任何配置模式都可以。
执行语句时加 AUTO-INC 表级锁,执行完毕后释放
针对 Bulk Inserts 时才会采用 AUTO-INC 锁,而针对 Simple Inserts 时,则采用了一种新的轻量级的互斥锁来分配 auto_increment 列的值。
该模式下可以保证同一条 insert 语句中新插入的自增 ID 都是连续的,但如果前一个事务 rollback 丢弃了一部分 ID 的话也会存在后续 ID 出现间隔的情况。
来一个分配一个,不会产生 AUTO-INC 表级锁 ,仅仅会锁住分配 ID 的过程。
由于锁的粒度减少,多条语句在插入时进行锁竞争,自增长的值可能不是连续的。
且当 Binlog 模式为 statement(SBR)时自增 ID 不能保证数据的正确性
不一定,业务也不应该过分依赖 MySQL 自增 ID 的连续性,在以下三种情况下,并不能保证自增 ID 的连续性:
假设已存在数据{1,张三},且张三所属的字段设置了唯一主键
此时再次插入{null,张三}时候,主键冲突插入失败,但表的计数器已由2变成了3
当下次插入{null,李四}的时候最终入库的会变成{3,李四}
在一个事务里进行数据的插入,但最后并没提交,而是执行了 Rollback 。那么计数器已递增的 ID 是不会返还的,而是被直接丢弃。
发生大量插入时可能会出现自增 ID 并不是连续的情况
当我们为表设置了自增主键后,自增 ID 的范围则与主键的数据类型长度相关。
如果没有一张表里没有设置任何主键,则会自动生成一个隐性的6字节的 row_id 作为主键,它的取值范围为 0 到 2^48-1。
row_id 是由一个全局的 dict_sys.row_id 参数进行维护的,所有没有主键的表都会用上它(并不是每一个表单独占一份 row_id list )
那么针对这两种主键,则会有以下两种情况发生:
当自增 ID 到达上限后,受到主键数据类型的影响,计数器发放的下一个 ID 也是当前这个 Max ID ,当执行语句时则会提示主键冲突。
建议根据业务合理规划,在进行表设计时就选择适合的数据类型。
当然也可以直接选择 Bigint 类型,它的取值范围是无符号情况下:0到 2^64–1(18446744073709551615)
这里并不是指 bigint 类型一定不会用完,毕竟一个有范围的持续增长的值一定会有溢出的时候,只是说一般场景下它都是足够使用的。
当 row_id 使用完后则又会从 0 开始发放,此时新插入的数据将覆盖回 row_id=0 的数据行。
由于它并不产生错误,还会造成数据的覆盖写。所以我们平时还是尽量给表都设置一个合理的主键才是。
在实际业务场景中,ID 常常需要返回给客户端用来进行相关业务操作。
假如我们有个 userinfo?uid=? 的 API 接口,而用户 ID 是自增的,这时会发生什么?
该接口通过简单的尝试就可以暴露出真实的业务用户总数,可以很方便的使用爬虫从1开始递增获取数据信息。
那么有的同学说,我既想使用自增 ID 带来的好处,也不想承受这种比较常见的问题,那该怎么办呢?
在输出或者获取前对指定字段进行可逆的转义操作
优点:实现起来比较简单,无论单体业务或者分布式应用都无需考虑对数据源的解析,只需在客户端实现自己的转义与解析方法即可;
缺点:业务入侵较大,且需要前后端各个合作方确认统一的标准;如果转义方法有调整,变更影响面也会很大;字符串长度会随ID长度而变化,使用空位填充也会特别明显;
优点:由于采用了时间戳进行 ID 生成,该 ID 是有序的,对范围查询与排序都比较友好;
缺点:需要保证发号节点的高可用性;另外由于生成时依赖时间戳,需要考虑时钟回拨与时钟同步的问题;
维护一份 ID 与 hash 的映射字典,它可以存在于客户端本身,也可以依赖其他如 Redis 、ETCD 之类的组件
优点:hash 长度不会随着 ID 长度或值的变化而变化;可以根据已有的 hash code 来造布隆过滤器;
缺点:业务入侵较大,查询时同样需要先根据 hash key 找到对应的 ID 值;需要考虑选择合适的 hash 算法以及解决 hash 冲突或扩容的问题。
create table cdat
(
localt char(20) not null,
cd char(5) not null,
snosat char(2) not null,
rnorec char(3) not null,
id INT(20) not null AUTO_INCREMENT,
primary key (id)
);
MySQL是一个开放源码的小型关联式数据库管理系统,开发者为瑞典MySQL AB公司。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。
系统特性
1.使用C和C++编写,并使用了多种编译器进行测试,保证源代码的可移植性
2.支持AIX、FreeBSD、HP-UX、Linux、Mac OS、NovellNetware、OpenBSD、OS/2 Wrap、Solaris、Windows等多种操作系统
3.为多种编程语言提供了API。这些编程语言包括C、C++、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。
4.支持多线程,充分利用CPU资源
5.优化的SQL查询算法,有效地提高查询速度
6.既能够作为一个单独的应用程序应用在客户端服务器网络环境中,也能够作为一个库而嵌入到其他的软件中。
7.提供多语言支持,常见的编码如中文的GB 2312、BIG5,日文的Shift_JIS等都可以用作数据表名和数据列名。
8.提供TCP/IP、ODBC和JDBC等多种数据库连接途径。
9.提供用于管理、检查、优化数据库操作的管理工具。
10.支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
11.支持多种存储引擎。
索引功能
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。索引不是万能的,索引可以加快数据检索操作,但会使数据修改操作变慢。每修改数据记录,索引就必须刷新一次。为了在某种程序上弥补这一缺陷,许多SQL命令都有一个DELAY_KEY_WRITE项。这个选项的作用是暂时制止MySQL在该命令每插入一条新记录和每修改一条现有之后立刻对索引进行刷新,对索引的刷新将等到全部记录插入/修改完毕之后再进行。在需要把许多新记录插入某个数据表的场合,DELAY_KEY_WRITE选项的作用将非常明显。另外,索引还会在硬盘上占用相当大的空间。因此应该只为最经常查询和最经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。从理论上讲,完全可以为数据表里的每个字段分别建一个索引,但MySQL把同一个数据表里的索引总数限制为16个。
1.InnoDB数据表的索引
与InnoDB数据表相比,在InnoDB数据表上,索引对InnoDB数据表的重要性要大得多。在InnoDB数据表上,索引不仅会在搜索数据记录时发挥作用,还是数据行级锁定机制的苊、基础。“数据行级锁定”的意思是指在事务操作的执行过程中锁定正在被处理的个别记录,不让其他用户进行访问。这种锁定将影响到(但不限于)SELECT、LOCKINSHAREMODE、SELECT、FORUPDATE命令以及INSERT、UPDATE和DELETE命令。出于效率方面的考虑,InnoDB数据表的数据行级锁定实际发生在它们的索引上,而不是数据表自身上。显然,数据行级锁定机制只有在有关的数据表有一个合适的索引可供锁定的时候才能发挥效力。
2.限制
如果WHERE子句的查询条件里有不等号(WHEREcoloum!=),MySQL将无法使用索引。类似地,如果WHERE子句的查询条件里使用了函数(WHEREDAY(column)=),MySQL也将无法使用索引。在JOIN操作中(需要从多个数据表提取数据时),MySQL只有在主键和外键的数据类型相同时才能使用索引。
如果WHERE子句的查询条件里使用比较操作符LIKE和REGEXP,MySQL只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。比如说,如果查询条件是LIKE'abc%‘,MySQL将使用索引;如果查询条件是LIKE'%abc’,MySQL将不使用索引。
在ORDERBY操作中,MySQL只有在排序条件不是一个查询条件表达式的情况下才使用索引。(虽然如此,在涉及多个数据表查询里,即使有索引可用,那些索引在加快ORDERBY方面也没什么作用)。如果某个数据列里包含许多重复的值,就算为它建立了索引也不会有很好的效果。比如说,如果某个数据列里包含的净是些诸如“0/1”或“Y/N”等值,就没有必要为它创建一个索引。
以插入语句的方法来解决此问题。
如下参考:
1.在添加字段之前,第一个zd应该首先检查tb1表的当前结构。
2.将字段列instance添加到表中,如下图。
3.再次查看表结构,比较添加字段之前和之后的情况。
4.最后,插入新的数据行,看看它是什么样子,最后就加入了自动增长字段如下图。
注意事项:
MySQL使用的SQL语言是访问数据库最常用的标准化语言。MySQL软件采用双重许可政策,分为社区版和商业版,由于其体积小,速度快,整体拥有成本低,尤其是开源这一特点,一般中小型网站开发都选择MySQL作为网站数据库。
设置自增列
MYSQL的自增列一定要是有索引的列,设置种子值要在表的后面设置
--mysql
-- 设置自增ID从N开始
CREATE TABLE empautoinc(
ID INT PRIMARY KEY AUTO_INCREMENT
) AUTO_INCREMENT = 100 ; --(设置自增ID从100开始)
insert into empautoinc(id) values(null);
Query OK, 1 row affected (0.00 sec)
mysql select * from empautoinc;
+-----+
| ID |
+-----+
| 100 |
+-----+
1 row in set (0.00 sec)
show table status like 'empautoinc'G;
*************************** 1. row ***************************
Name: empautoinc
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 1
Avg_row_length: 16384
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 101
Create_time: 2016-10-27 01:50:32
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
设置自增列的步长,可以分为全局级别和会话级别
如果是会话级别,那么当用户新建一个会话的时候,那么步长又回到了全局级别,所以mysql的步长跟sqlserver的步长有很大的不同
mysql不能设置为 表级别 的步长
私信666领取资料