구조화된 데이터는 하나의 테이블로 표현할 수 있다. 사전에 정의된 테이블을 relation 이라고도 부르기 때문에, 테이블을 사용하는 데이터베이스를 관계형 데이터베이스(Relational database)라고 한다.
하나의 레코드가 다른 테이블의 레코드 한 개와 연결된 경우
하나의 레코드가 서로 다른 여러 개의 레코드와 연결된 경우
여러 개의 레코드가 다른 테이블의 여러 개의 레코드와 관계가 있는 경우
때로는 테이블 내에서도 관계가 필요하다. 예를 들어 추천인이 누구인지 파악하기 위해 사용할 수 있다.
위와 같이 유저 테이블이 있다. user_id는 기본 키(primary key), name은 사용자의 이름, 그리고 recommend_id는 추천인 아이디이다.
SQL이란 하나의 언어인 Structured Query Language의 약자로 데이터베이스용 프로그래밍 언어이고 주로 관계형 데이터베이스( ex) MySQL, Oracle, SQLite, PostgreSQL )에서 사용한다. SQL을 통해 데이터베이스에 쿼리를 보내 원하는 데이터를 가져오거나 삽입할 수 있다.
쿼리(Query)란?
쿼리(query)란 무엇일까요? 쿼리는 '질의문' 이라는 뜻을 가지고 있습니다. 예를 들면 검색을 할 때 입력하는 검색어가 일종의 쿼리입니다. 검색을 할 때, 기존에 존재하는 데이터를 검색어로 필터링합니다. 따라서, 쿼리는 저장되어 있는 데이터를 필터하기 위한 질의문으로도 볼 수 있습니다.
SQL은 (relation 이라고도 불리는) 데이터가 구조화된(structured) 테이블을 사용하는 데이터베이스에서 활용할 수 있다.
SQL을 사용할 수 있는 데이터베이스와 달리, 데이터의 구조가 고정되어 있지 않은 데이터베이스를 NoSQL이라고 한다. 관계형 데이터베이스와는 달리, 테이블을 사용하지 않고 데이터를 다른 형태로 저장한다.
SQL 기본 문법 구문으로 아래와 같은 것들이 있다.
ACID(Atomicity / Consistency / Isolation / Durability)는 데이터베이스 내에서 일어나는 하나의 트랜잭션(transaction)의 안전성을 보장하기 위해 필요한 성질이다.
트랜잭션
트랜잭션이란 여러 개의 작업을 하나로 묶은 실행 유닛이다. 각 트랜잭션은 하나의 특정 작업으로 시작을 해 묶여 있는 모든 작업들을 다 완료해야 정상적으로 종료한다. 만약 하나의 트랜잭션에 속해있는 여러 작업 중에서 단 하나의 작업이라도 실패하면, 이 트랜잭션에 속한 모든 작업을 실패한 것으로 판단한다. 다시 말해 작업이 하나라도 실패를 하게 되면 트랜잭션도 실패이고, 모든 작업이 성공적이면 트랜잭션 또한 성공이다. 성공 또는 실패 라는 두 개의 결과만 존재하는 트랜잭션은, 미완료된 작업없이 모든 작업을 성공해야 한다.
원자성은 하나의 트랜잭션에 속해있는 모든 작업이 전부 성공하거나 전부 실패해서 결과를 예측할 수 있어야 한다.
하나의 단위로 묶여있는 여러 작업이 부분적으로 실행된다면, 업데이트가 일어났지만 누가 업데이트했는지 모르거나, 업데이트 날짜가 누락되는 등 데이터가 오염될 수 있. 예를 들어 계좌이체를 할 때에는 다음과 같은 두 단계가 있다.
계좌이체를 하려는데 A 계좌에서는 출금이 이뤄지고, B 계좌에 입금되지 않았다고 가정해보자. 어디서 문제가 발생했는지 파악할 수 없다면, A 계좌에서 출금된 돈은 세상에서 사라지는 돈이된다. 만약 은행에서 이런 일이 발생한다면, 은행은 더이상 제 기능을 할 수 없을 것이다. A 계좌에서 출금하는 일에 성공했지만, B 계좌에 입금하는 작업에 실패한다면 계좌 A에서 출금하는 작업을 포함하여 모든 작업이 실패로 돌아가야 한다는 것이 Atomicity(원자성)이다.
원자성을 지켰다면 1번과 2번, 두 작업이 모두 성공적으로 완료되어야 한다. 둘 중 하나의 작업이라도 실패한다면, 하나의 단위로 묶여있는 모든 작업이 실패하게 만들어 기존 데이터를 보호한다.
SQL에서도 마찬가지다. 특정 쿼리를 실행했는데 부분적으로 실패하는 부분이 있다면, 전부 실패하도록 구현되어 있. 때때로 충돌 요인에 대해서 선택지를 제공한다.
두 번째는 데이터베이스의 상태가 일관되어야 한다는 성질이다. 하나의 트랜잭션 이전과 이후, 데이터베이스의 상태는 이전과 같이 유효해야한다. 다시 말해, 트랜잭션이 일어난 이후의 데이터베이스는 데이터베이스의 제약이나 규칙을 만족해야 한다는 뜻이다.
예를 들어 '모든 고객은 반드시 이름을 가지고 있어야 한다'는 데이터베이스의 제약이 있다고 가정해보면
다음과 같은 트랜잭션은 일관성을 위반한다.
데이터베이스의 유효한 상태는 다를수 있지만, 데이터의 상태에 대한 일관성은 변하지 않아야 한다. 이 예시는 '이름이 있어야 한다' 라는 제약을 위반한다. 따라서 예시 트랜잭션이 일어난 이후의 데이터베이스는 일관되지 않는 상태를 가지게 된다.
Isolation(격리성) 은 모든 트랜잭션은 다른 트랜잭션으로부터 독립되어야 한다는 뜻이다.
실제로 동시에 여러 개의 트랜잭션들이 수행될 때, 각 트랜젝션은 고립(격리)되어 있어 연속으로 실행된 것과 동일한 결과를 나타낸다.
예를 들어 계좌에 만 원이 있다고 가정해보면,
이 계좌로부터 계좌 B로 6천 원을, 계좌 C로 6천 원을 동시에 계좌 이체하는 경우, 계좌 B에 먼저 송금한 뒤 계좌 C에 보내는 결과와 동일해야 한다.
동시에 트랜잭션을 실행한다고 해서 계좌 B와 C에 각각 6천 원씩 송금하여 마이너스 통장이 되는 것이 아니다. 각각의 송금 작업을 연속으로 실행하는 것과 동일한 결과가 나타나야 한다. 격리성을 지키는 각 트랜젝션은 철저히 독립적이기 때문에, 다른 트랜젝션의 작업 내용을 알 수 없다. 그리고 트랜잭션이 동시에 실행될 때와 연속으로 실행될 때의 데이터베이스 상태가 동일해야 한다.
Durability(지속성)는 하나의 트랜잭션이 성공적으로 수행되었다면, 해당 트랜잭션에 대한 로그가 남아야 한다. 만약 런타임 오류나 시스템 오류가 발생하더라도, 해당 기록은 영구적이어야 한다는 뜻이다.
예를 들어 은행에서 계좌이체를 성공적으로 실행한 뒤에, 해당 은행 데이터베이스에 오류가 발생해 종료되더라도 계좌이체 내역은 기록으로 남아야 한다.
마찬가지로 계좌이체를 로그로 기록하기 전에 시스템 오류 등에 의해 종료가 된다면, 해당 이체 내역은 실패로 돌아가고 각 계좌들은 계좌이체 이전 상태들로 돌아가게 된다.
ACID는 데이터베이스에서 실행되는 하나의 트랜잭션(Transaction)에 의한 상태의 변화를 수행하는 과정에서, 안전성을 보장하기 위해 필요한 성질이다. SQL을 사용하면 데이터베이스와 상호 작용하는 방식을 정확하게 규정할 수 있기 때문에, 데이터베이스에서 데이터를 처리할 때 발생할 수 있는 예외적인 상황을 줄이고, 데이터베이스의 무결성을 보호할 수 있다.
전자 상거래를 비롯한 모든 금융 서비스를 위한 소프트웨어 개발 에서는 반드시 데이터베이스의 ACID 성질을 준수해야 한다. 그래서 이런 경우에는 일반적으로 SQL을 이용한 관계형 데이터베이스를 사용한다.
소프트웨어(프로젝트)의 규모가 많은 서버를 필요로 하지 않고 일관된 데이터를 사용하는 경우, 관계형 데이터베이스를 사용하는 경우가 많다. 다양한 데이터 유형과 높은 트래픽을 지원하도록 설계된 NoSQL 데이터베이스를 사용해야만 하는 이유가 없기 때문이다.
스키마는 데이터베이스에서 데이터가 구성되는 방식과 서로 다른 엔티티(Entity) 간의 관계에 대한 설명이다.
쉽게 말해 데이터베이스의 청사진과 같다.
엔티티는 고유한 정보의 단위이다. 위 그림에서는 Teachers, Classes, Students 이렇게 3개의 엔티티가 있다. 엔티티는 데이터베이스에서 테이블로 나타낼 수 있다.
필드는 해당 엔티티의 특성을 설명하는 것이다. 데이터베이스에서 열(Column)에 해당된다.
레코드는 엔티티에 저장된 항목이다. 데이터베이스에서 행(row)이라고 할 수 있다.