背景
生產環境中,某個分割槽表兩三年了,佔用磁碟1T多,需要對前幾年的資料做歸檔
點選檢視程式碼
SELECT
table_schema as '資料庫',
table_name as '表名',
table_rows as '記錄數',
truncate(data_length/1024/1024, 2) as '資料容量(MB)',
truncate(index_length/1024/1024, 2) as '索引容量(MB)',
truncate(DATA_FREE/1024/1024, 2) as '碎片佔用(MB)'
from
information_schema.tables
where
table_schema='庫名'and table_name='表名'
order by
data_length desc, index_length desc;
分析
碎片佔用大量的容量,很多分割槽表都沒資料
一種可能是統計資訊沒更新。
TABLE_ROWS 列顯示的是表或分割槽的行數估計值,而不是實際行數。這個估計值可能不準確,尤其是在表資料頻繁變化的情況下。該表從生產上線之後就沒有最佳化。可能就存在該問題。
一種可能是資料頁未釋放。
即使分割槽中的資料已經被刪除,資料頁可能還沒有被完全釋放,因此 資料容量 和 索引容量 仍然顯示佔用空間。
解決方法
透過ANALYZE TABLE xxxx,來分析和最佳化表
該命令主要用於收集表的統計資訊,這些資訊對於查詢最佳化器來說非常重要,因為最佳化器會根據這些統計資訊來選擇最合適的執行計劃。
它具體完成了以下任務:
1.更新索引統計資訊:這個命令會掃描表中的資料,並重新計算索引的分佈情況,如鍵值的分佈等。這對於最佳化查詢效能非常有幫助,因為查詢最佳化器可以根據最新的統計資訊來做出更好的決策。
2.檢查並修復某些型別的表損壞:雖然 ANALYZE TABLE 並不是一個專門用來修復損壞表的工具,但它可以在一定程度上幫助識別表中可能存在的問題。如果表確實存在一些輕微的問題,該命令可能會嘗試解決這些問題。
3.輸出表的狀態資訊:執行 ANALYZE TABLE 後,MySQL 會返回一個結果集,其中包含關於表的狀態資訊,例如是否成功進行了分析、是否有錯誤發生等。
透過OPTIMIZE TABLE xxxx,來最佳化表
用於對錶進行最佳化,主要目的是透過重組表的資料檔案和索引檔案來提高表的效能。當表經歷了大量的插入、刪除或更新操作後,資料檔案和索引檔案可能會變得碎片化,這會影響查詢效率。OPTIMIZE TABLE 命令可以幫助減少這種碎片化,回收未使用的空間,重新組織資料和索引,從而提升表的讀寫效能。
它具體完成了以下任務:
1.回收空間:當表中的行被刪除時,這些行佔用的空間並不會立即歸還給作業系統,而是被標記為可用空間供未來的插入操作使用。OPTIMIZE TABLE 可以回收這些未使用的空間,並將它們歸還給作業系統。
2.重組資料檔案:隨著表的使用,資料檔案可能會變得碎片化。OPTIMIZE TABLE 會建立一個新的資料檔案,將舊的資料檔案中的資料按順序寫入新檔案中,然後刪除舊的資料檔案。這個過程有助於減少資料檔案的碎片化,提高磁碟的讀取效率。
3.重組索引檔案:與資料檔案類似,索引檔案也可能變得碎片化。OPTIMIZE TABLE 還會對索引檔案進行重組,確保索引樹更加平衡,從而加快索引查詢的速度。
4.更新統計資訊:在某些儲存引擎中,OPTIMIZE TABLE 也會更新儲存引擎內部使用的統計資訊,這有助於查詢最佳化器更好地選擇執行計劃。
排查
mysql> SELECT COUNT(*) AS actual_rows FROM 表名 PARTITION (p_2022_11_04);
mysql> SELECT * FROM 表名 PARTITION (p_2022_11_04) LIMIT 10;
透過檢查實際行數和資料,可以看出該分割槽確實沒有資料。
注意:
ANALYZE TABLE可能會導致短暫的表鎖定,尤其是在高併發環境下。且ANALYZE TABLE和OPTIMIZE TABLE分析和最佳化大表可能消耗較多的CPU和I/O資源。
建議如下:
1.選擇低峰時段:儘量在業務低峰時段執行這些操作,以減少對生產系統的影響。
2.監控系統資源:在執行這些操作時,監控系統的CPU、記憶體和I/O使用情況,確保系統資源充足。
3.測試環境:如果可能,先在測試環境中執行這些操作,評估其影響。
4.分批次處理:對於非常大的表,可以考慮分批次進行最佳化和分析。
處理:
分割槽容量
點選檢視程式碼
SELECT
TABLE_NAME,
PARTITION_NAME,
TABLE_ROWS,
DATA_LENGTH,
INDEX_LENGTH,
(DATA_LENGTH + INDEX_LENGTH) AS TOTAL_SIZE,
DATA_LENGTH / 1073741824.0 AS DATA_SIZE_GB,
INDEX_LENGTH / 1073741824.0 AS INDEX_SIZE_GB,
(DATA_LENGTH + INDEX_LENGTH) / 1073741824.0 AS TOTAL_SIZE_GB
FROM
INFORMATION_SCHEMA.PARTITIONS
WHERE
TABLE_SCHEMA = '庫名'
AND TABLE_NAME = '表名';
低峰期最佳化
檢查最佳化後分割槽表各分割槽大小
檢查最佳化後表的總大小
刪除沒有資料的分割槽
ALTER TABLE 表名 DROP PARTITION p_2023_01_26;
自此最佳化結束,一下子釋放了快1.9個T的容量,大快人心!!!
備份思路
如果有資料需要歸檔備份,備份思路如下:
建立一個臨時表,再往裡面插入特定分割槽的資料,再透過mysqldump匯出歸檔
表結構(脫敏)
show create table abc
| abc | CREATE TABLE `abc` (
`APP_ID` varchar(32) DEFAULT NULL COMMENT 'app編號',
`ABC_CODE` varchar(512) DEFAULT NULL COMMENT '二維碼號',
`CARD_ID` varchar(64) DEFAULT NULL COMMENT '卡ID',
`CODE_TYPE` varchar(32) DEFAULT NULL COMMENT '二維碼型別',
`CRT_DATE` varchar(32) NOT NULL DEFAULT '0' COMMENT '日期',
`CRT_TIME` varchar(32) DEFAULT NULL COMMENT '時間',
.......
PRIMARY KEY (`CRT_DATE`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50500 PARTITION BY RANGE COLUMNS(CRT_DATE)
(PARTITION p_2022_11_04 VALUES LESS THAN ('20221105') ENGINE = InnoDB,
PARTITION p_2022_11_05 VALUES LESS THAN ('20221106') ENGINE = InnoDB,
PARTITION p_2022_11_06 VALUES LESS THAN ('20221107') ENGINE = InnoDB,
PARTITION p_2022_11_07 VALUES LESS THAN ('20221108') ENGINE = InnoDB,
PARTITION p_2022_11_08 VALUES LESS THAN ('20221109') ENGINE = InnoDB,
PARTITION p_2022_11_09 VALUES LESS THAN ('20221110') ENGINE = InnoDB,
.......
備份方案1:
建立臨時表
CREATE TABLE abc_2022_11_04 LIKE abc;
插入特定分割槽資料
INSERT INTO abc_2022_11_04 SELECT * FROM abc PARTITION (p_2022_11_04);
透過mysqldump匯出來
mysqldump -u your_username -p 庫名 abc_2022_11_04 > abc_p_2022_11_04.sql
刪除臨時表
DROP TABLE abc_2022_11_04
備份方案2:
mysqldump -u root -p 庫名 表名 --where="CRT_DATE < '20221105'" > abc_p_2022_11_04.sql
注意:如果表中有大量資料,建議在低峰時段進行備份,以減少對生產環境的影響。