1. 용어

1.1. 데이터베이스

데이터베이스란 구조적인 데이터를 저장, 조회, 삭제, 수정할 수 있는 소프트웨어다.

데이터베이스의 특징은 다음과 같다.

  • 트랜잭션을 이용한 다수의 연결 처리
  • 데이터 중복 최소화
  • 메타데이터 및 인덱스를 통한 빠른 데이터 조회 및 처리
  • 어플리케이션과 데이터를 격리

1.2. SQL(Structured Query Language)

데이터베이스를 조회하고 관리할 목적으로 설계된, 관계형 모델을 기반으로 하는 ANSI 및 ISO 표준 언어이다.

1.3. RBDMS

관계형 모델을 가지는 기반으로 데이터베이스 관리 시스템이다.

예를들어 네이버 회원은 네이버 메일을 소유할 수 있으므로 1:N의 관계를 맺을 수 있다. 주요 특징으로는 SQL을 통한 질의를 제공하고 행과 열로 구성되어 데이터를 저장할 수 있는 공간인 테이블을 갖고있다. 또한 인덱스, 트랜잭션, 보안 등 부가적인 기능을 일반적인 특징으로 가지고 있다. RDBMS는 업무에서 지속적으로 관찰하는 대상을 찾는 데이터 모델링 작업과 정규화(데이터 중복제거)를 통해 최종적으로 테이블을 설계한다. (개체(Entity) 지향 모델)

대규모 서비스에서는 RDBMS를 Key-Value로 단순하게 사용하기도 한다.

1.4. 관계형 모델

데이터를 관리하고 이용하기 위한 이론적 모델이며 집합 이론, 술어 논리를 기반으로한다. 관계형 모델이 사용된 이유는 데이터의 중복을 제거하고 무결성을 정의하기 위한 것이다.

1.4.1. 릴레이션

집합 이론에서 집합을 뜻하며 헤더와 몸체로 구성된다.

1.4.2. 집합 이론

집합이란 한정된 대상 전체의 모임인 M을 말하며, 이 대상들은 일반적인 사고나 인지를 통해 명확히 구분되는(distinct) m(M에 대한 원소)이라 한다. 원소가 명확하게 구분되지 않는다는 것을 DB에 대입해보면 멀티셋이나 저장소의 역할밖에 할 수 없는 것을 의미한다.

1.4.3. 술어 논리

술어란 가지고 있느냐 아니면 가지고 있지 않느냐를 나타내는 표현식을 뜻한다. 따라서 참과 거짓으로 표현된다. 관계형 모델에서 데이터의 누락이 있을 경우 UNKNOWN이라는 표현이 추가될 수 있다.

1.4.4. 누락된 값 처리

누락은 타당한 누락 또는 타당하지 않은 누락(실제로 데이터가 없어서) 2가지로 볼 수 있다. SQL에서는 누락된 값을 표괄적으로 표현하는 NULL이 있다. 누락된 데이터의 처리가 술어에 포함될 경우 불확실한 값(UNKNOWN, 누락된 데이터의 처리가 될 경우)으로 표현되게 된다.

1.5. 데이터베이스 스키마

데이터베이스에서 저장하는 데이터의 구조, 형식, 관계를 나타내는 구조이다. 예를들어 테이블 스키마는 테이블의 속성과 다른 테이블과의 관계를 나타내고 있다. 이때 현재 테이블의 상태를 외연 , 스키마를 내포 라고 한다.

1.6. 테이블

데이터베이스에서 같은 종류의 데이터를 저장하는 논리적인 공간이다. 예를들면 메신저 서비스에서는 사용자 데이터를 테이블에 저장할 수 있다.

1.6.1. 카디날리티와 차수

차수란 테이블을 구성하는 속성의 수를 뜻하고 카디날리티는 레코드의 수를 뜻한다.

1.7. 무결성 제약조건

무결성 제약조건이란 데이터베이스가 일관되고 중복없는 데이터를 저장하기위한 규칙을 뜻한다. 도메인 제약조건, 키 제약조건, 기본키 무결성 제약조건, 외래키 무결성 제약조건 등이 있다.

1.8. 저장 프로시저(Stored Procedure)

T-SQL 코드를 감싸는 서버측 루틴이다.

저장 프로시저의 장점은 다음과 같다.

  • 실행 계획을 재사용하므로 성능이 좋다.
  • 보안 관리가 용이하다.
  • 유지보수가 용이하다.
  • 네트워크 트래픽을 줄여준다.

단점으로는 복잡한 로직 작성하기 위한 문법이 부족하다. 따라서 App 서버에 로직을 작성하고 단순히 CRUD로 사용하기도 한다.

1.9. 데이터베이스 락, 로크 (Lock)

락이란 하나의 데이터베이스에 여러개의 트랜잭션이 발생했을때 이를 조정하는 역할을 한다. 각 데이터 항목은 하나의 락과 연관되어 있으며 트랜잭션이 수행을 시작하여 데이터 항목에 접근할 때 마다 락은 락 테이블 에 유지된다.

