추가로 확인된 부분이 있어서 정리해 보았다.


Federated 테이블 생성 시 마지막에 remote DB의 접속 정보를 작성하게 된다.


간단하게 앞에서 만들어 본 federated_table 에 대해서 script 를 확인해 보자

(보기 편하게 \G 를 붙여 세로로 보자)

mysql > show create table fedrated_table\G


아무리 회사 테스트DB정보이지만 모자이크...-_-



다른 부분은 전부 필요없고, 맨 하단에 이렇게 IP 정보와 포트 정보, 계정 정보 등이 모두 표기가 된다......(모자이크지만....)


그래서 분명 보안상에 문제가 될 수 있다.


그렇기에 다음과 같이 Server를 Syntax(synonym??) 으로 만들어 진행하면 보안적인 부분을 해결할 수 있다.


Syntax 만드는 구문이다.


CREATE SERVER server_name
    FOREIGN DATA WRAPPER wrapper_name
    OPTIONS (option [, option] ...)

option:
    { HOST character-literal
     | DATABASE character-literal
     | USER character-literal
     | PASSWORD character-literal
     | SOCKET character-literal
     | OWNER character-literal

     | PORT numeric-literal }

출처 : http://m.blog.naver.com/kwoncharlie/10151416351


이제 Syntax를 이용하여 만들어 보자.

CREATE SERVER tlogin

FOREIGN DATA WRAPPER mysql

OPTIONS (

USER '접속ID',

PASSWORD '비밀번호',

HOST '접속DB IP',

PORT 3306, 

#SOCKET '/usr/local/mysql3/mysql.sock',

DATABASE 'DB명');


여기서 port는 반드시 integer 로 작성


이후 Federated 테이블 생성


CREATE TABLE `federated_server` (

  `nID` int(11) NOT NULL auto_increment,

  `PlayerID` varchar(36) NOT NULL default '',

  `Password` varchar(32) NOT NULL default '',

...

) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='tlogin/Player'

;


확인해 보쟈.


mysql > show create table fedrated_server\G



위와 같이 Connection 에서 tlogin/Player 으로 확인 가능하며, 정상적으로 select 도 될 수 있는 것을 확인할 수 있다.

보안적인 측면에서 효과를 볼 수 있다.




결론


이리 저리 DB에서 다른 원격지 DB의 정보를 가져 왔어 데이터를 쉽고, 프로그램 개발이 아닌 DB에서 해결하고자 하는 목적으로 진행을 해 보았다.

하지만 이 생각은 어디까지나 나의 욕심이고(DBA로써??아님 개발을 싫어하는 나로써??) 무식하면 용감하다고...

용감도 아닌 그냥 무식하고 무지해서 진행한 것이다.


여러 전문 DBA 고수분들은 비록 이런 기능이 있으나 사용하지 말라고 권고를 한다.

밑에 내용들만 조금만 깊게 생각해 보면 좋은 것 만은 아니라는 것을 알 수 있다.


1. 네트워크 성능에 따라 쿼리의 성능이 좌지우지.

2. 원격지의 Table에 DDL 작업이 발생 시 이것을 참조하는 Federated 테이블 에 대해서 재 생성

 - 혹시라도 federated 테이블을 모르는 경우 낭패..

3. 데이터 참조 시 해당 원격 DB 테이블을 모두 가져와야 하기에 처리량 증가 및 이에 따른 비용 증가


이 부분들은 여러 블로그를 조사하던 중에 참고한 내용을 기억나는 순으로 정리한 것이다.


가급적 사용하지 말자고 하는 것에서는 전부 이유가 있으니 가급적 사용안하는 방안으로 하고, 필요시 사용은 하되 엄격한 제한을 두고 사용하도록 해야겠다.


참조 : http://gywn.net/2014/12/let-me-introduce-federatedx/


반응형

Oracle 엔지니어겸 DBA 롤을 진행하다 보니 DB Link로 인해 종종 문제가 생긴 적이 많았다.


scn 이 Max치가 되어서 장애가 생긴적, 동일 DB 내에서 DB Link를 사용해서 불필요한 컨넥션 증가 등등...

어쩔때에는 db link 갯수가 한 DB내에 80개나 되는 경우도 있어서 당황한 적도 많았다.


그래서 DB Link만 생각해도 짜증나는 경우가 더 많았다.


