기은P
시간이 멈추는 장소
기은P
  • Programming (272)
    • 개발노트 (1)
    • FrontEnd (56)
      • ES&JS 문법 (14)
      • HTML&CSS (4)
      • React 기본 (18)
      • React 심화 (12)
      • React 이슈 (2)
      • Project 연습 (1)
      • Next.js (5)
    • Backend&Devops (33)
      • AWS (2)
      • Docker (9)
      • Jenkins (6)
      • Nginx (6)
      • Node.js (1)
      • ElasticSearch (5)
      • 프레임워크&아키텍처 (2)
      • 암호화 (0)
      • 기타 (2)
    • 알고리즘 (3)
    • C# (8)
      • WPF (8)
    • Java (51)
      • 순수 Java (18)
      • RDF&Jena (12)
      • RCP&GEF (9)
      • JMX (5)
      • JMapper (3)
      • 오류해결 (4)
    • Database (21)
      • RDBMS (9)
      • NoSQL (2)
      • TSDB (1)
      • GraphQL (1)
      • Hibernate (3)
      • 데이터베이스 이론 (4)
      • Redis (1)
    • 프로토콜 (11)
      • Netty (4)
      • gRPC (5)
      • 프로토콜 개념 (2)
    • Server (4)
      • Linux (4)
    • 2020 정보처리기사 필기 (43)
      • 목차 (1)
      • 기출문제 (1)
      • 1과목 - 소프트웨어 설계 (6)
      • 2과목 - 소프트웨어 개발 (7)
      • 3과목 - 데이터베이스 구축 (8)
      • 4과목 - 프로그래밍 언어 활용 (7)
      • 5과목 - 정보시스템 구축 관리 (10)
    • 2020 정보처리기사 실기 (31)
      • 목차 (4)
      • 기출예상문제 (19)
      • 실기요약 (8)
    • 빅데이터분석기사 필기 (4)
      • 목차 (0)
      • 필기 요약 (3)
    • 전기 공학 (1)
      • CIM (1)
    • 산업자동화시스템 (3)
      • SCADA (1)
      • OPC UA (2)
    • 디자인패턴 (1)
    • 휴지통 (0)

공지사항

  • 공지사항/포스팅 예정 항목

최근 댓글

최근 글

전체 방문자
오늘
어제

티스토리

hELLO · Designed By 정상우.
기은P

시간이 멈추는 장소

[MySQL] 파티셔닝 자동화 프로시저 코드
Database/RDBMS

[MySQL] 파티셔닝 자동화 프로시저 코드

2021. 4. 28. 16:01
반응형

MySQL 데이터베이스 테이블을 파티셔닝 할 일이 생겨서 프로시저로 작성하고, 이벤트 스케쥴러를 통해 매일 매일 실행시키는 것으로 자동화를 진행해보았습니다.

 

완전한 자동화이긴한데 처음에 설정을 해주어야 하는 것이 있습니다.

 

프로시저 동작 조건

1. 파티셔닝할 테이블에서 PK를 DateTime 컬럼으로 설정해주어야 합니다.(추가적인 PK가 있어도 무관) 즉, 날짜를 기준으로 Range 파티셔닝을 진행하니 날짜 컬럼이 있어야 합니다.

 

2. 그리고 프로시저를 동작시키기 전에 pFuture라는 파티션이 있어야 합니다.

 

ALTER TABLE `His_Ai` PARTITION BY RANGE( to_days(his_time)) (
                    PARTITION pFuture VALUES LESS THAN MAXVALUE                   
);

His_Ai는 테이블 이름

his_time은 PK인 DateTime 컬럼입니다.

환경에 맞게 바꾸어주세요.

 

 

3. pFuture 파티션이 제대로 생성되었는지 확인

SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, PARTITION_ORDINAL_POSITION, TABLE_ROWS
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME =  'his_ai';

 


4. 프로시저 동작 중 디버깅을 위해 로그 테이블을 생성

CREATE TABLE mg_dc.log_table (
	num int DEFAULT NULL,
	state varchar(255) DEFAULT NULL,
	msg varchar(255) DEFAULT NULL,
	date datetime DEFAULT NULL
)    

 

 

 

 

위 설정들을 해주시고 그 다음에 프로시저를 작성하고 테스트를 해봅니다.

