procedure簡單來說就跟寫程式一樣,只是procedure是運用資料庫的程式語言,透過不同語言邏輯的語法來達到相同目的。
預告: 這邊實作邏輯拆分上大致上會分個3天,帶各位一步一步實作整個流程~
每個新環境的開始就是要 Hello World
ps.複製時附註內容記得要刪掉才能執行喔
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
)
(需求拆分)
概念: 撈資料表最舊的那筆記錄時間當作第一個分區。
假設最舊日期為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分區重組的方式。
貼心提醒: 一樣註解要拿掉才能跑嘿
* 建立一個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)
今天的內容先到這邊~明天繼續後續的流程