背景:
筆者的源數據一張表大概7000多萬條,數據大小36G,索引6G,加起來表空間有40G+,類似的表有4張,總計2億多條
數據庫mysql,引擎為innodb,版本5.7,服務器內存256G,物理內存幾個T,硬件參數杠杠的,然而處理這些數據踩了不少坑,因
為之前沒做過這方面的工作,現在記錄下清洗的過程,詳細的業務清洗過程和規則均記錄在https://gitee.com/yanb618/zhirong/wikis
感受:
清洗從表名,字段名,字段類型,字段值,索引創建與刪除做起,每每看到那秒數慢慢的漲到幾千秒,心中一首涼涼唱起來
假設這個速度,一天下來甚至只能處理一張表,之前的工作經歷從來沒有做過性能調優,正好這次嘗到了苦頭,記錄之
在描述之前先插一句:一定要先做實驗,做實驗!看執行時間,這么大的一張表,處理不好執行起來得以小時記,連取消都得等好久
預備:
首先讀者要分清楚Innodb和Myisam兩種引擎的區別:Innodb有完整的事物支持,行鎖,B-Tree/Hash索引;Myisam支持表鎖,
不支持事物,有FullText索引,適用於快速讀取;
其次,臨時數據能在內存中讀寫操作的就不要往磁盤上讀寫
具體:
配置temp_table_size和max_heap_table_size,下面是官網說明
tmp_table_size Command-Line Format --tmp-table-size=# System Variable Name tmp_table_size Scope Global, Session Dynamic Yes Permitted Values Type integer Default 16777216 Minimum 1024 Maximum 18446744073709551615 The maximum size of internal in-memory temporary tables. This variable does not apply to user-created MEMORY tables. The actual limit is determined from whichever of the values of tmp_table_size and max_heap_table_size is smaller. If an in-memory temporary table exceeds the limit, MySQL automatically converts it to an on-disk MyISAM table. Increase the value of tmp_table_size (and max_heap_table_size if necessary) if you do many advanced GROUP BY queries and you have lots of memory. You can compare the number of internal on-disk temporary tables created to the total number of internal temporary tables created by comparing the values of the Created_tmp_disk_tables and Created_tmp_tables variables. See also Section 8.4.4, “Internal Temporary Table Use in MySQL”.
max_heap_table_size Command-Line Format --max-heap-table-size=# System Variable Name max_heap_table_size Scope Global, Session Dynamic Yes Permitted Values (32-bit platforms) Type integer Default 16777216 Minimum 16384 Maximum 4294967295 Permitted Values (64-bit platforms) Type integer Default 16777216 Minimum 16384 Maximum 1844674407370954752 This variable sets the maximum size to which user-created MEMORY tables are permitted to grow. The value of the variable is used to calculate MEMORY table MAX_ROWS values. Setting this variable has no effect on any existing MEMORY table, unless the table is re-created with a statement such as CREATE TABLE or altered with ALTER TABLE or TRUNCATE TABLE. A server restart also sets the maximum size of existing MEMORY tables to the global max_heap_table_size value. This variable is also used in conjunction with tmp_table_size to limit the size of internal in-memory tables. See Section 8.4.4, “Internal Temporary Table Use in MySQL”. max_heap_table_size is not replicated. See Section 17.4.1.20, “Replication and MEMORY Tables”, and Section 17.4.1.38, “Replication and Variables”, for more information.
通常在執行一個耗時很長的更新表操作時查看show processlist命令可以看到如下信息
Copying to tmp table Copying to tmp table on disk
后者表示內存臨時表空間不夠,需要往硬盤寫,這個很要命,臨時查詢數據部分在內存部分在硬盤,讀寫速度驟降
調整這兩個參數的大小為40G或者更大都行,你的服務器內存足夠大的話可以繼續往上調,筆者因為有select into 重構表的需求,
一次讀出來的數據很大,因此需要調高默認值
innodb_buffer_pool_size
innodb緩沖池,以下是他的職責場景
* 數據緩存 – 最重要的目的
* 索引緩存 – 使用的是同一個緩沖池
* 緩沖 – 更改的數據(通常稱為臟數據)在被刷新到硬盤之前先存放到緩沖
* 存儲內部結構 – 一些結構如自適應哈希索引或者行鎖也都存儲在InnoDB緩沖池
很幸運的是我們的服務器是獨立的划分給mysql了,根據坊間經驗設置為總可用內存的80%,在這里總內存256G,完成這個清洗
設置100G已經足矣,我們需要這個空間來存臨時查詢的數據,大數據量下盡量避免臨時數據在內存和磁盤間交換帶來的IO性能影響
bulk_insert_buffer_size
筆者的清洗方式其中一種是多線程讀取+插入,插入采用批量插入的方式,insert into tbl_name values(),(),(),這個參數可以設置插入
的語句的長度大小,java中String一般是沒有長度限制的(除非jvm裝不下),如果需要大批量的拼接insert語句,需要加大這個參數值
當然這個值其實是專門給Myisam存儲引擎設計的,設置這個參數后還要配合設置如下參數一起用才能飛起,否則會直接報錯
Max_allowed_packet=100M,最大值1G
其他的參數優化暫時未使用到,如果是正常的小型的項目數據量不是很大的情況下,一般建議是:使用默認值,不要更改,不要更改
道理很簡單:很多企業開發時都不會去調這些參數,這也意味着默認設置經歷過最多次的壓力測試,除非你已經到了不得不去優化的地步