事情是這樣的,上週大佬和我說測試服務器的磁盤滿了。他找到我叫我幫忙清理一下。發現是MySQL的data目錄太大了,因而我進入mysql,發現有好幾個百萬級別的表太大了,因而我就刪了,一頓操做猛如虎,空間佔用仍是95%。mysql
大佬:「你怎麼刪的?」
我:「我一個rm -rf / *
」
大佬:「???」
我:「不對,我是用 delete from 刪的呀 」
大佬:「你明天不用來上班了。」sql
後來爲了避免被大佬嫌棄,HaC我又補了一下知識,mysql中刪除數據原來不止delete,還有 drop 、truncate。數據庫
語法:安全
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
語法:3d
TRUNCATE TABLE t_table
1)、DDL(Data Definition Language,數據庫定義語言)操做,表和索引所佔用的空間會恢復到初始大小。
2)、不會記錄日誌,比較快。
3)、只能刪table,不能回滾。
4)、刪除表中全部記錄。重置索引位置。
語法:
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.TABLES
的 DATA_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;
哦豁,空間反而大了,這就是這個表產生了空洞。
查一下這個空洞大小:
show table status from test like 't_coke_copy2';
這個空洞居然有10m那麼大,必定是以前也delete過數據,沒來得及釋放。
執行delete語句後,並不會當即釋放空間,此時可使用 optimize table
指令,但該指令會鎖表;或者也能夠利用MySQL的自動清理,須要必定的時間。
OPTIMIZE TABLE t_coke_copy2;
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
。