-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPartition Add Purge
238 lines (205 loc) · 7.55 KB
/
Partition Add Purge
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
--
--
-- Remember to set group_concat_max_len to a high enough value.
-- I recommend setting it to at least 50000.
--
CREATE DATABASE IF NOT EXISTS tests;
use tests;
DROP TABLE IF EXISTS logs;
CREATE TABLE logs (
id INT AUTO_INCREMENT NOT NULL,
message VARCHAR(500) NOT NULL,
code TINYINT UNSIGNED NOT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id,created)
);
ALTER TABLE logs PARTITION BY RANGE COLUMNS(created) (
PARTITION p20230217 VALUES LESS THAN ('2023-02-17'),
PARTITION p20230218 VALUES LESS THAN ('2023-02-18'),
PARTITION p20230219 VALUES LESS THAN ('2023-02-19'),
PARTITION p20230220 VALUES LESS THAN ('2023-02-20'),
PARTITION p20230221 VALUES LESS THAN ('2023-02-21')
);
DROP TABLE IF EXISTS blogs;
CREATE TABLE blogs (
id INT AUTO_INCREMENT NOT NULL,
message VARCHAR(500) NOT NULL,
code TINYINT UNSIGNED NOT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id,created)
);
ALTER TABLE blogs PARTITION BY RANGE COLUMNS(created) (
PARTITION p20230217 VALUES LESS THAN ('2023-02-17'),
PARTITION p20230218 VALUES LESS THAN ('2023-02-18'),
PARTITION p20230219 VALUES LESS THAN ('2023-02-19'),
PARTITION p20230220 VALUES LESS THAN ('2023-02-20'),
PARTITION p20230221 VALUES LESS THAN ('2023-02-21')
);
-- SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='logs' AND TABLE_SCHEMA='tests'
--
-- Internal stuff to handle partitioning.
-- Table MyPartTables contains one row per table to manage.
-- Insert table name, schema name, number of future partitions to create
-- and max number of partitions to keep before starting to remove old partitions
--
-- Two events will run once per day, first event will call a SP to add new partitions,
-- the second event will call a SP to remove any old partitions. This is done for
-- all tables that are recorded on MyPartTables.
--
DROP TABLE IF EXISTS MyPartTables;
CREATE TABLE IF NOT EXISTS `MyPartTables` (
`schema_name` VARCHAR(100) NOT NULL,
`table_name` VARCHAR(100) NOT NULL,
`no_of_future_partitions` INT NOT NULL,
`max_partitions` INT NOT NULL,
PRIMARY KEY (`schema_name`,`table_name`)
);
INSERT INTO MyPartTables VALUES ('tests','logs',2,20);
-- Handle partition for table test.logs, create 2 partitions in the future and
-- keep only 20 partitions before starting to remove old partitions.
INSERT INTO MyPartTables VALUES ('tests','blogs',3,5);
-- Handle partition for table test.blogs, create 3 partitions in the future and
-- keep only 5 partitions before starting to remove old partitions.
-- Run SP AddPartition() once per day
DELIMITER $$
DROP EVENT IF EXISTS `AddPartitions`;
CREATE EVENT AddPartitions ON SCHEDULE EVERY 1 day STARTS '2023-02-16 20:00:00' ON COMPLETION
PRESERVE
DO
BEGIN
CALL AddPartitions();
END$$
DELIMITER ;
--
-- SP that creates new partitions
-- Only works for RANGE partitions using DAY resolution
--
use tests;
DELIMITER $$
DROP PROCEDURE IF EXISTS `AddPartitions` $$
CREATE PROCEDURE `AddPartitions`()
BEGIN
DECLARE done BOOL DEFAULT FALSE;
DECLARE maxp INT DEFAULT 0;
DECLARE pdate INT DEFAULT 0;
DECLARE pname VARCHAR(20);
DECLARE v_table_name VARCHAR(100);
DECLARE v_schema_name VARCHAR(100);
DECLARE v_no_future_part INT;
DECLARE list CURSOR FOR SELECT `table_name`,`schema_name`,`no_of_future_partitions` FROM MyPartTables;
DECLARE CONTINUE HANDLER FOR
SQLSTATE '02000'
SET done = TRUE;
OPEN list;
tloop: LOOP
IF done THEN
CLOSE list;
LEAVE tloop;
END IF;
FETCH list INTO v_table_name,v_schema_name,v_no_future_part;
-- DEBUG SELECT v_table_name,v_schema_name,v_no_future_part;
SET pdate=TO_DAYS(DATE(NOW() + INTERVAL (v_no_future_part) DAY));
SELECT TO_DAYS(TRIM(BOTH "'" FROM MAX(PARTITION_DESCRIPTION))) INTO maxp
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME=v_table_name
AND TABLE_SCHEMA=v_schema_name
AND PARTITION_DESCRIPTION!="MAXVALUE";
-- DEBUG' SELECT pdate, maxp;
WHILE pdate > maxp DO
SET maxp = maxp + 1;
SET pname = CONCAT('p', DATE_FORMAT(FROM_DAYS(maxp), '%Y%m%d'));
SET @qry = CONCAT('ALTER TABLE ',v_schema_name,'.',v_table_name, ' ADD PARTITION (PARTITION ',pname,' VALUES LESS THAN ("',
DATE_FORMAT(FROM_DAYS(maxp),'%Y-%m-%d'),'"))');
-- DEBUG SELECT @qry;
PREPARE stmt FROM @qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END WHILE;
END LOOP;
END $$
DELIMITER ;
use tests;
-- Run SP RemovePartition() once per day
DELIMITER $$
DROP EVENT IF EXISTS `AddPartitions`;
CREATE EVENT AddPartitions ON SCHEDULE EVERY 1 day STARTS '2023-02-16 20:00:00' ON COMPLETION
PRESERVE
DO
BEGIN
CALL RemovePartition();
END$$
DELIMITER ;
--
-- SP that removes old partitions once you have more than max_partitions
-- Only works for RANGE partitions using DAY resolution
--
use tests;
DELIMITER $$
DROP PROCEDURE IF EXISTS `AddPartitions` $$
CREATE PROCEDURE `AddPartitions`()
BEGIN
DECLARE done BOOL DEFAULT FALSE;
DECLARE v_table_name VARCHAR(100);
DECLARE v_schema_name VARCHAR(100);
DECLARE v_max_partitions INT;
DECLARE v_no_of_partitions_to_remove INT;
DECLARE cur CURSOR FOR SELECT `table_name`,`schema_name`,`max_partitions` FROM MyPartTables;
DECLARE CONTINUE HANDLER FOR
SQLSTATE '02000'
SET done = TRUE;
OPEN cur;
tloop: LOOP
FETCH cur INTO v_table_name,v_schema_name,v_max_partitions;
IF done THEN
CLOSE cur;
LEAVE tloop;
END IF;
-- DEBUG SELECT v_table_name,v_schema_name,v_max_partitions;
SET @qry = CONCAT('SELECT COUNT(DISTINCT(PARTITION_DESCRIPTION)) INTO @v_no_of_partitions ',
'FROM INFORMATION_SCHEMA.PARTITIONS ',
'WHERE TABLE_NAME="',v_table_name, '" ',
'AND TABLE_SCHEMA = "',v_schema_name, '" ');
-- DEBUG SELECT @qry;
PREPARE stmt FROM @qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- DEBUG SELECT @v_no_of_partitions, v_max_partitions;
IF @v_no_of_partitions > v_max_partitions THEN
SET v_no_of_partitions_to_remove = @v_no_of_partitions - v_max_partitions;
SET @qry = CONCAT('SELECT GROUP_CONCAT(DISTINCT(PARTITION_NAME)) INTO @v_list_of_partitions_to_remove FROM ( ',
'SELECT PARTITION_NAME ',
'FROM INFORMATION_SCHEMA.PARTITIONS ',
'WHERE TABLE_NAME = "',v_table_name, '" ',
'AND TABLE_SCHEMA = "',v_schema_name, '" ',
'AND PARTITION_DESCRIPTION!="MAXVALUE" ',
'ORDER BY PARTITION_DESCRIPTION LIMIT ',v_no_of_partitions_to_remove,
' ) as slabb');
-- DEBUG SELECT @qry;
-- DEBUG SELECT @v_partitions_to_remove;
PREPARE stmt FROM @qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @qry = CONCAT('ALTER TABLE ',v_table_name, ' DROP PARTITION ', @v_list_of_partitions_to_remove);
-- DEBUG SELECT @qry;
PREPARE stmt FROM @qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END LOOP;
END $$
DELIMITER ;
-- Run some tests:
SELECT "========== Tables before AddPartitions ==========" as "";
SHOW CREATE TABLE logs;
SHOW CREATE TABLE blogs;
CALL AddPartitions();
SELECT "========== Tables after AddPartitions ==========" as "";
SHOW CREATE TABLE logs;
SHOW CREATE TABLE blogs;
CALL RemovePartitions();
SELECT "========== Tables after RemovePartitions ===========" as "";
SHOW CREATE TABLE logs;
SHOW CREATE TABLE blogs;
SELECT "========== Contect of MyPartTables ==========" as "";
SELECT * FROM MyPartTables;
SHOW EVENTS;