加速MySQL的alter table操作

原文鏈接:https://blog.csdn.net/wzy0623/article/details/53908035

MySQL的alter table性能在表很大的時候會出現問題。MySQL執行大部分更改操作都是新建一個需要的結構的空表,然後把所有老的數據插入到新表,最後刪除舊錶。這會耗費很多時間,尤其是在內存緊張,而表很大並有很多索引的時候。

  不是所有的alter table操作都會導致重建表。例如,可以通過兩種方式創建或去掉列的默認值(一種快、一種慢)。下面是較慢的方式:

alter table film modify column rental_duration tinyint(3) not null default 5;
  使用show status分析該命令發現,它執行了1001次句柄讀取和1000次寫入。換句話說,即使列類型、大小和可空性沒有變化,它也把表拷貝到了新表中。

flush status;
alter table film modify column rental_duration tinyint(3) not null default 5;
show session status like 'handle%';
Variable_name    Value
Handler_commit     2
......    
Handler_read_rnd_next    1001
......    
Handler_write    1000
  理論上,MySQL能跳過構建一個新表的方式。列的默認值實際保存在表的.frm文件中,因此可以不接觸表而更改它。MySQL沒有使用這種優化,而是任何modify column都會導致表重建。但是可以使用alter column改變列的默認值:

alter table film alter column rental_duration set default 5;
  這個命令更改了.frm文件並且沒有改動表,它非常快。(alter table可以使用alter column、modify column、change column來修改列,每個命令做的事情都不一樣)。

flush status;
alter table film modify column rental_duration tinyint(3) not null default 5;
show session status like 'handle%';
Variable_name

Value

Handler_commit     2
......    
Handler_read_rnd_next    0
......    
Handler_write    0
1. 只修改.frm文件
  下面這種技巧不被MySQL支持,也沒有文檔記載,而且不保證一定能工作。使用它們需要自己承擔風險,建議在使用之前備份數據。

  不重建表可以執行下面的操作:

移除(不是添加)列的auto_increment屬性。
添加、移除或更改enum或set常量。如果移除了一個常量,查詢含有該常量的行將返回空字符串。
  基本的技巧是爲想要的表結構創建一個.frm文件來替代現有的.frm文件,步驟如下:

創建一個佈局完全一樣的空表,但是想改動的地方除外(例如添加enum的常量)。
執行flush tables with read lock。這會關閉所有正在使用的表,並且防止任何表被打開。
交換.frm文件。
執行unlock tables釋放讀鎖。
  例子:
  向film表的rating列添加一個常量,當前列定義如下:

show columns from film like 'rating';
Field    Type    Null    Key    Default
rating    enum('G','PG','PG-13','R','NC-17')    YES    
G
  現在增加一個PG-14:

create table film_new like film;
alter table film_new modify column rating enum('G','PG','PG-13','R','NC-17','PG-14') default 'G';
flush tables with read lock;
  現在從系統的命令行交換.frm文件:

mv film.frm film_tmp.frm
mv film_new.frm film.frm
mv film_tmp.frm film_new.frm
  回到MySQL命令行,現在可以給表解鎖並查看改動是否生效;

unlock tables;
show columns from film like 'rating';
Field    Type    Null    Key    Default
rating    enum('G','PG','PG-13','R','NC-17','PG-14')    YES    
G
  最後刪除用來輔助該操作的表:

drop table film_new;
  注意新值被添加到常量列表的末尾,如果放到中間,如在PG-13之後,就更改了已有數據的含義:已有R值就會變成PG-14,NC-17就會變成R,等等。

2. 快速建立MyISAM表的索引
  高效加載MyISAM表的訣竅是禁用鍵、加載數據、啓用鍵:

alter table load_data disable keys;
-- load the data
alter table load_data enable keys;
  這不會有問題,因爲它使MyISAM直到所有數據被加載後才建立鍵,在這個時候,它可以按照排序構建索引。它很快並且會得到無碎片、緊湊的索引樹(MyISAM在使用load data infile和空表的時候也會按照排序創建索引)。

  不幸的是,disable keys只適用於非唯一索引。MyISAM在內存中構建唯一索引並且在加載每一行的時候檢驗其唯一性,一旦索引的大小超過可用內存,加載就變得極爲緩慢。

  如果已經知道所有的數據都是有效的從而沒有必要進行唯一性檢查,可以採用下面的步驟加速這個過程(再次提醒這是不被MySQL支持,也沒有文檔的技巧。使用它需要承擔風險,要先備份數據):

創建一個有需要的結構的表,但是沒有任何索引。
把數據加載到表中,以構建.MYD文件。
創建另一個有需要結構的表,這次包含索引。這會創建.frm和.MYI文件。
用讀取鎖刷新該表。
重命名第2個表的.frm和.MYI文件,這樣MySQL就可以把它們用在第1個表上。
釋放讀鎖。
使用repair table創建表的索引。這會按照排序創建所有的索引,包括唯一索引。
  這個過程對很大的表也很快。
————————————————
版權聲明:本文爲CSDN博主「wzy0623」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/wzy0623/article/details/53908035

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章