delete、truncate、drop 有什麼區別,誤刪數據怎麼辦

事情是這樣的,上週大佬和我說測試服務器的磁盤滿了。他找到我叫我幫忙清理一下。

發現是MySQL的data目錄太大了,因而我進入mysql,發現有好幾個百萬級別的表太大了,因而我就刪了,一頓操做猛如虎,空間佔用仍是95%。mysql

大佬:「你怎麼刪的?」
我:「我一個 rm -rf / *
大佬:「???」
我:「不對,我是用 delete from 刪的呀 」
大佬:「你明天不用來上班了。」sql

後來爲了避免被大佬嫌棄,HaC我又補了一下知識,mysql中刪除數據原來不止delete,還有 drop 、truncate。數據庫

一、delete

語法:安全

DELETE FROM t_table;

1) 、DELETE語句是DML(Data Manipulation Language, 數據操縱語言),因此它只會刪除數據,不刪除表結構。不會減小表或索引所佔用的空間服務器

2)、執行的過程就是每次從表中刪除一行,須要記錄到日誌(binlog,若是開啓了binlog),執行比較慢,能夠加上where條件。工具

養成好習慣:delete加 limit 條件,更快。
假如加 limit 1 命中第一條就返回,不用全表掃描再返回。

3)、不會重置索引,插入索引仍是從你刪除的上一條+1 開始。測試

4)、MyISAM 會馬上釋放磁盤空間 ,而InnoDB 不會釋放磁盤空間,數據只是對你不可見。會產生空洞,標記爲可複用,下次你執行insert,會覆蓋這部分空間。spa

5)走事務,若是你沒有commit,可使用 rollback 。還會觸發觸發器。.net

二、truncate

語法:3d

TRUNCATE TABLE t_table

1)、DDL(Data Definition Language,數據庫定義語言)操做,表和索引所佔用的空間會恢復到初始大小

2)、不會記錄日誌,比較快。

3)、只能刪table,不能回滾。

4)、刪除表中全部記錄。重置索引位置。

三、drop

語法:

DROP TABLE t_table

1)、DDL(Data Definition Language,數據庫定義語言)操做。

2)、直接刪掉表有關的一切(數據/結構/約束…),並將表所佔用的空間所有釋放

3)、不能回滾,不會觸發觸發器。


四、空間釋放測試

新建一個表,插入10w條數據,

CREATE TABLE `t_coke` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '編號',
  `name` varchar(500) DEFAULT NULL COMMENT '可樂',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='可樂';

# 存儲過程,插入 10w數據
CREATE DEFINER=`root`@`localhost` PROCEDURE `coke`()
begin
  declare i int;
  set i=1;
  while(i<=100000)do
    insert into t_coke values(i, "1984的可口可樂");
    set i=i+1;
  end while;
end

複製多兩個表:

CREATE TABLE t_coke_copy1 SELECT * FROM t_coke;
CREATE TABLE t_coke_copy2 SELECT * FROM t_coke;

MySQL的 information_schema.TABLESDATA_LENGTH 記錄了表的數據大小,咱們能夠利用這個計算表的大小。

SELECT
    concat( round( sum( DATA_LENGTH / 1024 / 1024 ), 2 ), 'M' ) AS table_size 
FROM
    information_schema.TABLES 
WHERE
    table_schema = 'test'  # 數據庫名稱
    AND table_name = 't_coke_copy2'; # 表名

執行delete:

DELETE FROM t_coke_copy2;

delete後變大了

哦豁,空間反而大了,這就是這個表產生了空洞。

查一下這個空洞大小:

show table status from test like 't_coke_copy2';

 查空洞

這個空洞居然有10m那麼大,必定是以前也delete過數據,沒來得及釋放。

執行delete語句後,並不會當即釋放空間,此時可使用 optimize table 指令,但該指令會鎖表;或者也能夠利用MySQL的自動清理,須要必定的時間。

OPTIMIZE TABLE t_coke_copy2;

OPTIMIZE

OPTIMIZE以後,再查一下大小:

變成了初始化大小了。

雖然刪除了,可是你的索引仍是在原來的基礎上繼續遞增的:

truncate 一步到位,直接初始化這個表。

五、恢復

delete恢復比較容易(前提是開啓了binlog):

# binlog是否開啓
show variables like 'log_bin';
# binlog 的格式
SHOW VARIABLES LIKE 'binlog_format';

找到binlog就能夠了,參考:

https://blog.csdn.net/huangba...

還可使用 Flashback 工具進行恢復。

假如生產一不當心使用了truncate和drop,怎麼恢復數據呢?

準備跑路?

duck沒必要!若是你的MySQL有全量備份,而且實時備份binlog。

一、假如HaC我在中午12點刪除了一個表。昨晚凌晨0點備份了一個庫。
二、恢復到0點的庫,
三、拿12點到0點之間的binlog進行還原。(找到binlog的drop table、truncate table 的時間節點)
四、再執行drop table、truncate table 的時間節點 到目前時間節點 的binlog的語句,至關於跳過了這個刪除語句。

因此,備份很重要!

六、總結:

delete truncate drop
安全性
空間 MyISAM 會馬上釋放磁盤空間 ,而InnoDB 不會釋放磁盤空間 馬上釋放磁盤空間 ,無論是 Innodb和MyISAM 馬上釋放磁盤空間 ,無論是 Innodb和MyISAM
恢復 可恢復 不可恢復 不可恢復
速度
事務 走事務,觸發 trigger 不走事務,不觸發 trigger 不走事務,不觸發 trigger

簡單的說,我手裏有一瓶可樂,delete就像把可樂藏起來了,其實瓶子還在,可樂也還在;truncate就是把可樂喝完,留下了個瓶子;drop 就是把可樂喝完並且把瓶子也丟掉了。

不說了,大佬又要催我了,我這就去喝可樂,不,執行truncate

相關文章
相關標籤/搜索