개요
-
Web Application 개발에 있어, FRONT가 중요한 역할을 하며, JSON과 같은 비정형 데이터를 저장해야 하는 요구사항이 많아지게 되었다. 이에따라, Mongo DB 와 같은 Document Store Database 가 많은 유행을 하게 되었고 지금까지 사용되어져 왔다.
-
MySQL에 Document Store기능이 내장됨으로써 더 이상 JSON type의 데이터 처리를 위해서 MongoDB와 같은 Document NoSQL Database 사용 및 운영에 대한 고민을 할 필요가 없게 되었다.
-
MySQL 은 이러한 흐름에 맞추어 Document를 저장할 수 있는 JSON Data type 을 지원 (MySQL 5.7) 하게 되었고, 이를 이용하여 MySQL 8.0에 새로 소개된 X DEV API 를 통해 MongoDB 와 같은 Document Store Database사용 및 운영에 대한 고민을 할 필요가 없어졌고, DATA 자체는
- Undo image 및 Transaction 지원으로, 백업 / 복구가 현재까지 사용되던 방식 그대로 사용될 수 있다.
- 현재 개발되어 사용되던 RDBMS 방식 그대로 사용될 수 있으며, JSON 을 저장하는 Document Store를 추가로 이용할 수 있다.
- JSON 데이터를 저장하고 있는 Document Store와 일반 InnoDB Table간의 조인을 포함하여 여러가지 연산을 실행해낼 수 있다.
-
저장된 JSON 문서에 접근하기 위한 Document-Store API방식을 X DEV API로 제공하여, SQL보다는 API방식으로 데이터를 처리하는 것을 선호하는 개발자에게 새로운 interface를 통해 개발을 용이하게 할 수 있도록 도와주었다. (개발자는 X DEV API를 통해 데이터를 관리하고, 관리자 혹은 DBA는 해당 테이블에 대해 일반적인 SQL 을 통해 관리할 수 있다. (hybrid형태))
-
X DEV API 를 이용하기 위해서는 전통적인 MySQL Client Tool 인 mysql CLI (command line interface) 를 이용하지 않고, MySQL Shell 을 이용해야 한다. 또한 MySQL 8.0 은 X DEV API를 위한 새로운 port 와 socket를 제공된다.
mysql 8.0 [localhost] {msandbox} ((none)) > select @@global.port, @@global.mysqlx_port, @@global.socket, @@global.mysqlx_socket\G *************************** 1. row *************************** @@global.port: 3306 @@global.mysqlx_port: 33060 @@global.socket: /tmp/mysql.sock @@global.mysqlx_socket: /tmp/mysqlx.sock 1 row in set (0.00 sec)
-
아래의 그림은 mysqlsh 을 통해 Javascript 모드로 접속한 화면이다. 전통적인 mysql client tool 과 비슷하지만, 가독성이 높은 Prompt가 적용이 되었다.
-
X DEV API 를 이용한 MySQL 사용은 아래와 같이 다양한 언어를 지원하며, 각각의 API를 통해 Collection 과 Document 를 저장할 수 있다. 해당 코드는 MySQL Manual 에서 발췌해왔다.
MySQL Shell JavaScript Code
// Create a new collection var myColl = db.createCollection('my_collection'); // Insert a document myColl.add( {_id: '1', name: 'Sakila', age: 15 } ).execute(); // Insert several documents at once myColl.add( [ {_id: '5', name: 'Susanne', age: 24 }, {_id: '6', name: 'User', age: 39 } ] ).execute();
MySQL Shell Python Code
# Create a new collection myColl = db.create_collection('my_collection') # Insert a document myColl.add( {'_id': '1', 'name': 'Sakila', 'age': 15 } ).execute() # Insert several documents at once myColl.add( [ {'_id': '5', 'name': 'Susanne', 'age': 24 }, {'_id': '6', 'name': 'User', 'age': 39 } ] ).execute()
Node.js JavaScript Code
// Create a new collection db.createCollection('myCollection').then(function (myColl) { return Promise.all([ // Insert a document myColl .add({ name: 'Sakila', age: 15 }) .execute(), // Insert several documents at once myColl .add([ { name: 'Susanne', age: 24 }, { name: 'User', age: 39 } ]) .execute() ]) });
C# Code
// Assumptions: test schema assigned to db, my_collection collection not exists // Create a new collection var myColl = db.CreateCollection("my_collection"); // Insert a document myColl.Add(new { name = "Sakila", age = 15 }).Execute(); // Insert several documents at once myColl.Add(new[] { new { name = "Susanne", age = 24 }, new { name = "User", age = 39 } }).Execute();
Python Code
# Create a new collection my_coll = my_schema.create_collection('my_collection') # Insert a document my_coll.add({'name': 'Sakila', 'age': 15}).execute() # Insert several documents at once my_coll.add([ {'name': 'Susanne', 'age': 24}, {'name': 'User', 'age': 39} ]).execute()
Java Code
// Create a new collection Collection coll = db.createCollection("payments"); // Insert a document coll.add("{\"name\":\"Sakila\", \"age\":15}"); // Insert several documents at once coll.add("{\"name\":\"Susanne\", \"age\":24}", "{\"name\":\"User\", \"age\":39}");
C++ Code
// Create a new collection Collection coll = db.createCollection("payments"); // Insert a document coll.add(R"({"name":"Sakila", "age":15})").execute(); // Insert several documents at once std::list<DbDoc> docs = { DbDoc(R"({"name":"Susanne", "age":24})"), DbDoc(R"({"name":"User", "age":39})") }; coll.add(docs).execute();
## 사용예제
-
Collation 생성 (With mysqlsh)
MySQL localhost:33060+ ssl test JS > var myColl = db.createCollection('min_collection');
-
테이블확인 (With mysql CLI)
mysql 8.0 [localhost] {msandbox} (test) > show create table min_collection\G *************************** 1. row *************************** Table: min_collection Create Table: CREATE TABLE `min_collection` ( `doc` json DEFAULT NULL, `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL, PRIMARY KEY (`_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.01 sec)
-
Row 추가 (With mysqlsh)
MySQL localhost:33060+ ssl test JS > myColl.add({_id: '1', name: 'min', joined_year: '2018'}).execute(); Query OK, 1 item affected (0.0603 sec) MySQL localhost:33060+ ssl test JS > db.min_collection.add([{_id: '2', name: 'chan', joined_year: '2016'},{_id: '3', name: 'tim', joined_year: '2016'}]).execute(); Query OK, 2 items affected (0.0234 sec) Records: 2 Duplicates: 0 Warnings: 0
-
검색 (With mysqlsh)
// 전체검색 MySQL localhost:33060+ ssl test JS > db.min_collection.find(); [ { "_id": "1", "name": "min", "joined_year": "2018" }, { "_id": "2", "name": "chan", "joined_year": "2016" }, { "_id": "3", "name": "tim", "joined_year": "2016" } ] 3 documents in set (0.0004 sec) // _id 값이 1 을 검색 MySQL localhost:33060+ ssl test JS > db.min_collection.find('_id="1"'); [ { "_id": "1", "name": "min", "joined_year": "2018" } ] 1 document in set (0.0005 sec) // 입사년이 2016년인 사람들의 이름을 뽑아 정렬한 후 첫번째값을 가져온다. MySQL localhost:33060+ ssl test JS > db.min_collection.find('joined_year="2016"').fields('name').sort('name').limit(1) [ { "name": "chan" } ] 1 document in set (0.0012 sec) // 전체 count를 가져온다. MySQL localhost:33060+ ssl test JS > db.min_collection.count();
-
Index 생성 (With mysqlsh)
db.min_collection.createIndex("testIndex", {fields:[{"field": "$.name", "type":"TEXT(100)", required:true}]});
-
상태확인 (With mysql CLI)
mysql 8.0 [localhost] {msandbox} (test) > show create table min_collection\G *************************** 1. row *************************** Table: min_collection Create Table: CREATE TABLE `min_collection` ( `doc` json DEFAULT NULL, `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL, `$ix_t100_r_2BAA686C5604372BA51E965E6346198F5072C3D7` text GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$.name'))) VIRTUAL NOT NULL, PRIMARY KEY (`_id`), KEY `testIndex` (`$ix_t100_r_2BAA686C5604372BA51E965E6346198F5072C3D7`(100)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) INDEX가 Virtual COLUMN을 통해 생성된다. mysql 8.0 [localhost] {msandbox} (test) > select * from min_collection; +-----------------------------------------------------+-----+-----------------------------------------------------+ | doc | _id | $ix_t100_r_2BAA686C5604372BA51E965E6346198F5072C3D7 | +-----------------------------------------------------+-----+-----------------------------------------------------+ | {"_id": "1", "name": "min", "joined_year": "2017"} | 1 | min | | {"_id": "2", "name": "chan", "joined_year": "2016"} | 2 | chan | | {"_id": "3", "name": "tim", "joined_year": "2016"} | 3 | tim | +-----------------------------------------------------+-----+-----------------------------------------------------+ 3 rows in set (0.00 sec)
-
삭제 (With mysqlsh)
MySQL localhost:33060+ ssl test JS > db.min_collection.remove('_id="1"').execute(); Query OK, 1 item affected (0.1053 sec) MySQL localhost:33060+ ssl test JS > db.min_collection.find() [ { "_id": "2", "name": "chan", "joined_year": "2016" }, { "_id": "3", "name": "tim", "joined_year": "2016" } ] 2 documents in set (0.0004 sec)
-
삭제 (With mysql CLI)
mysql 8.0 [localhost] {msandbox} (test) > delete from min_collection where doc->'$.name' = 'tim'; Query OK, 1 row affected (0.02 sec)
-
상태확인 (With mysqlsh)
MySQL localhost:33060+ ssl test JS > db.min_collection.find() [ { "_id": "2", "name": "chan", "joined_year": "2016" } ] 1 document in set (0.0004 sec)
-
Truncate (With mysql CLI)
mysql 8.0 [localhost] {msandbox} (test) > truncate table min_collection; Query OK, 0 rows affected (0.10 sec)
-
상태확인 (With mysqlsh)
MySQL localhost:33060+ ssl test JS > db.min_collection.find() Empty set (0.0087 sec)
-
Drop (With mysql CLI)
mysql 8.0 [localhost] {msandbox} (test) > drop table min_collection; Query OK, 0 rows affected (0.13 sec)
-
상태확인 (With mysqlsh)
MySQL localhost:33060+ ssl test JS > db.min_collection.find(); ERROR: 1146: Table 'test.min_collection' doesn't exist
## 적용범위
-
데이터 sharding의 목적이 아닌 Document 만을 저장 하는 목적이라면 Document Store Database (예를 들면 MongoDB , CouchDB) 를 따로 운영하지 않아도 된다는 큰 장점이 있다.
-
내부적으로 저장소는 InnoDB를 사용함으로, ACID 를 포함한 Transaction 을 모두 지원한다.
-
백업/복구의 경우 기존의 방법을 통해 진행될 수 있다.
-
DBA 에게 익숙한 전통적인 방식의 mysql client tool 혹은 JDBC 방식으로 데이터를 조회 및 조작가능하다.
-
-
SQL 보다는, 제공되는 API 호츌에 익숙하며 JSON 형태의 데이터를 잘 다루는 개발자들에게 더욱 쉬운 개발 환경을 제공해줄 수 있다.