1. 程式人生 > >MySQL大資料表水平分割槽優化的詳細步驟

MySQL大資料表水平分割槽優化的詳細步驟

將執行中的大表修改為分割槽表

本文章程式碼僅限於以資料時間按月水平分割槽,其他需求可自行修改程式碼實現

1. 建立一張分割槽表

這張表的表字段和原表的欄位一摸一樣,附帶分割槽

1

2

3

4

5

6

7

8

9

10

11

12

CREATE TABLE `metric_data_tmp`  (

    id bigint primary key auto_increment,

    metric varchar(128),

    datadt datetime not null unqine,

    value decimal(30, 6)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8

partition by range (to_days(DATADT)) (

    PARTITION p201811 VALUES LESS THAN (to_days("2018-12-01"

)),

    PARTITION p201812 VALUES LESS THAN (to_days("2019-01-01")),

    PARTITION p201901 VALUES LESS THAN (to_days("2019-02-01")),

    PARTITION p201902 VALUES LESS THAN (to_days("2019-03-01")),

);

2. 將原表資料複製到臨時表

  • 直接通過insert語句

1

insert into metric_data_tmp select * from metric_data;

  • 資料量非常大,可使用select into outfile, Load data file方式匯出匯入

1

2

SELECT * INTO OUTFILE 'data.txt' FIELDS TERMINATED BY ',' FROM metric_data;

LOAD DATA INFILE 'data.txt' INTO TABLE metric_data_tmp FIELDS TERMINATED BY ',';

3. 重新命名分割槽表和歷史表:

1

2

rename table metric_data to metric_data_bak;

rename table metric_data_tmp to metric_data;

4. 通過資料庫的定時任務定時自動建立下月的分割槽

  • 儲存過程

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

delimiter $$

use `db_orbit`$$

drop procedure if exists `create_partition_by_month`$$

create procedure `create_partition_by_month`(in_schemaname varchar(64), in_tablename varchar(64))

begin

    # 用於判斷需要建立的表分割槽是否已經存在

    declare rows_cnt int unsigned;

    # 要建立表分割槽的時間

    declare target_date timestamp;

    #分割槽的名稱,格式為p201811

    declare partition_name varchar(8);

         

    #要建立的分割槽時間為下個月

    set target_date = date_add(now(), interval 1 month);

    set partition_name = date_format( target_date, 'p%Y%m' );

         

    # 判斷要建立的分割槽是否存在

    select count(1) into rows_cnt from information_schema.partitions t where table_schema = in_schemaname and table_name = in_tablename and ifnull(t.partition_name, '') = partition_name;

    if rows_cnt = 0 then

        set @sql = concat(

            'alter table `',

            in_schemaname,

            '`.`',

            in_tablename,

            '`',

            ' add partition (partition ',

            partition_name,

            " values less than (to_days('",

            date_format(DATE_ADD(target_date, INTERVAL 1 month), '%Y-%m-01'),

            "')) engine = innodb);"

        );

        prepare stmt from @sql;

        execute stmt;

        deallocate prepare stmt;

     else

       select concat("partition `", partition_name, "` for table `",in_schemaname, ".", in_tablename, "` already exists") as result;

     end if;

end$$

delimiter ;

  • 建立定時任務,定時執行儲存過程建立分割槽

1

2

3

4

5

6

7

8

9

10

11

12

13

14

DELIMITER $$

#該表所在的資料庫名稱

USE `db_orbit`$$

CREATE EVENT IF NOT EXISTS `generate_partition_for_metric_data`

ON SCHEDULE EVERY 1 MONTH   #執行週期,還有天、月等等

STARTS '2019-03-15 00:00:00'

ON COMPLETION PRESERVE

ENABLE

COMMENT 'Creating partitions'

DO BEGIN

    #呼叫剛才建立的儲存過程,第一個引數是資料庫名稱,第二個引數是表名稱

    CALL db_orbit.create_partition_by_month('db_orbit', 'metric_data');

END$$

DELIMITER ;

5.其他

  • 查看錶分割槽情況的SQL

1

2

3

4

5

6

select

    partition_name part, 

    partition_expression expr,

    partition_description descr,

    table_rows 

from information_schema.partitions where table_name='metric_data';