독점 락(Exclusive lock) 은 데이터 갱신을 목적으로 접근할때 사용하는 락이다. 이에 반해서 트랜잭션에서 읽을 목적으로 데이터 항목에 접근할 때는 공유 락(Shared lock) 을 사용한다.

현재 걸려있는 락이 독점 락 이라면 공유 락을 걸 수 없다. 공류 락이나 독점 락 이 걸려 있는 경우는 독점 락을 걸 수 없다. 오직 공유 락과 공류 락만 동시에 락을 걸 수 있다.

1.10. 트랜잭션 격리조건

기본적으로 트랜잭션안에서 쓰기 작업을 할 경우 독점 락은 커밋할때까지 유지된다.

  1. READ UNCOMMITTED
  2. READ COMMITTED
  3. REPEATABLE READ
  4. SERIALIZABLE

READ UNCOMMITTED 는 SELECT 문이 공유 락을 얻지 않도록 한다. 반드시 SELECT를 실행하는 트랜잭션에서 격리조건을 변경해야 동작한다. 즉, 한 트랜잭션에서 INSERT, UPDATE를 하고 커밋하지 않더라도 다른 트랜잭션 안에서 바뀐 데이터를 읽을 수 있다. 이는 커밋되지 않은 변경사항 읽기(dirty read)라 한다.:

-- READ UNCOMMITTED 격리 조건을 사용할 경우 SELECT는 항상 성공한다.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM LIVE_COMMENT

READ COMMITTED 는 SELECT 문이 공유 락을 얻도록 한다. 단 즉시 반환한다. 데이터가 다른 트랜잭션의 독점 락으로 잠겨있을 경우 읽지 못하며, 커밋된 이후에 읽을 수 있게된다.:

-- 다른 트랜잭션에서 INSERT, UPDATE한  커밋하지 않았을  SELECT는 대기한다.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT * FROM LIVE_COMMENT

REPEATABLE READ 는 SELECT 문의 공유 락(조회한 데이터만 행단위 락)을 커밋할때까지 소유한다. 즉, 그동안 다른 트랜잭션에서 INSERT나 UPDATE를 할 수 없다. 단 락이 걸려 있지 않은 위치에 레코드를 삽입할 수 있다. 따라서 다른행에 INSERT 된 데이터를 읽게 되는 팬텀 문제가 발생할 수 있다.:

-- SELECT가 실행된 뒤에 다른 트랜잭션에서 UPDATE은 대기한다. , 독점 락을 즉시 얻을  없다.
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRAN;
SELECT * FROM LIVE_COMMENT WHERE ID = 1; //항상 같은 결과를 조회함
SELECT * FROM LIVE_COMMENT WHERE ID = 1; //항상 같은 결과를 조회함
...
SELECT * FROM LIVE_COMMENT WHERE ID > 0;
...
SELECT * FROM LIVE_COMMENT WHERE ID > 0; //항상 같은 결과를 기대할  없음
...
SELECT * FROM LIVE_COMMENT WHERE ID > 0; //항상 같은 결과를 기대할  없음

SERIALIZABLE 은 COMMIT 할때 까지 공유 락 을 조회한 데이터 뿐만아니라 주변 데이터 까지 걸어버린다. 또한 REPEATABLE READ의 팬텀 문제를 해결한다.:

-- SELECT가 실행된 뒤에 다른 트랜잭션에서 INSERT, UPDATE은 대기한다. , 독점 락을 즉시 얻을  없다.
SET TRANSACTION ISOLATION LEVEL SERIALIZBLE;
BEGIN TRAN;
SELECT * FROM LIVE_COMMENT;

...

-- 다른 트래잭션에서 INSER, UPDATE시 독점락을 얻을  없다.
BEGIN TRAN;
INSERT INTO LIVE_COMMENT VALUES('135fd', 'Great work');
COMMIT;

1.11. 팬텀 문제

위의 REPEATABLE READ 설명에서 공유락이 걸려있지 않은 레코드는 삽입할 수 있다고 하였다. SELECT 쿼리가 하나의 트랜잭션에 2번이 실행되고 그 사이에 INSERT 쿼리가 발생할 경우 2번째 SELECT 문에서 새로운 데이터가 검색될 것이다.

팬텀 문제

    트랜잭션 1

BEGIN TRAN;
    SELECT ENAME
    FROM EMPLOYEE
    WHERE DNO > 1;

    트랜잭션 2

BEGIN TRAN;
    INSERT INTO EMPLOYEE
    VALUES(3474, '정희연', '사원', 2106, 1500000, 1);
COMMIT;

트랜잭션 1 (아직 트랜잭션 내부)

    SELECT ENAME
    FROM EMPLOYEE
    WHERE DNO = 1;

1.12. 물리적 데이터 베이스

데이터베이스의 데이터는 파일, 블록(페이지), 레코드 이라는 구조로 저장된다. 파일은 블록의 집합이며 블록은 레코드의 집합이다. 파일은 하나의 테이블을 저장할 수도 있고 여러개의 테이블을 저장할 수도 있다. 블록단위 I/O

