iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Software Development

MYSQL-相關實務操作學習紀錄系列 第 26

Day.26 實務應用 - 實作表自動分區管理( event / procedure / partition )_1

procedure簡單來說就跟寫程式一樣,只是procedure是運用資料庫的程式語言,透過不同語言邏輯的語法來達到相同目的。
預告: 這邊實作邏輯拆分上大致上會分個3天,帶各位一步一步實作整個流程~

每個新環境的開始就是要 Hello World

ps.複製時附註內容記得要刪掉才能執行喔/images/emoticon/emoticon33.gif

Example. 新增一個簡單的procedure名為 hello_proc()

DELIMITER ||    -- 重新定義SQL結束符號(必要&自定義符號可變)
DROP PROCEDURE IF EXISTS hello_proc || --存在時先刪除(加了就不用每次修改邏輯內容都得先刪除在新增)
CREATE PROCEDURE hello_proc()  --建立procedure 

-- (BEGIN 開始/ END 結尾) 之間的部分為寫邏輯的區塊
BEGIN

--變數宣告賦值 
SET @val = 'hello world';
--輸出
SELECT @val; 

END || 

-- 恢復原本的結束符號
DELIMITER ;

Q: 有了上面的procedure如何呼叫它!?

A: 使用CALL指令執行procedure


mysql> CALL hello_proc();
+-------------+
| @val        |
+-------------+
| hello world |
+-------------+
1 row in set (0.00 sec)

如果要帶參數怎麼辦? 來看以下簡單IF-ELSE邏輯範例判斷輸入值大小。


DELIMITER || 
DROP PROCEDURE IF EXISTS t1_proc ||  
CREATE PROCEDURE t1_proc(v1 INT(10))
BEGIN
        --定義變數型態
        DECLARE val INT(10);
        --變數賦值
        SET val = v1;

        IF val < 10 THEN
			SET @CHECK = "TRUE";
        ELSE
			SET @CHECK = "FALSE";
        END IF;

		SELECT @CHECK;
END||
DELIMITER ;

mysql> call t1_proc(7);
+--------+
| @CHECK |
+--------+
| TRUE   |
+--------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

簡單的認識如何使用後,在來進入正題囉~

  • 情境模擬

有一個尚未切分區的資料表act,且本身已經有資料在內了,想用該表欄位created_at(建立時間)當做partition key切表,除了切分區還要能達到自動新增分區與刪除舊資料分區的動作,方便資料上的維護。

CREATE TABLE `act` (
  `actives_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `status` bigint(20) NOT NULL,
  `start_time` int(11) unsigned NOT NULL,
  `end_time` int(11) unsigned NOT NULL,
  `platform_id` bigint(20) DEFAULT NULL,
  `updated_at` int(11) unsigned NOT NULL,
  `created_at` int(11) unsigned NOT NULL,
  PRIMARY KEY (`actives_id`)
);

  • 需求準備

(前置)

既然要當作partition key 須先將該欄位與原PK結合成複合主鍵。(actives_id,created_at)

(需求拆分)

  1. 能判斷原資料表有無做分區,沒有的話撈資料表紀錄最舊的那筆記錄時間當作第一個分區,建立基礎分區資訊。

概念: 撈資料表最舊的那筆記錄時間當作第一個分區。

假設最舊日期為1632499200(2021-09-25 00:00:00) GMT +8 

將表中現有資料先新增以下基礎分區 (第一天的分區 & pmax)。 
ALTER TABLE `active`.`act` PARTITION BY RANGE (`created_at`) (
    PARTITION p20210924 VALUES LESS THAN (1632528000),
    PARTITION pmax VALUES LESS THAN MAXVALUE 
);

之後的日期分區新增使用pmax分區重組的方式。
  • 實作流程

貼心提醒: 一樣註解要拿掉才能跑嘿/images/emoticon/emoticon14.gif

  * 建立一個procedure檢查分區: check_part()
   
  * 可帶入參數: 1.資料庫名稱 2.資料表名稱
   
  * 流程上會針對partition key型態&表去寫,使用時要記得修改小部分內容。
     1. partition key不同型態轉換分區的邏輯
     2. 查詢直接寫死表名稱的地方
DELIMITER ||  
DROP PROCEDURE IF EXISTS check_part ||  
CREATE PROCEDURE check_part(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))
BEGIN   

DECLARE isexist_partition varchar(255) default ''; --判斷表是否存在分區
DECLARE old_date VARCHAR(255);  --資料中最早紀錄的日期
DECLARE new_p_description VARCHAR(255); --切分區用的分區描述
DECLARE new_p_name VARCHAR(255); --切分區用的分區名稱
--判斷是否存在分區
select partition_name into isexist_partition from information_schema.partitions where table_schema = IN_SCHEMANAME  and table_name = IN_TABLENAME limit 1;

--資料表沒有分區就做新增分區動作
IF isexist_partition <=> NULL THEN 
	SET @p_check = "The table has no partition。 STEP: Add table partition";
    SELECT @p_check;
    
    --撈最早的一筆日期
    select date(from_unixtime(`created_at`)) into old_date  from `act` order by `created_at` asc limit 1 ;
	SET old_date = REPLACE(old_date, '-', ''); 

	SET new_p_name = DATE_FORMAT(old_date, 'p%Y%m%d');
	SET new_p_description = unix_timestamp(old_date + INTERVAL 1 DAY);
	SET @SQL = CONCAT('ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`', ' PARTITION BY RANGE (`created_at`) (PARTITION ', new_p_name, ' VALUES LESS THAN (', new_p_description, '),PARTITION pmax VALUES LESS THAN MAXVALUE );');	
	SELECT @SQL;
    PREPARE stmt FROM @SQL;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

END IF;

SET @STEP = "STEP: check partition [ PASS ]";
SELECT @STEP; 
  
END || 
DELIMITER ;

  • 成果瀏覽

    • 假設資料表已存在分區
mysql> call check_part('active','act');
+--------------------------------+
| @STEP                          |
+--------------------------------+
| STEP: check partition [ PASS ] |
+--------------------------------+
1 row in set (0.01 sec)
  • 清除表分區定義再試一次
 ALTER TABLE act REMOVE PARTITIONING;
  • 資料表尚未存在分區的執行顯示
mysql> call check_part('active','act');
+------------------------------------------------------+
| @p_check                                             |
+------------------------------------------------------+
| The table has no partition STEP: Add table partition |
+------------------------------------------------------+
1 row in set (0.01 sec)

+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
| @SQL                                                                                                                                                        |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ALTER TABLE `active`.`act` PARTITION BY RANGE (`created_at`) (PARTITION p20210924 VALUES LESS THAN (1632528000),PARTITION pmax VALUES LESS THAN MAXVALUE ); |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

+--------------------------------+
| @STEP                          |
+--------------------------------+
| STEP: check partition [ PASS ] |
+--------------------------------+
1 row in set (0.10 sec)

Query OK, 0 rows affected (0.10 sec)

今天的內容先到這邊~明天繼續後續的流程/images/emoticon/emoticon34.gif


上一篇
Day.25 提升大數據資料管理 - 資料表分區 ( MYSQL Partition)_2
下一篇
Day.27 實務應用 - 實作表自動分區管理( event / procedure / partition )_2
系列文
MYSQL-相關實務操作學習紀錄30

尚未有邦友留言

立即登入留言