하지만, MySQL DBA로 업무를 진행하다 보니 오히려 여기서는 DB Link 기능 없이 

Python 으로 일일이 개발해서 진행하는 경우가 허다하게 많았다.


처음부터 Python 개발을 했었다면 모르겠지만 Python을 익히면서 DBA 업무를 하다보니 괜히 개발이 더더더 싫어졌다.

(컴퓨터과에서 공부하며 DBA 가 되고 싶었지만 개발이 싫어서 DBA가 하고 싶은 부분도 상당히 많았기에...)


어쨋든 MySQL 에서도 Federated storage engine 이라는 것이 있어서 이 기술을 사용하면 db link 역활을 할 수 있다는 것을 찾아서 

이에 대해 간략한 설명과 테스트한 부분을 소개하고자 한다.



Federated Storage Engine 이란?


FEDERATED 스토리지 엔진을 사용하면 리플리케이션이나 클러스터 기술을 이용하지 않고도 원격의 MySQL 데이터베이스에 접근할 수 있다. 서비스 운영을 위해 여러 데이터베이스를 사용하는데, 한 데이터베이스의 데이터를 다른 데이터베이스들이 참조하여 사용할 때 활용할 수 있다. Oracle의 DBLink와 유사한 기능이라고 한다.


FEDERATED 엔진은 MySQL에 기본으로 설정되어 있지 않기 때문에 이를 사용하기 위해서는 별도의 작업이 필요하다. 검색을 해보면 처음에 설치할 때 부터 –with-federated-storage-engine 옵션을 주어야 한다는 등의 이야기 등이 있지만, 실제로는 재설치를 하거나 할 필요는 없다.

참조 : http://blog.weirdx.io/post/3503


그럼 나의 테스트 환경이다.

현재 회사 테스트 DB 장비와 나의 Local DB 를 연결하였다.


회사 테스트 DB는 5.0.37 이다



나의 local DB 는 5.7.12 이다

테스트는 개발장비의 데이터를 내 pc 에서 select 하고자 한다.


1. Engine 이 설치되어 있는지 확인해 본다. (Local DB)

 - 보통은 아래와 같이 Federated engine 이 NO 라고 되어 있는 것을 확인할 수 있다.



이 부분을 YES 로 변경해 보자.


my.cnf 또는 my.ini 파일에서 아래와 같이 추가해 보자


FEDERATED    만 추가한 후 저장하자.


(내 PC는 윈도우 이기에, my.ini 파일을 수정하였다.)



이 후, 적용을 위해서 DB를 재 기동 한다.


다시 Engine을 확인해 본다.




Federated가 YES 로 되어 있는 것을 확인 할 수 있다.


2. Engine을 이용하여 테이블을 추가해 보자.

 - Federated 엔진을 이용한 테이블은 쉽게 생각해 보면 원격 테이블을 가져와서 보여주는 것을 의미하며, 

   DML 작업을 진행하게 되면 원격지의 테이블 또한 변경이 되기에 굉장히 조심하자!!


* 원격지의 Table과 동일한 형태로 만들자

* 기본적으로 원격지 DB로 접속이 되는지 확인하자.(IP / Port 허용 여부)

* Oracle DB Link와 같이 원격지로 접근할 수 있도록 ID와 패스워드를 알아야 한다.


기본 문구는 아래와 같다.


CREATE TABLE `테이블명` (

  `컬럼1` 속성, 

  `컬럼2` 속성,

  `컬럼3` 속성

) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='mysql://원격지접속ID:패스워드@원격지DB의IP:포트/DB명/테이블명'

;


ex) 

