1. delete和truncate
delete和truncate都是用于删除数据库表中数据的SQL语句,但是它们有以下几个区别:
1 . 对表结构的影响:
DELETE
语句删除表中的数据行,不会删除表的结构(表名、列等)。TRUNCATE
语句删除表中的所有数据行,不会删除表的结构(表名、列等),并重置表的自增长列的计数器。同时也会释放表占用的存储空间。
2 . 执行速度:
TRUNCATE
语句通常比DELETE
语句执行得更快,因为它只需要重置表的数据页,而不需要遍历整个表来删除每一行数据。
3 . 事务日志记录:
DELETE
语句会将每个被删除的行记录到事务日志中,因此可以进行回滚操作。TRUNCATE
语句会直接从磁盘中删除数据页,不会记录到事务日志中,因此无法进行回滚。
4 . WHERE 子句:
DELETE
语句可以使用WHERE
子句来有选择地删除满足条件的行。TRUNCATE
语句无法使用WHERE
子句,它会删除整个表的所有数据行。
总的来说,如果需要删除表中的全部数据,并且不需要保留删除记录,那么使用 TRUNCATE
语句更加高效。如果需要有选择地删除部分数据行,并且需要保留删除记录以便于回滚,那么使用 DELETE
语句更合适。
TRUNCATE TABLE table_name;
2. 自增列的问题
使用 DELETE
语句删除记录后,自增列的值不会自动重置。这是 MySQL 设计的一部分,旨在确保新的记录不会重复使用已删除记录的自增值。如果确实需要重置自增列的值,可以使用 ALTER TABLE
语句,但应谨慎操作,以避免数据完整性问题
-- 重置自增列的起始值,
ALTER TABLE employees AUTO_INCREMENT = 2;
-- 下一条插入的新记录的 `id` 将会是 `2`,但如果已经存在 `id` 为 `2` 的记录,会导致插入失败
2.1. InnoDB 自增列
在 InnoDB 存储引擎中,自增列的当前计数器值是存储在内存中的。这意味着:
- 在数据库运行期间,自增列的值会随着每次插入操作而递增。
- 如果数据库服务重启,自增列的计数器会重新初始化。
重启后的行为
- MySQL 5.6 及更早版本:自增列的计数器会从表中最大的现有自增列值加一开始。
- MySQL 5.7 及更高版本:自增列计数器的行为进行了优化,通常会继续从上次插入的最大值加一开始。
2.2. MyISAM 自增列
在 MyISAM 存储引擎中,自增列的当前计数器值是存储在磁盘上的。这意味着:
- 自增列的值会随着每次插入操作而递增。
- 即使数据库服务重启,自增列的计数器值也不会丢失。
重启后的行为
- MyISAM:自增列的值会继续从上一个自增值加一开始,无论数据库是否重启
3. delete 清空表之后,磁盘空间未发生变化
3.1. 原理
MySQL 中的delete数据删除操作有点像我们平日里做业务开发时用的逻辑删除,当你想要删除掉一行数据的时候,这行数据其实并没有被真正的删除掉,只是暂时给标记为删除了而已
一张表在经过 N 多次delete删除之后,就会出现大量这种情况,这种就称之为删除空洞
3.2. optimize table
optimize table table_name
该命令可以用来重新整理表空间,并优化文件碎片
optimize 操作是 online DDL 的。online DDL 意味着在执行 optimize 重整表的时候,并不会阻塞正在进行的 CURD 操作。具体流程如下:
1 . 首先建立一个临时文件,这个临时文件用来扫描表原始表主键的所有数据页。
2 . 根据第一步获取到的表记录生成一个 B+Tree,将这个生成的 B+Tree 存储到临时文件中。
3 . 由于第二步会比较耗时,在第二步执行过程中,如果有针对原始表的 CRUD 操作,则先将操作记录到一个日志文件中,等到第二步的临时文件生成后,在把日志文件应用到临时文件中,就可以获取到一个最新的数据表了。