이 프로시저는 his_ai라는 테이블을 기준으로 파티셔닝이 이루어지고, his_time이 기준이 되는 시간 컬럼입니다.

 

  • update_his_ai_partition = 프로시저 이름입니다.
  • tb_name = 파티셔닝 할 테이블 이름입니다. 프로시저 호출 시 인자로 받습니다.
  • his_time = 시간 컬럼입니다. 환경에 맞게 이름을 변경해줍니다.
  • his_ai = 파티셔닝할 테이블 이름입니다. 환경에 맞게 이름을 변경해줍니다.

이 4개의 변수들만 잘 확인하시고 변경해주시면 됩니다.

 

CREATE DEFINER=`root`@`localhost` PROCEDURE `update_his_ai_partition`(IN tb_name VARCHAR(100))
BLOCK1: BEGIN
	DECLARE no_more_rows1 boolean DEFAULT FALSE; -- 조회할 데이터가 없는 것을 확인하는 핸들러 변수
    DECLARE b_check boolean DEFAULT FALSE; -- 같은 값이 있었는지를 체크하는 변수	
	DECLARE p_name, current_partition, current_tb_time VARCHAR(100); -- 파티션 이름, 현재 커서로 조회중인 파티션 이름, 현재 커서로 조회중인 테이블 시간 이름
            
    -- Cursor 정의(현재 파티션에 등록된 테이블과 테이블의 시간 Cursor)    
	DECLARE tb_time_list CURSOR FOR SELECT DISTINCT LEFT(his_time, 10) FROM his_ai;
	DECLARE current_partition_list CURSOR FOR SELECT PARTITION_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = tb_name;
    
	-- 더이상 조회할 데이터가 없을 때의 핸들러
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows1 := TRUE;

        
	-- 외부 블록 : 테이블의 날짜 데이터 리스트 조회
    OPEN tb_time_list;    
    LOOP1: LOOP
		-- 정보가 있다면 로드
		FETCH NEXT FROM tb_time_list INTO current_tb_time;   			
		-- 더 조회할 데이터가 없다면 루프를 빠져나옴
		IF no_more_rows1 THEN
			LEAVE LOOP1;
		END IF;
        -- 2021-04-04 -> 20210404 문자열 자르기    
		SET current_tb_time := replace(current_tb_time, '-', '');  		      
		           
			-- 내부 블록 : 현재 파티션에 등록된 파티션 리스트 조회
			BLOCK2: BEGIN 
				DECLARE no_more_rows2 boolean DEFAULT FALSE;
				DECLARE sql_error2 boolean DEFAULT FALSE;
				-- 더이상 조회할 데이터가 없을 때의 핸들러
				DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows2 := TRUE;
				-- 에러가 발생할 경우의 핸들러
				DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET sql_error2 = TRUE;
               
				OPEN current_partition_list;		
                
				LOOP2: LOOP
					FETCH NEXT FROM current_partition_list INTO current_partition;                                 
                                  
					IF no_more_rows2 = TRUE AND b_check = FALSE THEN
                    
						INSERT INTO mg_dc.LOG_TABLE VALUES(				
							(SELECT NUM FROM ( SELECT IFNULL(MAX(num),0)+1 AS NUM FROM mg_dc.LOG_TABLE) A
										  ), 'Insert', current_tb_time, NOW());
                        -- p'20210404' 파티션 이름
						SET p_name := CONCAT('p', current_tb_time);						
						SET @alter_sql := CONCAT('ALTER TABLE mg_dc.',tb_name, ' REORGANIZE PARTITION pFuture INTO (',
										  'PARTITION ', p_name, ' VALUES LESS THAN (TO_DAYS(', current_tb_time, ')),
										   PARTITION pFuture VALUES LESS THAN MAXVALUE)' );
						PREPARE alter_cmd FROM @alter_sql;
						EXECUTE alter_cmd;     
						DEALLOCATE PREPARE alter_cmd;	 
						-- 파티션을 생성했다면 내부 블록 루프 종료
                        SET b_check := FALSE;	
						LEAVE LOOP2;
					ELSEIF no_more_rows2 = TRUE AND b_check = TRUE THEN
						INSERT INTO mg_dc.LOG_TABLE VALUES(
							(SELECT NUM FROM ( SELECT IFNULL(MAX(num),0)+1 AS NUM FROM mg_dc.LOG_TABLE) A
										  ), 'Duplicate', current_tb_time, NOW());
						-- 파티션이 이미 생성되었기에 루프 종료
						SET b_check := FALSE;	
                        LEAVE LOOP2;
					END IF;
					
                    
					-- 더 조회할 데이터가 없다면 루프를 빠져나옴
					IF no_more_rows2 THEN
						 LEAVE LOOP2;
					END IF;
                    
                    -- SQL 에러가 발생할 경우 루프를 빠져나옴
                    IF sql_error2 THEN
						 LEAVE LOOP2;
					END IF;   
                    INSERT INTO mg_dc.LOG_TABLE VALUES(
						(SELECT NUM FROM ( SELECT IFNULL(MAX(num),0)+1 AS NUM FROM mg_dc.LOG_TABLE) A
									  ), 'Before Data', current_partition, NOW());
					-- p20210404 -> 20210404로 문자열 자르기
					SET current_partition := RIGHT(current_partition, 8); 	
                    
                    INSERT INTO mg_dc.LOG_TABLE VALUES(
						(SELECT NUM FROM ( SELECT IFNULL(MAX(num),0)+1 AS NUM FROM mg_dc.LOG_TABLE) A
									  ), 'After Data', current_partition, NOW());
                                                            
					-- 파티션에 해당 날짜의 파티션이 있다면 체킹
					IF current_tb_time = current_partition THEN 
						SET b_check := TRUE;        						
					END IF;          
				END LOOP LOOP2;      
			END BLOCK2;	
            
			close current_partition_list;   
		END LOOP LOOP1;   
    close tb_time_list;
