重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
也就是说不用管每条记录的id会不会变咯?
创新互联建站不只是一家网站建设的网络公司;我们对营销、技术、服务都有自己独特见解,公司采取“创意+综合+营销”一体化的方式为您提供更专业的服务!我们经历的每一步也许不一定是最完美的,但每一步都有值得深思的意义。我们珍视每一份信任,关注我们的成都做网站、网站制作质量和服务品质,在得到用户满意的同时,也能得到同行业的专业认可,能够为行业创新发展助力。未来将继续专注于技术创新,服务升级,满足企业一站式营销型网站建设需求,让再小的品牌网站制作也能产生价值!
方法一:使用select ...into outfile 和 load data infile ...
1.导出除了字段id的所有字段
2.清空表
3.导入数据
例子:
#建立测试表 lt1
mysql create table lt1(id int(10) auto_increment,v1 int(10) default 0,v2 int(10
) default 0,primary key(id))engine=innodb,default charset=utf8;
Query OK, 0 rows affected (0.11 sec)
#插入测试数据
mysql insert into lt1(v1,v2) values(1,1),(2,2),(3,3),(4,4),(5,5);
Query OK, 5 rows affected (0.06 sec)
Records: 5 Duplicates: 0 Warnings: 0
#删除id=4的数据
mysql delete from lt1 where id=4;
Query OK, 1 row affected (0.08 sec)
#查看测试表的数据,这时候id不连续。
mysql select * from lt1;
+----+------+------+
| id | v1 | v2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 5 | 5 | 5 |
+----+------+------+
4 rows in set (0.00 sec)
#将表中的v1,v2字段导出到lt1.xls中。
mysql select v1,v2 from lt1 into outfile 'd:/localdmp/data/lt1.xls';
Query OK, 4 rows affected (0.03 sec)
#清空lt1
mysql truncate table lt1;
Query OK, 0 rows affected (0.08 sec)
#从lt1.xls文件中导入数据到lt1中,注意指定字段名(v1,v2)。
mysql load data infile 'd:/localdmp/data/lt1.xls' into table lt1(v1,v2);
Query OK, 4 rows affected (0.08 sec)
Records: 4 Deleted: 0 Skipped: 0 Warnings: 0
#现在id连续了
mysql select * from lt1;
+----+------+------+
| id | v1 | v2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 5 | 5 |
+----+------+------+
4 rows in set (0.00 sec)
方法二:
使用临时表create table ...select ... 和 insert ...select ...
例子:
#还是lt1表,先清空
mysql truncate table lt1;
Query OK, 0 rows affected (0.08 sec)
#插入测试数据,id 1-5
mysql insert into lt1(v1,v2) values(1,1),(2,2),(3,3),(4,4),(
Query OK, 5 rows affected (0.06 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql select * from lt1;
+----+------+------+
| id | v1 | v2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 4 | 4 |
| 5 | 5 | 5 |
+----+------+------+
5 rows in set (0.00 sec)
#把id=4删除
mysql delete from lt1 where id=4;
Query OK, 1 row affected (0.06 sec)
mysql select * from lt1;
+----+------+------+
| id | v1 | v2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 5 | 5 | 5 |
+----+------+------+
4 rows in set (0.00 sec)
#创建临时表lt11
mysql create table lt11 select v1,v2 from lt1;
Query OK, 4 rows affected (0.11 sec)
Records: 4 Duplicates: 0 Warnings: 0
#临时表的数据
mysql select *from lt11;
+------+------+
| v1 | v2 |
+------+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 5 | 5 |
+------+------+
4 rows in set (0.00 sec)
#清空lt1
mysql truncate table lt1;
Query OK, 0 rows affected (0.06 sec)
#将临时表lt11的数据插入lt1中
mysql insert into lt1 (v1,v2) select v1,v2 from lt11;
Query OK, 4 rows affected (0.06 sec)
Records: 4 Duplicates: 0 Warnings: 0
#查看结果,id已经连续。
mysql select *from lt1;
+----+------+------+
| id | v1 | v2 |
+----+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 5 | 5 |
+----+------+------+
4 rows in set (0.00 sec)
唔,这么辛苦,给个最佳至少啊...
清空MySQL表,使ID重新从1自增的步骤如下:
我们需要准备的材料分别是:电脑、Mysql查询器。
1、首先,打开Mysql查询器,连接上相应的mysql连接。
2、鼠标右击需要清空自增ID的表,选择“设计表”,再将选项卡切换到“设置”栏,会发现虽然清空了表,但是自动递增的数值仍然没有变回1。
3、在自动递增栏,将数值更改为数字1,并点击“保存”按钮。
4、此时会发现,再新增数据时,ID自动从1开始递增了。
重置mysql的自增列AUTO的方法有:
方法一: delete from tb1;
ALTER TABLE tbl AUTO_INCREMENT = 100;
注意:如果表列和数据很多, 速度会很慢, 如90多万条, 会在10分钟以上.
方法二: truncate tb1;
重置mysql的自增列 的步骤如下:
1. 支持设置自增列的值 ;
ALTER TABLE table_name AUTO_INCREMENT = 1;
这种方式只能设置大于当前使用的值,不能设置小于等于当前已经使用的自增列的值。myisam如果设置小于等于,则自增列的值会自动设置为 :
当前最大值加1,innodb则不会改变。
2.通过TRUNCATE把自增列设置为0,从MySQL 5.0.13开始TRUNCATE重置自增列为0.myisam和innode都一样。
TRUNCATE TABLE table_name;
3.drop和create重建表方式重置自增列为0
DROP TABLE table_name;
CREATE TABLE table_name { ... };
使用两种方法重置mysql的自增列AUTO的好处有:
方法一:可设置 AUTO_INCREMENT 为任意值开始;
方法二:简单, AUTO_INCREMENT 值重新开始计数;
注意:使用以上方法都会将现有数据删除.
1、创建表时指定AUTO_INCREMENT自增值的初始值(即起始值):
CREATE TABLE XXX (ID INT(5) PRIMARY KEY AUTO_INCREMENT) AUTO_INCREMENT=100;
2、通过 ALTER TABLE 修改初始值(但是要大于表中的 AUTO_INCREMENT 自增值,否则设置无效):
ALTER TABLE XXX AUTO_INCREMENT=100;
3、如果自增序列的最大值被删除了,则在插入新记录时,该值被重用:
就是说如果表中原本有AUTO_INCREMENT属性值连续为78、100的值,但100这个数据被删除了,下此再添加数据的时候自增值为101,100被重用了。
即使在你将整个表中的所有数据delete清空后,之前的自增序列最大值还是会被重用。
解决办法是:
使用 ALTER TABLE XXX AUTO_INCREMENT=0; 重新设置自增初始值。
1.
支持设置自增列的值
ALTER
TABLE
table_name
AUTO_INCREMENT
=
1;
不过这种方式只能设置大于当前使用的值,不能设置小于等于当前已经使用的自增列的值。myisam如果设置小于等于,则自增列的值会自动设置为当前最大值加1。innodb则不会改变。
2.通过TRUNCATE把自增列设置为0,从MySQL
5.0.13开始TRUNCATE就能重置自增列为0.myisam和innode都是如此。
TRUNCATE
TABLE
table_name;
注意:TRUNCATE
会清空表中数据
3.drop和create重建表方式重置自增列为0
DROP
TABLE
table_name;
CREATE
TABLE
table_name
{
...
};
MYSQL的自增列在实际生产中应用的非常广泛,相信各位所在的公司or团队,MYSQL开发规范中一定会有要求尽量使用自增列去充当表的主键,为什么DBA会有这样的要求,各位在使用MYSQL自增列时遇到过哪些问题?这些问题是由什么原因造成的呢?本文由浅入深,带领大家彻底弄懂MYSQL的自增机制。
1. 通过auto_increment关键字来指定自增的列,并指定自增列的初始值为1。
[root@localhost][test1]Create table t(id int auto_increment ,namevarchar(10),primary key(id))auto_increment=1;
QueryOK, 0 rows affected (0.63 sec)
2. 自增列上必须有索引,将t表的主键索引删除掉,会报错
[root@localhost][test1]alter table t drop primary key;
ERROR1075 (42000): Incorrect table definition; there can be only one auto column andit must be defined as a key
3. 设定auto_increment_increment参数,可以调整自增步长,该参数有session级跟global级,在分库分表以及双主or多主的模式下比较有用。
4. 一个表上只能有一个自增列
5. Mysql5.7及以下版本,innodb表的自增值保存在内存中,重启后表的自增值会设为max(id)+1,而myisam引擎的自增值是保存在文件中,重启不会丢失。Mysql8.0开始,innodb的自增id能持久化了,重启mysql,自增ID不会丢。
首先:表中自增列的上限是根据自增列的字段类型来定的。
若设定了自增id充当主键,当达到了自增id的上限值时,会发生什么样的事情呢?还是以上面创建的 t表为例, 先回顾它的表结构:
CREATETABLE `t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_binDEFAULT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
无符号的int类型,上限是2147483647。这里我们将表的自增值设为2147483647,再插入两行数据:
[root@localhost][test1]alter table t auto_increment=2147483647;
QueryOK, 0 rows affected (0.01 sec)
Records:0 Duplicates: 0 Warnings: 0
[root@localhost][test1]insert into t(name) values ('test');
QueryOK, 1 row affected (0.01 sec)
[root@localhost][test1]insert into t(name) values ('test');
ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'
可以看到,第一个插入没问题,因为自增列的值为2147483647,这是达到了上限,还没有超过,第二行数据插入时,则报出主键重复,在达到上限后,无法再分配新的更大的自增值,也没有从1开始从头分配,在这里表的auto_increment值会一直是2147483647。
对于写入量大,且经常删除数据的表,自增id设为int类型还是偏小的,所以我们为了避免出现自增id涨满的情况,这边统一建议自增id的类型设为unsigned bingint,这样基本可以保障表的自增id是永远够用的。
这里内容比较多,innodb是索引组织表,所以涉及到索引的知识,但这不是本文的重点,我们快速回顾索引知识:
1. Innodb索引分为主键跟辅助索引,主键即全表,辅助索引叶子节点保存主键的值,而主键的叶子节点保存数据行,中间节点存着叶子节点的路由值。
2. Innodb存储数据(索引)的单位是页,这里默认是16K,这也意味着,数据本身越小,一个页中能存数据的量越多,而检索效率不仅仅由索引的层数来决定,更是由一次能够缓存的数据量来定,也就是说数据本身越小,则一次IO能够提取到缓冲区的数据越多(OS每次IO的量是固定的4K),查询的效率越好。
其实能够理解索引的结构及索引写入插入、更新的原理,则自然就明白为何建议使用自增id。这里我直接列出使用自增id 当主键的好处吧:
1. 顺序写入,避免了叶的分裂,数据写入效率好
2. 缩小了表的体积,特别是相比于UUID当主键,甚至组合字段当主键时,效果更明显
3. 查询效率好,原因就是我上面说到索引知识的第二点。
4. 某些情况下,我们可以利用自增id来统计大表的大致行数。
5. 在数据归档or垃圾数据清理时,也可方便的利用这个id去操作,效率高。
容易出现不连续的id
有的同志会发现,自己的表中id值存在空洞,如类似于1、2、3、8、9、10这样,有的适合有想依赖于自增id的连续性来实现业务逻辑,所以会想方设法去修改id让其变的连续,其实,这是没有必要的,这一块的业务逻辑交由MySQL实现是很不理智的,表的记录小还好,要是表的数据量很大,修改起来就糟糕了。那么,为什么自增id会容易出现空洞呢?
自增id的修改机制如下:
在MySQL里面,如果字段id被定义为AUTO_INCREMENT,在插入一行数据的时候,自增值的行为如下:
1. 如果插入数据时id字段指定为0、null 或未指定值,那么就把这个表当前的
AUTO_INCREMENT值填到自增字段;
2. 如果插入数据时id字段指定了具体的值,就直接使用语句里指定的值。
根据要插入的值和当前自增值的大小关系,自增值的变更结果也会有所不同。假设,某次要插入的值是X,当前的自增值是Y。
1. 如果XY,那么这个表的自增值不变;
2. 如果X≥Y,就需要把当前自增值修改为 新的自增值 。
新的自增值生成算法是:从auto_increment_offset开始,以auto_increment_increment为步长,持续叠加,直到找到第一个大于X的值,作为新的自增值。
Insert、update、delete操作会让id不连续。
Delete、update:删除中间数据,会造成空动,而修改自增id值,也会造成空洞(这个很少)。
Insert:插入报错(唯一键冲突与事务回滚),会造成空洞,因为这时候自增id已经分配出去了,新的自增值已经生成,如下面例子:
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
| 1| aaa |
| 2| aaa |
| 3| aaa |
| 4| aaa |
+----+------+
4 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
| 5 |
+----------------+
1 row in set (0.00 sec)
[root@localhost][test1] begin;
Query OK, 0 rows affected (0.00 sec)
[root@localhost][test1] insert intot(name) values('aaa');
Query OK, 1 row affected (0.00 sec)
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
| 1| aaa |
| 2| aaa |
| 3| aaa |
| 4| aaa |
| 5| aaa |
+----+------+
5 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
| 6 |
+----------------+
1 row in set (0.00 sec)
[root@localhost][test1] rollback;
Query OK, 0 rows affected (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
| 6 |
+----------------+
1 row in set (0.01 sec)
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
| 1| aaa |
| 2| aaa |
| 3| aaa |
| 4| aaa |
+----+------+
4 rows in set (0.00 sec)
可以看到,虽然事务回滚了,但自增id已经回不到从前啦,唯一键冲突也是这样的,这里就不做测试了。
在批量插入时(insert select等),也存在空洞的问题。看下面实验:
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
| 1| aaa |
| 2| aaa |
| 3| aaa |
| 4| aaa |
+----+------+
4 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
| 5 |
+----------------+
1 row in set (0.00 sec)
[root@localhost][test1] insert intot(name) select name from t;
Query OK, 4 rows affected (0.04 sec)
Records: 4 Duplicates: 0 Warnings: 0
[root@localhost][test1] select * fromt;
+----+------+
| id | name |
+----+------+
| 1| aaa |
| 2| aaa |
| 3| aaa |
| 4| aaa |
| 5| aaa |
| 6| aaa |
| 7| aaa |
| 8| aaa |
+----+------+
8 rows in set (0.00 sec)
[root@localhost][test1] selectAuto_increment from information_schema.tables where table_name='t';
+----------------+
| Auto_increment |
+----------------+
| 12 |
+----------------+
1 row in set (0.00 sec)
可以看到,批量插入,导致下一个id值不为9了,再插入数据,即产生了空洞,这里是由mysql申请自增值的机制所造成的,MySQL在批量插入时,若一个值申请一个id,效率太慢,影响了批量插入的速度,故mysql采用下面的策略批量申请id。
1. 语句执行过程中,第一次申请自增id,会分配1个;
2. 1个用完以后,这个语句第二次申请自增id,会分配2个;
3. 2个用完以后,还是这个语句,第三次申请自增id,会分配4个;
4. 依此类推,同一个语句去申请自增id,每次申请到的自增id个数都是上一次的两倍。
在对自增列进行操作时,存在着自增锁,mysql的innodb_autoinc_lock_mode参数控制着自增锁的上锁机制。该参数有0、1、2三种模式:
0:语句执行结束后释放自增锁,MySQL5.0时采用这种模式,并发度较低。
1:mysql的默认设置。普通的insert语句申请后立马释放,insert select、replace insert、load data等批量插入语句要等语句执行结束后才释放,并发读得到提升
2:所有的语句都是申请后立马释放,并发度大大提升!但是在binlog为statement格式时,主从数据会发生不一致。这一块网上有很多介绍,我不做介绍了。
在彻底了解了MYSQL的自增机制以后,在实际生产中就能灵活避坑,这里建议不要用自增id值去当表的行数,当需要对大表准确统计行数时,可以去count(*)从库,如果业务很依赖大表的准确行数,直接弄个中间表来统计,或者考虑要不要用mysql的innodb来存储数据,这个是需要自己去权衡。另外对于要求很高的写入性能,但写入量又比较大的业务,自增id的使用依然存在热点写入的问题,存在性能瓶颈,这时候可通过分库分表来解决。