데이터베이스 에서는 블록단위 I/O 를 수행한다. 그 이유는 Sequential Access가 I/O효율이 좋기 때문이다. 즉 블록 I/O를 하는 이유는 Random Access가 아닌 Sequential Access를 최대한 많이 하려는 노력이다.

한번의 블록 I/O로 최대한 많은 데이터를 읽어서 성능을 향상 시키는 것이다. Native Command Queue와 비순사적 명령어 처리(CPU) 와 비슷한 원리이다.

데이터 접근 성능 향상을 위해 I/O요청 큐에 있는 데이터 각각을 위해 하나의 블록을 여러번 접근하는 것이 아닌 이를 데잍러르 정렬하여 한번의 블록 I/O로 대부분의 데이터를 읽어오는 방식이다. 즉 Sequential Access를 높이기 위해 이런 방식을 고집하고 있는 것이다. 반대로 하나를 위해 하나의 블록만 접근하는 것을 Random Access라 한다.

파일의 종류에는 히프 파일(비 순차), 순차 파일 이 있다. 비 순차 파일은 삽입 시간이 짧고 순차파일은 탐색시간이 짧다고 한다.

1.13. NoSQL

참고 할만한 글

Not Only SQL이라는 뜻을 지닌 제품으로 삽입 삭제와 같은 단순한 연산을 제공하면서 분산 확장을 지원하는 데이터베이스를 뜻한다. 대규모 서비스가 등장하면서 데이터가 쌓이는 속도가 빨라지며 동시에 많은 요청을 처리해야하는 경우가 많아졌다. 기존의 RDMS는 분산을 고려하여 나온 제품이 아니기 때문에 확장성 면에서 NoSQL에 비해 부족하고 삽입/삭제와 같은 단순한 명령에서 NoSQL이 빠른 성능을 보이고 있다.

NoSQL이 RDBMS에 비해 가지는 장점은 다음과 같다.

  • 분산 저장이 더 쉽고 가용성이 높다.

RDBMS를 복제(Query off loading)를 통해 확장할 경우 Write연산에 병목이 발생한다. 이를 Master를 2개의 DB로 분산하면 충돌 (무결성 위반이나 인덱스 불일치와 같은 문제) 문제가 발생하므로 분산이 쉽지 않다. 또한 수직 샤딩을 할 경우 관계 테이블을 모아놓지 않으면 특별한 솔루션의 힘을 받지 않는한 JOIN 연산은 어렵다. 이러한 JOIN을 어플리케이션에서 구현해야한다. 반면 NoSQL은 샤딩과 복제를 기본적으로 지원하는 경우가 많다. (MongoDB Auto sharding 지원)

  • NoSQL 구문은 SQL에 비해 단순하고 트래픽을 감소시킨다.
  • RDBMS의 쿼리는 트랜잭션 보장을 위해 잠금에 대한 오버헤드가 있으며 처리량이 떨어진다.
  • 분산 RDMS는 비싸다.
  • 단순한 삽입/삭제 연산만 지원하기 때문에 빠른 읽기/쓰기 속도를 가지고 있다.
  • 고정된 스키마는 인덱스 변환시 문제를 발생시킨다.

새로운 요구사항이 발생했을때 테이블의 칼럼 추가/수정/삭제와 인덱스의 수정은 테이블에 락을 걸기 때문에 문제가 발생한다고 한다. MySQL에서는 ALTER TABLE시 테이블 WRITE 락이 발생 , MySQL에서는 CREATE INDEX를 할때 WRITE 락이 발생 해결책1 , 해결책2

ALTER TABLE 절차 (테이블 락)

  1. 임시 테이블로 데이터 복사
  2. 원래 테이블 삭제
  3. 새로운 테이블 이름을 변경
  4. 다른 세선에서 읽을 수 있으나 UPDATE, INSERT문은 새로운 테이블이 생성이 될 때까지 수행되지 않는다.

NoSQL의 단점은 다음과 같다.

  • NoSQL이 익숙하지 않은데서 오는 개발자들의 어려움이 있다.
  • 관계(Relation)이 없기 때문에 복잡한 구조를 처리하기 어렵다.
  • 데이터 중복이 많아져서 저장 효율은 떨어진다.
  • 인덱싱과 트랜잭션(ACID) 지원이 없는 솔루션이 많다.
  • Join 연산이 어렵다

NoSQL은 BASE의 특성을 따른다. Basically Available(기본적인 가용성), Soft-state(시간이 지나면 데이터가 expire될 수 있다), Eventually consistency(결과적으로 일관성을 띈다)이다.

NoSQL은 테이블 디자인이 아닌 쿼리디자인을 먼저한다. 업무에서 필요한 정보에 대한 쿼리를 만들고 쿼리를 바탕으로 저장한 데이터 테이블을 설계한다. 이때 쿼리를 위해 데이터를 중복을 허용해서 테이블을 정의해야한다. 일반적으로 RDBMS처럼 정규화를 하면 성능문제가 발생하게 된다고 한다. (쿼리 지향)

1.14. 참조

  • 집합 이론: T-SQL 프로그래밍 입문, 칸토어의 집합에 대한 정의