END BLOCK1

코드의 로직은 이렇습니다.

파티션의 이름은 p20210404와 같이 p + 날짜로 저장됩니다.

첫째 루프에서 현재 데이터베이스에 추가된 파티션들의 목록을 가져옵니다.

둘째 루프에서 테이블에 실시간으로 저장되고 있는 날짜 데이터를 DISTINCT로 중복 제거하여 가져옵니다. 20210401, 20210402, 20210403, ..., etc 이런 식으로요.

저장된 파티션의 이름과 테이블에서 추출한 날짜 데이터와 일치하는 파티션이 있으면 b_check 변수가 True바뀌고 파티셔닝을 수행하지 않습니다.

반대로 일치하는 파티션이 없을 경우에는 b_check 변수가 False를 유지한 상태로 alter_sql 커맨드가 실행되는 원리입니다.

 

 

 

CALL update_his_di_partition('his_di');

이 코드로 프로시저를 실행하고, 결과는 3번의 파티션 리스트 조회 쿼리를 통해 확인해봅니다.

정상적으로 작동이 되었다면 이벤트 스케쥴러를 통해 원하는 시간 간격으로 프로시저 실행 주기를 작성합니다.

 

 

SET GLOBAL event_scheduler = on; -- 이벤트 스케쥴러 작동
SELECT * FROM information_schema.`EVENTS` ; -- 등록된 이벤트 스케쥴 조회
DROP EVENT IF EXISTS everyday_update_his_ao_partition; -- 이벤트 삭제

스케쥴러를 처음 실행한다면 On으로 상태를 바꿔주시고 조회나 삭제는 위의 쿼리를 참고해서 진행하면 됩니다.

 

 

CREATE EVENT everyday_update_his_ao_partition
    ON SCHEDULE 
 EVERY 5 Minute
STARTS '2021-04-28 15:25:00'
    DO CALL update_his_ao_partition('his_ao');

이벤트 스케쥴러 등록 쿼리입니다. 시간 간격은 EVERY n Hour, EVERY n Day 등도 사용할 수 있습니다.

 

 

 

반응형
저작자표시 변경금지

'Database > RDBMS' 카테고리의 다른 글

[Mysql] 위도 경도 반경 구하기  (0) 2022.07.15
Maria DB cent os home 경로에 설치하기  (0) 2021.08.09
[MySQL] 파티셔닝 개념 및 사용법  (2) 2021.04.28
[오류해결] MySQL Read Only Table  (0) 2020.08.06
[오류해결] MariaDB errno: 150 "Foreign key constraint is incorrectly formed"  (0) 2020.08.06
    'Database/RDBMS' 카테고리의 다른 글
    • [Mysql] 위도 경도 반경 구하기
    • Maria DB cent os home 경로에 설치하기
    • [MySQL] 파티셔닝 개념 및 사용법
    • [오류해결] MySQL Read Only Table
    기은P
    기은P
    기은P의 블로그 일상과 개발 관련 포스팅 #React #Typescript #Next #Nest https://github.com/kimdongjang

    티스토리툴바