最近大后台查看一些數據統計的時候,很慢,甚至會有超時情況,前端設置的超時時間是20秒。
后來通過查看日志和慢查詢,發現一條sql語句執行時間超過18秒,基本都19秒左右。
select count(*) from tb_name where create_time > xxx;
最終得知是因為這個表數據行數已經超過 一千萬了,然后create_time字段又沒有索引 。
那解決辦法肯定是加索引嘍。
但是這個表是一直在線上運行,很重要和業務部分。如果給千萬級的大表在線加索引 ,肯定會卡死。
然后就搜羅了一大筐解決方案,比如 在線無鎖加索引使用
ALTER TABLE tbl_name ADD PRIMARY KEY (column), ALGORITHM=INPLACE, LOCK=NONE;
后來才發現,這個特性是Mysql 5.6以后才支持,然而我們的mysql用的是5.5版本
最后在 《高性能Mysql》一書中看到,可在通過 “影子拷貝”來解決,
就是 先創建一張和源表無關的新表,然后通過重命名和刪表操作交換兩張表;
#操作步驟: #1、創建一張和原表結構一樣的空表,只是表名不一樣 create table tb_name_tmp like tb_name; #2、把新建的空表非主鍵索引都刪掉,因為這樣在往新表導數據的時候效率會很快(因為除了必要的主鍵以外,不用再去建立其它索引數據了) alter tb_name_tmp drop index index_name; #3、從舊表往主表里導數據,如果數據太大,建議分批導入,只需確保無重復數據就行,因為導入數據太大,會很占用資源(內存,磁盤io, cpu等),可能會影響舊表在線上的業務。我是每批次100萬條數據導入,基本上每次都是在 20s左右 insert into tb_name_tmp select * from tb_name where id between start_id and end_id; #4、數據導完后,再對新表進行添加索引 create index index_name on tb_name_tmp(column_name); #5、當大部分數據導入后,索引也建立好了,但是舊表數據量還是會因業務的增長而增長,這時候為了確保新舊表的數據一至性和平滑切換,建議寫一個腳本,判斷當舊表的數據行數與新表一致時,就切換。我是以 max(id)來判斷的。 rename table tb_name to tb_name_tmp1; rename table tb_name_tmp to tb_name;
當給新表加完索引后,最上面那條查詢直接就是0.0002s
