5 분 소요

열 번째 포스팅

안녕하세요! 열 번째 포스팅으로 찾아뵙게 되어 반갑습니다!♥

벌써 7월 30일이네요. 이제 방학이 한 달 밖에 남지 않았어요 :(
이번 포스팅이 7월의 마지막 포스팅이 될 것 같네요❗️ 한 달 동안 부랴부랴 포스팅을 해보았는데 재밌기도 하고 복습하기에도 좋고 … 더 보기 ㅋ

오늘의 포스팅 내용은 SQL에 관한 이야기입니다.
자세한 내용을 알아보러 갑시다❗️

[Boongranii] Here We Go 🔥

Udemy의 NodeJS-The Complete Guide (incl MVC, REST APIs, GraphQL, Deno) 강의를 바탕으로 작성된 글입니다.

1️⃣ SQL vs. NoSQL

지금까지 우리는 데이터를 데이터베이스에서 끌어오지 않고 변수에 저장할 때는 메모리를 사용하였습니다. 따라서, 요청 간에는 저장된 데이터만 공유가 됐죠. 또한 파일에 저장하기도 했는데 더 많은 데이터를 저장할수록 파일 접근이 특히 더 느려지기 때문에 실제 상황에서 쓸 만한 방법은 아닙니다.

그 대신 데이터 저장과 데이터 검색에 특화된 데이터베이스를 사용할 겁니다❗️

💬 차이점?

둘의 차이점을 알기 위해서는 목표를 알아야겠죠? 우리의 목표는 데이터를 저장하고 쉽게 가용 혹은 접근할 수 있게 하여 코드 측면에서뿐만 아니라 데이터 접근도 용이하게 하는 것입니다. 물론 효율적이고 빨라야 합니다.

데이터베이스를 이용하면 내부 데이터가 커짐에 따라 파일에 접근할 때보다 더 빠릅니다. 또한 정보를 읽기 위해 여러 파일을 읽을 필요가 없는 도움을 받을 수 있습니다.

데이터베이스에는 SQL 데이터베이스 기반(ex.MySQL)이 있고 NoSQL 데이터베이스 기반(ex.MongoDB)가 존재합니다.

⚡️ SQL이란?

테이블이라는 요소를 통해 소통합니다.
예를 들어 Users 테이블에는 id, email, name과 같은 엔티티가 존재합니다. Products 테이블에는 id, title, price, description 등이 존재하죠. 우린 이 엔티티 안에 데이터를 채워 넣어야 합니다.
또한, SQL 데이터베이스에서는 다른 테이블끼리 연결이 가능하게 합니다.
예를 들면 Orders 테이블에 Users에 속했던 id와 Products에 속했던 id가 들어가는 거죠. 서로의 속성을 묶어 다른 테이블에 연결이 가능합니다.

가장 핵심적인 요소를 지니고 있습니다.
그것은 바로 데이터 스키마입니다. 이를 지녀 각 테이블마다 내부 데이터의 형태, 보유한 영역과 각각에 저장되는 데이터의 종류를 명확하게 정의해야 합니다. 테이블의 데이터는 해당 테이블에 대한 스키마와 일치해야 한다는 것입니다.
데이터의 형태에 대한 정의가 SQL에 핵심 사항이라고 볼 수 있습니다.

또한 데이터와의 상관관계입니다.

  • 일대일 관계
  • 일대다 관계
  • 다대다 관계

이러한 상관관계로 다양한 테이블의 관계를 결정할 수 있습니다.

SQL은 Structured Query Language 구조화된 쿼리 언어를 뜻합니다.
쿼리란 우리가 데이터베이스와 상호작용 하기 위해 사용되는 명령어를 말합니다.

SELECT * FROM USERS WHERE AGE < 19

위와 같이 밑줄 친 부분을 쿼리라고 합니다. 이 외에도 다른 명령어가 존재합니다.
나머지는 매개변수 또는 데이터를 삽입할 수 있습니다.


이것이 SQL의 작동방식입니다.

⚡️NoSQL이란?

이름에서 No가 붙은 것처럼 SQL의 방식을 따르지 않는다는 뜻입니다. 이것도 다양한 쿼리 언어를 사용하지만 스키마와 상관관계 대신 NoSQL은 다른 신경 쓰는 부분이나 다른 장점들이 존재하겠죠?

NoSQL에도 SQL과 마찬가지로 데이터베이스가 있고 이름도 지정할 수 있습니다.
NoSQL에서 테이블은 Collections라고 합니다. 여기서는 SQL에서처럼 테이블에 있는 튜플은 존재하지는 않지만 다른 것이 존재합니다.
예를 들어, { name: ‘Boongranii’, age: 24 }, { name: ‘Chan’ } 처럼요. JS 객체와 유사하게 생겼죠? 이를 Documents라고 부릅니다. 위 예시에서 보듯 스키마가 엄격하지 않습니다. 첫 번째 Document에서는 두 가지의 속성이 있지만 두 번째 Document에서는 한 가지의 속성만 존재합니다.

같은 집단에 각각 다른 구조를 지닌 다수의 문서들을 저장할 수 있습니다. 또 SQL과 다른 점은 상관관계가 존재하지 않는다는 것입니다. 대신 데이터를 복제할 수 있습니다. 즉, 명령 Collection에 필요한 데이터를 복제하는 것입니다.

컬렉션에서 전부 업데이트나 데이터 변경을 요구해도 큰 문제가 없습니다. 왜냐하면 데이터를 받았을 때 다수의 테이블을 하나로 합칠 필요가 없다는 큰 이점을 제공하기 때문입니다❗️

원하는 데이터를 복제만 해서 쓰면 되기 때문에 매우 빠른 속도로 진행할 수 있고 이것이 NoSQL의 장점 중 하나입니다.

  • 강한 데이터 스키마가 존재하지 않는다. (어떤 구조도 강요되지 않음)
  • 일반적인 데이터 상관관계도 없다.

💿 수평 및 수직 스케일링

사용자가 늘어나고 규모가 커지는 애플리케이션을 유지하기 위해서는 데이터베이스를 확장해야 합니다.

데이터베이스를 확장할 때 사용하는 2가지 방법이 있습니다.

  • 수평적 스케일링
  • 수직적 스케일링

수평 스케일링

수평적 스케일링에서는 서버를 더 추가합니다. 이것의 장점은 이를 무한으로 진해 가능하다는 점입니다. 클라우드 업체든 자체 데이터 서버든 언제든지 새로운 서버를 구매해서 데이터베이스에 연결하고 서버들에 데이터를 분산시키면 됩니다.
동시에 쿼리를 모든 서버에 실행하고 지능적으로 통합하는 절차도 일부 필요합니다.

수직 스케일링

존재하는 서버에 CPU나 메모리 등을 추가하여 더 강력하게 만드는 것을 의미합니다. 특히 클라우드 제공업체의 경우 이 방식이 일반적으로 용이하여 목록에서 다른 옵션을 고르고 돈을 냅니다. 하지만 이것의 단점이 있습니다. 단일 머신에 무한정 CPU 출력을 집어넣을 수는 없기 때문이죠.

SQL NoSQL
Data uses Schemas Schema-less
Relations No (or very few) Relations
Data is distributed across multiple tables Data is typically merged/nested in a few collections
수직 스케일링 수평 스케일링
Limitations for lots of (thousands) read & write queries per second Great performance for mass read & write requests

스케일링에 있어서 SQL이 작동하는 방식으로 인해 수평 스케일링이 어렵거나 불가능합니다. 서버를 추가하는 건 가능하지만 전부 하나의 공유된 데이터 클라우드, 하나의 공유된 데이터베이스에서 구동하는 것은 꽤 어렵습니다.
매초 다수 혹은 수천 건의 쿼리를 읽고 쓰면 문제 될 수 있는 부분입니다. 이 경우 SQL 데이터베이스는 특히 관련된 테이블 간 매우 복잡한 연결을 진행하는 경우 한도에 도달하거나 최선의 선택이 될 수 없습니다.

NoSQL은 존재하는 문서에 통합이나 중첩된 문서를 작업하게 되는데 일반적으로 애플리케이션의 다양한 특징들에 대응하는 몇 개의 집합들도 존재할 수 있죠.
수평적 스케일링이 더욱 쉽습니다. 일반적으로 연결의 수가 적은 작동 방식으로 인해 가능한 일입니다. 따라서 방대한 읽기 및 쓰기 요청에 대해 탁월한 성능을 얻게 되고 NoSQL은 처리량이 많은 애플리케이션에서 매우 고성능을 발휘할 수 있습니다.

자주 변경되지 않는 사용자 데이터라면 SQL이 더욱 좋을 것입니다. 장바구니처럼 애플리케이션이 자주 변경되는 부분이라면 NoSQL을 통해 저장할 수 있습니다.

2️⃣ MySQL 사용

🔲 설치

1
npm install --save mysql2

✅ 적용

util/database.js파일을 만든 후 여기에 코드를 설정해서 SQL 데이터베이스로 연결하고 쿼리를 실행하게 하는 연결 객체를 전달받을 수 있도록 하면 됩니다.

1
2
3
const mysql = require("mysql2");

const pool = mysql.createPool({});

데이터베이스

위와 같이 create에 관한 메소드가 여럿 존재합니다. 단일 연결이 아니라 커넥션 풀을 통해 실행할 쿼리가 있을 때마다 항상 활용하면 좋겠죠? 다중 연결을 관리하는 이 풀에서 새로운 연결을 받아오면 각 쿼리마다 개별적으로 연결이 필요하므로 다수의 쿼리를 동시에 실행할 수 있습니다. 쿼리가 완료된 후 연결을 다시 풀로 돌려주고 새 쿼리를 위해 사용될 수 있습니다. 그리고 풀은 애플리케이션이 종료될 때 완료됩니다.

객체 안에는 데이터베이스 엔진 및 우리가 연결하려 하는 데이터베이스 호스트의 정보 등이 포함 되어야 합니다.

1
2
3
4
5
6
7
8
const pool = mysql.createPool({
  host: "localhost",
  user: "root",
  database: "MYSQL_DB",
  password: "MYSQL_PASSWORD",
});

module.exports = pool.promise();

객체 안에는 host, user, database, password가 포함 되어야 합니다. database에는 워크벤치에서 스키마로 형성했던 이름을 적으면 되고 password는 초기에 MYSQL-PASSWORD로 설정 했던 값을 넣어 주시면 됩니다.

promise를 사용함으로써 콜백 대신 비동기적 태스크, 비동기적 데이터를 다룰 수 있습니다. promise는 코드를 좀 더 체계화된 방식으로 작성할 수 있도록 하니 다수의 중첩 콜백을 피하기 위해서 사용하면 좋습니다.

app.js

1
const db = require("./util/database");

app.js에서 위 부분이 풀 역할을 하여 내부의 연결을 사용 가능하게 합니다.

1
db.execute("SELECT * FROM products");

execute메소드를 사용하여 데이터베이스 구문을 실행시킬 수 있습니다. query메소드도 있지만 execute메소드가 더욱 안전하다고 하니 이것을 사용해줍니다.

데이터베이스2

위와 같이 products 테이블에 요소들을 만들어 줍니다.

비동기 함수는 뒤에 thencatch를 사용 가능합니다. 이 메소드들은 execute 호출 결과에 따라 연결할 수 있습니다. 돌려주는 값을 토대로 실행할 것이고 이것을 promise라고 합니다.
then은 앞 내용에 따라 실행되는 메소드이고 catch는 오류가 발생하는 경우 실행되는 함수입니다.

1
2
3
4
5
6
7
db.execute("SELECT * FROM products")
  .then((result) => {
    console.log(result);
  })
  .catch((err) => {
    console.log(err);
  });

이렇게 하면 우리가 등록한 데이터가 로깅되는 것을 확인할 수 있습니다.

데이터베이스3

위와 같이 DB를 불러와 execute 사용과 promise 사용을 통해 컨트롤러와 모델에서 사용할 수 있습니다.


이번 포스팅에서는 데이터베이스를 사용해야 하는 이유와 그 종류인 SQL과 NoSQL에 대해 알아보았고 express에 MySQL을 연결하여 적용하는 방법을 살펴봤습니다.

7월의 포스팅을 읽어주셔서 감사하고 꾸준히 노력하도록 하겠습니다👊

댓글남기기