CREATE TABLE `federated_table` (
  `nID` int(11) NOT NULL auto_increment,
  `PlayerID` varchar(36) NOT NULL default '',
  `Password` varchar(32) NOT NULL default '',
  `Name` varchar(20) NOT NULL default ''
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='mysql://root:password@192.168.1.70:3306/TestDB/Player'
;


3. 이렇게 추가가 정상적으로 되면 테스트 진행해 보자.


local 에서 federated_table 를 select 해 보자.



워낙 데이터가 많아 이렇게 먼저 비교를 해 보았다.


이번에는 데이터 한건에 대해서 DML 작업을 진행해 보자.



이 한건을 이용하여 Remote에서 지워지면 local 에서는 어떻게 되는지 보자.



지워져서 검색이 안되는 것을 확인할 수 있다.


다시 Insert를 진행해 보자.


local 에서 보여 지는 것을 확인할 수 있다.


이번에는 반대로 테스트 해 보자.

Local 에서 작업을 진행하면 원격지 DB에서는 어떻게 진행되는지 Delete 작업 하나만 해 보자.



Local 에서 삭제 작업을 진행 하였더니, 원격지에서 삭제 된 것을 확인할 수 있다.


DB Link를 대신 할 수 있는 분명 좋은 기능인 것을 확인할 수 있다.


이 작업을 통해서 파이썬을 이용한 작업을 대체할 수 있지 않을까 생각해 본다.

원격지의 필요한 것에 대해서 미리 테이블을 생성한 후 프로시저 등으로 작업을 진행하고, 스케줄러를 통해 주기적으로 한다면,

crontab 에 걸어서 사용을 하고 등의 필요성이 줄어들고, 동시에 보안도 해결되지 않을까 고민해 본다.



추가로 아래 사이트를 참조해도 좋을 듯 싶다.


http://blackbull.tistory.com/31


[HELP FEDERATED ENGINE]
길다.. 생략..... -0-;;;;;;;

[FEDERATED ENGINE 설명]
Federated Engine은,
실제적으로 물리적인 저장공간을 확보하여 데이터를 복사해서 갖는 것이 아니다.
무슨 말이냐 하면... 흠...

마치 C에서의 포인터나, C++, Java에서의 참조형 처럼,
단순히 틀에 대한 정보만을 지니고, 
그것을 원거리에서 MySQL의 API를 이용하여 접근하는 방식이다.


그리하여, 물리적으로 격리되어 있는 다른 MySQL 서버의 테이블로의 접근이 
로컬 내에서 가능하게 만들어준다.
(5.0 에서는 MySQL 서버간에만 사용가능하며, 추후에 이기종 DB 와의 연계도 개발할꺼라는데...
언제나 될런지 -0-;;;)

물론, 
DBLink와 마찬가지로 물리적 거리감은 실행 속도의 하락과
DDL(Data Definition Language) 같은 쿼리는 적용 되지 않는 부효과를 발생시킨다.

그런 이유로, 
만약 로컬에서 DROP TABLE 명령어를 사용하여 테이블을 DROP 시킨다면,
로컬만 DROP되고, 원거리의 TABLE에는 영향을 미치지 않는다.



[FEDERATED ENGINE 사용방법]
먼저, 원본 테이블이 어딘가 존재해야 한다.

# 원본 테이블
USE testdb;
CREATE TABLE testtbl (
 id INT AUTO_INCREMENT PRIMARY KEY,
 col1 VARCHAR(100) DEFAULT NULL,
 col2 VARCHAR(200) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=UTF8;


그리고 난 후에야, 로컬에 동일한 구조로 테이블을 생성한다.
단, 이번에는, 
****************************************************************************************
1. ENIGINE :  ENGINE=FEDERATED
2. CONNECTION 정보 : 'mysql://아이디:패스워드@IP또는DOMAIN:PORT/DB명/TABLE명'
****************************************************************************************

# FEDERATED 된 테이블
CREATE TABLE testtbl (
 id INT AUTO_INCREMENT PRIMARY KEY,
 col1 VARCHAR(100) DEFAULT NULL,
 col2 VARCHAR(200) DEFAULT NULL
) ENGINE=FEDERATED 
  DEFAULT CHARSET=UTF8
  CONNECTION='mysql://scott:tiger@192.168.10.2:3306/testdb/testtbl;


라고 만들면,
그 때부터 INSERT, DELETE, UPDATE, SELECT 가 가능해지며, 
INDEX를 사용할 수 있게 된다.

[FEDERATED 주의할 점]
1. 반드시 #원본테이블 처럼, 대상이 되는 테이블이 먼저 존재해야 한다.
2. Transaction은 지원되지 않는다.
3. #원본테이블 데이터를 제외한 필드명/타입/구조 등의 변경 사항은 
   #FEDERATED 된 테이블 적용이 되지 않기 때문에,
   수동으로 변경해 주어야 한다.
4. Query Cache는 이용할 수 없다.
5. !!!!! 중요 !!!!! SHOW CREATE TABLE #FEDERATED된 테이블
   입력시 #원본테이블로의 접속정보가 고스란히 노출 되므로, 주의가 요구된다.


반응형

[출처] http://blackbull.tistory.com/43

쿼리를 날리다 보면, 필요에 따라 그룹별로 순위를 매겨야 할 때가 있다.

이에 대해 오라클에서는 그러한 기능을 제공하는데,

아래가 바로 그 예이다.


[Oracle] 


SELECT empno, ename, job, sal, 

            ROW_NUMBER() OVER(PARTITION BY job ORDER BY sal) AS rnum 

FROM scott.emp;

<<결과>>

     EMPNO ENAME                JOB                       SAL       RNUM

---------- -------------------- ------------------ ---------- ----------

      7902 FORD                  ANALYST                    3000          1

      7788 SCOTT                ANALYST                   3000          2

      7369 SMITH                 CLERK                         800          1

      7900 JAMES                CLERK                         950          2

      7876 ADAMS                CLERK                       1100          3

      7934 MILLER                CLERK                       1300          4

      7782 CLARK                 MANAGER                  2450          1

      7698 BLAKE                 MANAGER                  2850          2

      7566 JONES                 MANAGER                  2975          3

      7839 KING                    PRESIDENT                5000          1

      7654 MARTIN               SALESMAN                 1250          1

      7521 WARD                  SALESMAN                 1250          2

      7844 TURNER               SALESMAN                 1500          3

      7499 ALLEN                 SALESMAN                 1600          4


14 개의 행이 선택되었습니다.




상기 쿼리는,

emp 테이블의 JOB을 기준으로 하여 그룹을 정하고 (PARTITION BY job),  -- 1

sal을 기준으로 하여 순위를 매겨(ORDER BY sal),

각각의 행에 ROW_NUMBER를 부여하겠다는 의미이다.                         -- 2


여기서 'PARTITION BY job'은 job별 정렬을 발생시킨다.

즉, 최종 결과물의 넘버링은 ORDER BY job, sal의 순으로 결과가 나오는 것이다.



[MySQL]

그런데, 불행하게도..... MySQL에는 저 기능이 없다.

그렇기 때문에 우리의 친구 꼼수(?)를 이용하여 저것을 구현해 내야 하는데.....


SELECT empno, ename, job, sal, rnum

FROM (

   SELECT a.*, 

           (CASE @vjob WHEN a.job THEN @rownum:=@rownum+1 ELSE @rownum:=1 END) rnum,

           (@vjob:=a.job) vjob

   FROM emp a, (SELECT @vjob:='', @rownum:=0 FROM DUAL) b

   ORDER BY a.job, a.sal                  

) c;

<<결과>>

+-------+--------+-----------+------+------+

| empno | ename  | job       | sal  | rnum |

+-------+--------+-----------+------+------+

|  7902 | FORD   | ANALYST   | 3000 |    1 |

|  7788 | SCOTT  | ANALYST   | 3000 |    2 |

|  7369 | SMITH  | CLERK     |  800 |    1 |

|  7900 | JAMES  | CLERK     |  950 |    2 |

|  7876 | ADAMS  | CLERK     | 1100 |    3 |

|  7934 | MILLER | CLERK     | 1300 |    4 |

|  7782 | CLARK  | MANAGER   | 2450 |    1 |

|  7698 | BLAKE  | MANAGER   | 2850 |    2 |

|  7566 | JONES  | MANAGER   | 2975 |    3 |

|  7839 | KING   | PRESIDENT | 5000 |    1 |

|  7654 | MARTIN | SALESMAN  | 1250 |    1 |

|  7521 | WARD   | SALESMAN  | 1250 |    2 |

|  7844 | TURNER | SALESMAN  | 1500 |    3 |

|  7499 | ALLEN  | SALESMAN  | 1600 |    4 |

+-------+--------+-----------+------+------+

14 rows in set (0.00 sec)


어때... 결과가 같아 보이는가? 


자, 그럼 쿼리를 뜯어보자.

여기서 궁금하게 생각되는 부분은 아래 3개의 쿼리라고 예상 된다.


1. (CASE @vjob WHEN a.job THEN @rownum:=@rownum+1 ELSE @rownum:=1 END) rnum,

--> 이전 job 필드와 동일한 그룹인가를 판별하고, 그룹에 따라 순번을 부여하기 위함이며,

      테이블에서 각각의 행을 읽을 때마다,

      변수 @vjob 값이 지금 새로 읽은 job 과 같다면 변수 @rownum을 1증가 시키고, 

      그렇지 않은 경우(@vjob이 현재 읽은 job값과 같지 않다면) @rownum을 1로 초기화 시킨다.


2. (@vjob:=a.job) as vjob

--> 테이블에서 각각의 행을 읽을 때마다,

      그룹 판별을 위해 현재 읽고 있는 행의 job값을 변수 @vjob에 입력


3. (SELECT @vjob:='', @rownum:=0 FROM DUAL) b

--> 원래는 쿼리를 수행하기 이전에, 

      SET @vjob:=0, @rownum:=0;  을 수행하여 변수를 초기화 해야 한다. 

      만약 해주지 않으면, NULL 값이 들어가게 된다.


      하지만 그럴 경우 쿼리가 2번 수행되어야 하기 때문에,

      하나의 쿼리로 만들기 위해서 이런 식의 서브 쿼리를 이용한 것이다.

      이 서브쿼리는 초기 테이블 확인시 1회만 수행되고,

      이후부터는 열람되지 않는다.

    

      !! 주의 !! 

      서브쿼리 안에서의 결과값만 가지고 현재의 결과값을 얻고자 할 때,

      변수가 되는 항목의 값을 동일한 자료형으로 맞춰주지 않으면, 

      정상적인 결과값이 나오지 않는다.

      가령 위의 예를 이용하자면, @vjob의 초기값을 @vjob:=0 으로 수행 하고

      서브쿼리만을 수행하면 정상적인 결과값이 나오지 않게 된다. 

      한 번 해보자~

       

이 3가지를 이해한다면 아마 이해할 수 있을 것이라 생각되지만,

한 가지 짚고 넘어가야 할 것이 있다. 


Q. 우리가 흔히 쓰는 SELECT 문장의 수행순서는 어떻게 될까?

무슨의미냐 하면..

위에서 사용한 것처럼 변수를 이용한 SELECT 내 연속적인 값의 할당은, 

수행결과에 영향을 미치게 되지 않을까? 

라는 질문이다.


흠.. 내가 말을 써놓고 난해하군..

예제를 보도록 하자.


<<예제>>

SET @val1=0, @val2=0;    #아까도 말했듯이 변수 초기화는 먼저 선행되어야 한다.

SELECT @val1:=@val1+1, @val2:=@val1+1, @val2:=0, @val1=@val2+1 

FROM DUAL;


자.... 당신이 예상하는 결과는?.....




<<쿼리 수행 결과>>

 +----------------+----------------+----------+---------------+

| @val1:=@val1+1 | @val2:=@val1+1 | @val2:=0 | @val1=@val2+1 |

+----------------+----------------+----------+---------------+

|                      1 |                     2 |             0 |                    1 |

+----------------+----------------+----------+---------------+

1 row in set (0.00 sec)


상기와 같이 SELECT 내 수행 결과는,

왼쪽에서 오른쪽으로 순차적인 수행이 이루어짐을 알 수 있다.


즉, @val1:=@val1+1 → @val2:=@val1+1 → @val2:=0  →  @val1=@val2+1 

로 수행 순서가 정해진다는 의미.


그러므로, 

변수를 이용한 SELECT를 이용할 때는 반드시 수행순서를 염두해 두고 쿼리를 작성하도록 하자.




PS : 오라클에는 예제 테이블이 있지만 MySQL 에는 없으니

       혹시 테스트 해보고 싶은 사람은 아래 쿼리를 수행해서 테스트 해보도록...


CREATE TABLE emp (

   empno INT,

   ename VARCHAR(30),

   job VARCHAR(30),

   sal INT

)ENGINE=INNODB DEFAULT CHAR SET=UTF8;


INSERT INTO emp

VALUES

(7902,'FORD','ANALYST',3000),

(7788,'SCOTT','ANALYST',3000),

(7369,'SMITH','CLERK',800),

(7900,'JAMES','CLERK',950),

(7876,'ADAMS','CLERK',1100),

(7934,'MILLER','CLERK',1300),

(7782,'CLARK','MANAGER',2450),

(7698,'BLAKE','MANAGER',2850),

(7566,'JONES','MANAGER',2975),

(7839,'KING','PRESIDENT',5000),

(7654,'MARTIN','SALESMAN',1250),

(7521,'WARD','SALESMAN',1250),

(7844,'TURNER','SALESMAN',1500),

(7499,'ALLEN','SALESMAN',1600);


반응형

+ Recent posts