Lucian Log
Blog
Computer Science
Algorithm
DB
Network
OS
General
AI
Blockchain
Concurrency
ETC
Git
Infrastructure
AWS
Docker
Java-Ecosystem
JPA
Java
Spring
JavaScript-Ecosystem
JavaScript
Next.js
React
TypeScript
Python-Ecosystem
Django
FastAPI
Python
SQLAlchemy
Software Engineering
Architecture
Culture
Test
Home
Contact
Copyright © 2024 |
Yankos
Home
>
Computer Science
> DB
Now Loading ...
DB
DB 설계 규칙 정리
DB 네이밍 규칙 테이블명, 컬럼명은 소문자로 작성하고 snake_case를 사용한다. 테이블명은 복수형을 사용하자. (선택사항) 여러 개 데이터를 가지고 있음을 표현 회사마다 규칙이 갈리므로, 복수형이든 단수형이든 일관성 있게만 사용하면 됨 축약어를 사용하지 않는다. SQL문은 예약어만 대문자로 작성하자. (SELECT, FROM, WHERE…) DB 설계 핵심 원칙 핵심 원칙: 중복 없애기 (정규화) 데이터 간 모순(이상 현상)의 근본적 원인은 데이터 중복이고, 정규화는 데이터 중복을 제거 e.g. 두 테이블에 작성자 컬럼이 있는데, 모두 수정하다가 한 데이터를 빼먹으면 갱신 이상 발생 DB 설계 과정 저장해야 하는 데이터 파악하기 대략적인 UI 디자인 기획을 보고 필요한 데이터 파악 가끔 글로만 정리된 요구사항이 있을 수 있지만, 놓치는 부분이 생길 수 있어 좋지 않은 방식 기준: 나중에 조회해서 쓸 일이 있겠다 싶은 데이터를 전부 저장 그룹핑해서 분류하기 관련 있는 것들끼리 묶어 상위 개념을 찾음 (= 엔터티 = 테이블) 따로 법칙이 있다기보다 인간이 모두 가지고 있는 보편적인 분류 능력을 따르자 e.g. 아이디, 패스워드, 이름, 이메일 → 사용자 (엔터티) 영화 이름, 영화에 출연한 배우, 영화 상영 시간 → 영화 (엔터티) 게시글 제목, 게시글 내용, 게시글 생성 시간 → 게시글 (엔터티) 6가지 규칙을 적용하며 테이블 분리해나가기 유의점 데이터 예시를 입력하며 파악하자 규칙 1 + 규칙 2의 결과는 규칙 3의 결과 동일 (무얼 선택해도 괜찮음!) 처음에 완벽한 설계가 안돼도 추후 데이터 중복을 발견해 수정 가능하니 불안해하지 말자 연관 관계 파악 관련 규칙 규칙 1: 한 칸에 한 가지 정보만 들어가야 한다 (제1정규형) 한 칸에 두 가지 정보가 있을 시, 테이블을 분리하고 FK를 적용 FK 적용이 규칙 1을 어길 경우, 반대쪽 테이블에도 FK를 적용해보자 ‘한 가지 정보’의 기준은 절대적이지 않아서, 자신의 서비스에 맞게 판단해야 함 e.g. 손/흥민 or 손흥민, 01012341234 or 010/1234/1234 규칙 2: 어떤 테이블에 FK를 넣어도 ‘규칙 1’을 못 지킬 때는 중간 테이블을 하나 더 만들자 양쪽 테이블의 FK를 중간 테이블로 옮기기 중간 테이블의 이름은 동사를활용하면 좋음 (직관성, 가독성 상승) e.g. students & courses -> course_registrations {id(PK), student_id(FK), course_id(FK)} movies & actors -> casting {id(PK), movie_id(FK), actor_id(FK)} 규칙 3: 헷갈릴 땐 연관 관계를 파악해보자 (1:1, 1:N, N:M) 판단 방법 엔터티 간에 어울리는 동사를 찾기 (A가 B를 ___.) e.g. 사용자가 이메일을 소유한다. 이메일은 사용자에 의해 소유되어진다. 적절한 단어 찾기 (하나의 or 여러개의) e.g. ‘하나의’를 고정해서 따져보기 하나의 사용자는 ___ 이메일을 소유한다. 하나의 이메일은 ___ 사용자에 의해 소유되어진다. 관계 파악하기 (1:1, 1:N, N:M) e.g. 사용자와 이메일은 1: N 관계 1:N 관계 N 쪽 테이블에 FK 들어가야 함 N:M 관계 중간 테이블이 있어야 하고, 중간 테이블에 두 테이블의 FK가 들어가야 함 (1:N으로 해소) 1:1 관계 아무 테이블에 FK를 넣어도 됨 합쳐도 되는지 고려해보자 (왠만하면 1:1 관계로 분리하지 않는 걸 추천) 통쨰로 조회하는 일이 많다면 합치는게 좋음 만약 각각 따로 조회할 일이 많다면 분리하는게 좋음 중복 없애기 관련 규칙 규칙 4: 데이터 중복이 발생하는 컬럼이 있는지 확인하자 임의의 데이터를 넣고 시뮬레이션해서 데이터 중복 발생 여부 파악 e.g. 게시물 테이블의 작성자 데이터가 중복됨 중복이 있다면 테이블 분리하고 FK 적용 수정 포인트가 하나가 되므로, 갱신 이상 여지가 사라짐 규칙 5: 가짜 중복과 진짜 중복 구별하기 실제 서비스에서 A 데이터 값을 수정하면, B 데이터 값도 같이 수정되어야 하는가? e.g. id 1 게시물의 작성자를 수정하면, id 2 게시물의 작성자도 수정해야 하나? 같이 수정되어야 하면 진짜 중복, 아니라면 가짜 중복 진짜 중복인 경우 테이블 분리해야 함 규칙 6: 숨어있는 중복을 찾아라 숨어 있는 중복 겉으로는 중복이 아닌 것 같지만, 무언가 수정해야할 때 같이 수정해야 하는 경우 e.g. users & posts -> likes (중간 테이블) 좋아요를 제거할 때, 게시글의 좋아요 수도 같이 수정해야 함 주로 통계치(합계, 평균, 최대값 등)를 낼 때 발생 해결 방법: 테이블에서 통계치 칼럼을 없애야 함 e.g. 좋아요 수 없애기 좋아요 수를 알고 싶다면, 좋아요 테이블에서 필터링하여 개수 카운팅하자 DB 설계 반영 지침 최대한 정규화를 지켜서 DB 설계하자 정규화 적용하지 않은 케이스의 의견들 정규화를 지키면 테이블 개수가 많아져서 관리가 불편해요. → 데이터 중복으로 인해 발생하는 단점들이 훨씬 크고 관리하기가 더 어렵다. JOIN을 많이 하면 할수록 성능이 안 좋아져서 정규화를 안 했어요. → 실제로 JOIN을 많이 했을 때 성능이 안 좋아지는 경우도 존재한다. 하지만 이렇게 얘기하는 사람치고 실제로 성능 측정해본 사람이 아무도 없다. (추측만 했을 뿐) 즉, 이상 현상 방지에 가장 초점을 두자 데이터 중복으로 인해 실수로 데이터가 잘못 관리되는 문제가 더 큼 성능 개선은 느려지기 전까지 최대한 안 건드리는 게 Best! 필요성을 느낀다면 반드시 ‘측정’을 기반으로 해야 함 역정규화는 정말 구조로 인한 성능 문제가 클 때만 사용하라 ERD 표기 지침 DB 설계 시 ERD 그리는 게 필수가 아니어서, 보고 해석하는 방법 정도만 알아도 충분 홀로할 때는 편하고 빠른 방법으로 진행 (엑셀, A4지…) 협업할 때는 툴 사용 (ERD Clould, dbdiagram…) 1:1 관계인지 1:N 관계인지만 파악할 수 있으면 됨 (그 외 표기는 잘 안쓰임) 데이터 타입 실전 활용 지침 (MySQL 기준) 주요 사용 타입 정수를 저장해야 하는 경우 : INT 10억이 넘어가는 정수를 저장해야 될 수도 있는 경우 : BIGINT 실수를 저장하고 싶은 경우 : DECIMAL 문자를 저장해야 하는 경우 : VARCHAR(글자수) 6만이 넘어가는 문자를 저장해야 하는 경우 : LONGTEXT TimeZone을 고려하지 않고 날짜/시간 데이터만 저장하면 되는 경우 : DATETIME ex) 국내 서비스 TimeZone을 고려하면서 날짜/시간 데이터를 저장해야 하는 경우 : TIMESTAMP ex) 글로벌 서비스 True, False의 형태를 저장하고 싶은 경우 : TINYINT(1) 참고: 숫자는 숫자로 저장할 수도 있고 문자로 저장할 수도 있음 DB 관점에서는 “계산에서 쓰는 값인지 안 쓰는 값인지”를 기준으로 선택 휴대폰 번호는 문자로 저장 (숫자를 더해서 사용하지 않고 단순히 고유의 값으로 사용할 뿐) 주민등록번호도 마찬가지로 문자로 저장 현업에서 잘 사용하지 않는 데이터 타입 : CHAR, FLOAT, DOUBLE, TEXT 등 Reference 비전공자도 이해할 수 있는 DB 설계 입문/실전
Computer Science
· 2025-01-15
데이터베이스 첫걸음
데이터 베이스가 갖춰야 할 기본 기능 데이터의 검색과 갱신 데이터베이스는 주소록에서 시작 데이터의 조회 및 등록, 수정, 삭제가 가능해야 함 데이터 포멧 및 처리 성능에 대한 고려가 필요 동시성 제어 (= 배타 제어) 데이터베이스는 동시에 복수의 사용자로부터 검색 및 갱신 처리를 받음 갱신의 무결성이 중요 (갱신 상황에 대한 제어가 필요) 만일 두 명의 사용자가 같은 파일에 접근해 수정하려 한다면 다음 동작 중 하나가 시나리오가 될 것 한 사람이 파일을 열고 있을 때, 다른 사람은 열 수 없음 한 사람이 파일을 열고 있을 때, 다른 사람은 읽기 전용(ReadOnly)으로만 파일을 열 수 있음 어떤 사람도 문제없이 파일을 열 수 있고, 나중에 수행된 쪽의 갱신이 반영 이를 더티 쓰기(Dirty Write)라고 하며, 선착순으로 갱신을 반영하는 상황 데이터 무결성 관점에서 지양 장애 대응 데이터베이스는 장애에 강해야 한다. 데이터 보호와 장애 대책에 최대한으로 예민해져야 함 데이터 소실은 큰 사회문제와 손해배상청구 유발 데이터 소실 문제에 대한 대책 데이터 다중화: 데이터를 복수의 장소에 분산해서 유지 (예방책) 백업: 데이터 소실이 발생했을 때 데이터를 복원하는 방법 (사후대책) 보안 데이터베이스에 보존된 데이터를 어떻게 숨길 것인가 데이터베이스는 사용자가 서버를 의식하지 못하도록 설계되고 있음 데이터베이스의 종류 계층형 데이터베이스 데이터를 계층구조로 관리 (조직도, 전체 구조도) 최초의 현대적 데이터베이스 관계형 데이터베이스 2차원 표 형식으로 데이터를 관리 (현재 가장 주류) 프로그래밍 언어를 사용하지 않아도 데이터를 조작 가능 (SQL) SQL이란 관계형 데이터베이스가 데이터를 조작하기 위해 준비한 언어 객체지향 데이터베이스 & XML 데이터베이스 객체와 XML 형식으로 데이터를 관리 (비주류) NoSQL 데이터베이스 Not only SQL (SQL뿐만 아니라 다른 것이 더 있다) 관계형 데이터베이스의 기능 일부를 버리고 성능(처리속도)을 높임 대량의 데이터를 고속으로 처리해야 하는 웹서비스와 잘 맞음 데이터베이스의 구성 DBMS와 데이터베이스 Database 데이터 저장소를 뜻하는 추상화된 개념 DBMS(Database Management System) 데이터베이스의 기능을 제공하는 소프트웨어 데이터베이스 추상화를 구현한 제품 MySQL, PostgreSQL, Oracle… 시스템과 데이터베이스 시스템은 여러가지 소프트웨어를 조합해 만들어야 하며, 이 작업을 SI(System Integration)라고 함 사용되는 소프트웨어는 크게 3가지로 구분하며 계층성을 띔 애플리케이션 비즈니스 로직을 자동화한 소프트웨어 사용자는 애플리케이션을 매개로 데이터베이스에 접근 미들웨어 중간 소프트웨어 DBMS가 해당하는 위치 운영체제 시스템을 동작하게 하기 위한 토대가 되는 기능을 제공하는 소프트웨어 적합한 조합은 예산, 제품 기능, 엔지니어 리소스를 고려해 선택 제품의 비즈니스적 관점도 고려 필요 현시점에서 최고라고 생각해 선택한 조합이 수년 후에는 불가능해지는 곳이 IT 세계 HP-UX + Oracle 조합은 두 기업의 친밀한 관계로 지속되었으나, 추후 서로 소송으로 얽힘 데이터베이스와 비용 시스템 혹은 서비스를 새로 만드는 목적은 돈벌이 관공서나 지방공공단체는 직접적인 이익추구를 하지 않지만, 사회 전체의 이익을 높이기 위해 시스템을 사용 비용감각이 있는 엔지니어가 되어야 함 시스템 전체 비용 내역 초기비용 서비스 이용시 최초로 지급하는 비용 하드웨어 구매비용, 엔지니어 급여… 운영비용 서비스 이용 기간에 지속적으로 지급하는 비용 유지보수 비용 (장애 대응, 프로그램 수정) 데이터베이스 관점의 비용 초기비용 소프트웨어 라이센스 요금 (사용허가료) 시스템 규모가 클수록 라이센스료가 증가 (CPU, 사용자 수는 규모의 척도) 종류 프로세서 라이센스(Processor License) 하드웨어(DB 서버) CPU 성능에 따라 가격 결정 어느 정도 규모를 가진 상용 시스템에서 채택 사용자 라이센스(User License) 사용자 수에 따라 가격 결정 사용자 수 파악이 쉬운 소규모 환경에서 채택 에디션과 옵션 종류 스탠다드 에디션 중소규모 시스템용 엔터프라이즈 에디션 대규모 시스템용 신뢰성, 성능, 보안 등의 추가 기능 지원 제공 익스프레스 에디션 시험판 평범한 기능 및 동작 확인용 운영비용 기술지원 비용 버그에 대한 기술적 Q&A, 긴급 수정 프로그램 배포 등의 지원 데이터베이스는 복잡한 로직으로 구현되어 있으므로, 해당 데이터베이스 개발자의 도움 필요 기술 지원 없는 소프트웨어 사용은 생명줄 없이 등산하는 것 너무 오래된 버전의 제품은 기술지원을 받을 수 있는 기간이 짧음 EOSL(End of Service LIfe) 제품이 배포되고 오랜 시간이 지나 기술 지원이 종료되는 시점 EOSL 가까우면 서비스 채택을 지양하거나 새로운 서비스로 마이그레이션해야 함 반대로 최신 버전은 버그의 집합체로 안정성과 신뢰성에 결함이 있는 경우가 많음 현실적인 데이터베이스 비용 선택지 벤더 제품의 데이터베이스 초기비용 있음 + 운영비용 있음 고기능이 더 많음 반영구적 거주 가능 오픈소스 데이터베이스 초기비용 없음 + 운영비용 있음 기술지원료만 유상 혹은 구독 요금제 초기비용 없이 간단히 시작할 수 있어 의사결정 비용이 낮음 초기비용이 낮으면 전체비용이 높은 경우가 많으니 전체 비용을 확실히 계산 후 냉정한 판단 필요 구독 요금 (Subscription) 무기한 사용의 라이센스 형태와 달리 기한을 정한 사용 허가 운영비용만 존재 기술 지원이 포함 데이터베이스와 아키텍처 구성 아키텍처 역사 아키텍처 시스템을 만들기 위한 물리 레벨의 조합 시스템의 목적과 기능을 표현 (아키텍처를 보고 그 시스템의 용도와 목적을 추측할 수 있음) 폭넓은 지식이 필요 (데이터베이스, 서버, OS, 미들웨어, 저장소, 로드밸런서, 방화벽…) 초반 아키텍처 설계가 프로젝트의 비용과 성패를 결정 역사 Stand-alone (1980) 데이터베이스가 동작하는 머신(DB서버)이 네트워크 없이 독립적으로 동작 물리적으로 서버 앞에 앉아서 사용해야함 클라이언트/서버 (1990~2000) 네트워크를 통해 데이터베이스 서버 1대에 복수 사용자의 단말이 접속하는 구성 보안상 이유로 주로 기업이나 조직 내 닫힌 네트워크(LAN)에 이용 네이티브 애플리케이션을 사용해 비즈니스 로직이 클라이언트에 존재 Web 3계층 (2000~) Web Server, WAS, DB 서버로 이루어진 구성 클라이언트(브라우저)와 DB 서버 사이에 웹 서버와 웹 애플리케이션 서버를 둠 네트워크를 이용해도 애플리케이션 계층과 DB 계층의 보안성을 높일 수 있음 클라이언트의 비즈니스로직을 애플리케이션 계층으로 옮겨서 애플리케이션 관리 비용을 낮춤 다중화 관련 용어 다중화(=고가용성) 서비스 정지를 막기 위해 서버를 여러개 두어 1대가 고장나도 나머지가 동작하도록 구성하는 설계 클러스터링(Clustering) 동일한 기능의 컴포넌트를 병렬화하는 것 클러스터링으로 가용성을 높인다 = 여유도(Redundancy)를 확보한다 = 다중화 가용성 사용자 입장에서 시스템을 어느정도 사용할 수 있는지 신뢰성 컴포넌트(하드웨어, 소프트웨어)가 고장나는 빈도나 고장 기간을 나타내는 개념 가용성을 높이는 2가지 전략 심장전략: 시스템 내 각 컴포넌트의 신뢰성을 높이기 신장전략: 컴포넌트를 병렬화하기 (물량작전) 신뢰성이 낮은 컴포넌트를 사용하더라도 다중화(클러스터링)한다면 시스템 전체 가용성 상승 가동률(=가용률) 시스템이 무고장으로 동작할 확률 100% - 장애 발생률(서버) 100%는 원리적으로 불가능 (비용을 들여도 달성 불가능) 서버가 늘어날수록 가동률이 증가하나 증가 폭은 크게 적어짐 시스템 세계에서는 가용률 99%도 낮은 수치 (= 1년 중 3일 15시간 36분 서비스 다운) 유지보수 등의 계획정지를 포함하지 않는 경우 실제 가용률이란 표현을 사용하는 경우도 존재 단일 장애점(SPFO, Single Point of Failure) 다중화되어 있지 않아서 전체 서비스의 계속성에 영향을 주는 컴포넌트 단일 장애점의 신뢰성이 시스템 전체의 가용성을 결정 단일 장애점을 없애기 위해 대부분 이중화 노력 DB 서버의 다중화 DB 서버는 데이터를 보존하는 영속 계층이기 때문에, 오랫동안 클러스터링이 어려운 컴포넌트로 인식 웹서버, WAS는 데이터를 일시적으로 처리하므로 다중화가 간편 데이터는 항상 갱신되므로 DB 서버 다중화는 데이터 정합성이 중요 DB 서버 아키텍처 = DB 서버 + 저장소 대량의 데이터를 영구적으로 보존해야하고 그에 따른 성능도 요구됨 DB 아키텍처 패턴 클러스터링(Clustering) Shared Disk (기본 다중화) DB 서버 다중화 + 1개 저장소 저장소가 1개라 데이터 정합성은 신경 쓸 필요 없음 종류 (DB 서버 동시 동작 여부에 따라) Active-Active 컴포넌트를 동시에 가동 Oracle RAC, DB2 pureScale 말고는 없음 장점 시스템 다운 시간이 짧음 (한 대가 다운되어도 남은 서버가 계속 처리) 좋은 처리 성능 (DB 서버 대수가 증가하면 동시 가동 CPU 및 메모리도 증가) 단점 저장소가 병목지점이므로 생각만큼 성능 향상이 없는 경우도 존재 저장소가 파괴될 경우 데이터 유실 Active-Standby 컴포넌트 중 실제 가동하는 것은 Active, 남은 것은 대기(Standby) Standby 상태 DB 서버는 Active DB 서버에 장애가 날 때만 사용 Heartbeat: Standby DB 서버는 일정 간격으로 Active DB에 이상 없는지 체크 (수 초~수십 초) 신호가 끊기면 장애 발생으로 판단하고 Standby DB 서버 종작 전환시간만큼의 시스템 다운 발생 (수십초~수분) 종류 Cold-Standby 평소에는 Standby DB 작동 X, Active DB가 다운된 시점에 작동 Hot-Standby 평소에도 Standby DB 작동 전환시간이 더 짧지만, 라이센스료가 더 비쌈 사치스러운 구성이지만, 그럼에도 Active-Active보다 저렴 가용성과 성능이 좋은 순서(= 라이센스 가격순) Active-Active Active-Standby(Hot-Standby) Active-Standby(Cold-Standby) Shared Nothing (성능 추구를 위한 다중화) 네트워크 이외의 자원을 모두 분리하는 방식 서버, 저장소, 데이터를 한 세트 단위로 해서 여러 세트로 분리 구글이 개발한 구조를 Sharding이라고도 부름 (구글이 극적인 방식으로 유효성 증명) 장점 구조가 간단하고 저장소 병목 방지 서버와 저장소 세트를 늘리면 병렬처리 때문에 선형적으로 성능(처리율)이 향상 단점 각각의 DB 서버가 동일한 1개 데이터에 엑세스할 수 없음 시 단위 DB 서버 + 저장소 세트 고양시 데이터는 고양시 데이터를 가진 DB 서버만 엑세스 가능 경기도 인구 계산할 때는 각 시별 세트로부터 데이터를 집계 정리하는 서버 필요 DB 서버 다운 대책으로 커버링(Covering) 구성 필요 한 DB 서버가 다운되면 다른 DB 서버가 이어받아 계속 처리 리플리케이션 (Replication) DB 서버와 저장소 세트를 복수로 준비하는 구성 종류 마스터 슬레이브 (주로 사용) 멀티 마스터 (복잡해서 흔치 않음) 성능과 갱신주기 사이에 트레이드 오프 고려 필요 Active 세트(마스터)와 Standby 세트(슬레이브)가 나뉘어 있음 주기적으로 Standby측 저장소를 최신 데이터로 동기화해야 함 (데이터 정합성 유지) 장점 원격지 리플리케이션 덕분에 가용성이 매우 높음 DB 서버와 저장소가 모두 사용 불능이어도 다른 1세트가 살아있다면 서비스 지속 자연재해로 서울 데이터센터가 파괴돼도 부산 데이터 센터가 무사하면 계속 처리 가능 피라미드형 리플리케이션 구성을 하면 부하 분산도 가능 오래된 데이터를 사용해도 되는 기능은 손자나 증손자 세트에 분산 커넥션과 세션 커넥션 (Connection) 로그인 후 사용자와 데이터베이스가 연결된 상태 커넥션이 유지되는 한 사용자는 데이터베이스와 무언가를 주고 받을 수 있음 데이터베이스는 동시에 여러 개의 커넥션 유지 가능 (=동시에 복수의 사용자 연결 병행처리) 전화 이미지와 유사 전화번호 입력 - 전화 걸기 - 상대방이 전화를 받음 사용자 정보 입력 - 로그인 실행 - 커넥션 연결 완료 세션 (Session) 커넥션의 시작과 종료 사이에서 교환의 시작과 종료까지의 단위 커넥션과 매우 유사하지만 실제로 커넥션 확립 후 세션 생성 기본적으로 커넥션과 세션은 1:1 대응 커넥션이 성립되면 동시에 암묵적으로 세션도 시작, 세션을 끊으면 커넥션도 끊어지는 경우가 대다수 관계형 데이터베이스의 계층 데이터베이스 내부의 테이블은 몇 개의 그룹으로 나뉘어 관리 (디렉토리와 유사) 4 계층 트리구조 (ANSI 표준 SQL) 1계층: 인스턴스 (Instance) 물리적 개념으로 DBMS 동작 단위 프로세스, 서버라 부름 멀티 인스턴스가 가능하지만, 거의 사용하지 않음 2계층: 데이터베이스 (Database) 3계층: 스키마 (Schema) 데이터베이스의 디렉토리에 해당하는 것 사용자가 스키마를 자유롭게 만들어 용도별 분류 혹은 권한 관리 등을 할 수 있음 4계층: 오브젝트 (Object) 테이블(Table), 인덱스 (Index), 저장 프로시저 (Stored Procedure) 등을 총칭 실제 RDBMS의 계층 분류 3계층 RDBMS: MySQL, Oracle MySQL은 데이터베이스와 스키마를 동일한 것으로 간주 Oracle은 인스턴스 아래에 데이터베이스를 한 개만 만들 수 있다는 독자적 제약 (실질적 3계층) 4계층 RDBMS: PostgreSQL, SQL Server, DB2 트랜잭션과 동시성 제어 트랜잭션 (Transaction) DB의 상태를 변경시키기 위해 복수의 SQL 쿼리를 한 작업 단위로 묶은 것 데이터를 파일에 저장하지 않고 데이터베이스를 이용하는 이유 중 하나 특성 (ACID) Atomic(원자성) 트랜잭션 내 작업들이 전부 성공하거나 전부 실패하는 것을 보증 전부 성공하면 COMMIT, 하나라도 실패하면 ROLLBACK Consistency(일관성) 허용된 방식으로만 데이터를 변경할 수 있도록 보증 트랜잭션은 데이터 변경 시 무결성 제약을 지킴 (유니크 제약 등) Isolation(격리성, 고립성) 트랜잭션을 복수 사용자가 동시에 실행해도 각각의 처리가 모순없이 실행되는 것을 보증 모순 없음: 복수의 트랜잭션이 순서대로 실행되는 경우와 같은 결과를 얻을 수 있는 상태 = Serializable (직렬화 가능) 다만 격리성은 동시성 관련 성능 이슈로 인해 트랜잭션 격리 수준을 선택 가능 Serializable은 격리성을 온전히 반영하지만 성능면에서 실용적이지 않음 Durability(지속성) 트랜잭션이 커밋되면 영구적이 되어 그 결과를 잃지 않는 것 시스템 장애도 견딜 수 있음(데이터베이스나 OS의 비정상적 종료) 트랜잭션을 하드 디스크에 로그로도 기록하므로, 성공한 트랜잭션들은 복구 잠금 (Lock) 갱신시 락을 걸어서 후속처리를 블록하는 방법 갱신 중일 때 조회는 블록하지 않음 조회는 락을 얻지 않음 결과적으로 트랜잭션 수행 동안 하나의 로우를 동시에 수정하는 것은 안됨 잠금단위: 테이블 전체, 블록, 행 락 획득 경우 한 트랜잭션이 갱신을 시도하면 락을 얻음 (INSERT, UPDATE, DELETE) SELECT ~ FOR UPDATE로 조회하면, 조회 시점부터 해당 트랜잭션이 끝날 때까지 락을 얻음 애플리케이션에서 금액 조회 후 해당 금액 관련 계산시 필요 락 타임아웃 갱신과 갱신이 부딪히는 경우 나중에 온 트랜잭션이 잠금 대기상태가 됨 설정한 락 타임아웃 대기시간을 넘어가면 다음 중 하나의 롤백 진행 오류가 발생한 쿼리만 롤백 (MySQL 기본 설정) 트랜잭션 롤백을 원할 때는 타임아웃 후 명시적 ROLLBACK 실행 트랜잭션 전체 롤백 innodb_rollback_on_timeout 설정 교착 상태 (Dead Lock) 트랜잭션끼리 각자가 점유하고 있는 락을 교차해 얻으려고 하여, 상황이 바뀌지 않는 상태 DBMS는 교착상태를 자동으로 검출해 상태를 보고 일반적인 데이터베이스에서 발생할 가능성이 있고 모든 것을 없앨 수는 없음 애플리케이션에서 트랜잭션을 항상 재실행할 수 있는 구조로 만들어야 함 대책 트랜잭션을 작은 단위로 자주 커밋 항상 각각의 테이블 액세스 순서 정하기 이유 없는 SELECT ~ FOR UPDATE 피하기 잠금 범위를 줄이기 (행 단위), 다만 동시성이 많은 경우 테이블 단위가 유리할 때도 있음 트랜잭션 격리 수준 (Transaction Isolation level, ANSI 표준) 실용적인 성능을 위해 Serializable로 부터 격리 수준을 완화해 자신이 아닌 다른 트랜잭션의 영향받는 것을 허용하는 4가지 단계 조회하는 사람 관점에서 생각하기 종류 Read Uncommitted (가장 완화) 다른 트랜잭션이 커밋하지 않은 데이터까지 조회 이상현상: Dirty Read, NonRepeatable Read, Phantom Read 갱신시 데이터 정합성 문제가 발생할 수 있어서 유의 (Dirty Read) Read Committed - 일반적으로 가장 많이 사용 커밋 완료된 데이터만 조회 (최신 쿼리 실행 시점 커밋 데이터 읽음) 이상현상: NonRepeatable Read, Phantom Read Repeatable Read 커밋 완료된 데이터만 조회하며, 하나의 트랜잭션에서 반복해 행을 조회하더라도 똑같은 행을 보장 이상현상: Phantom Read Serializable (가장 엄격) 커밋 완료된 데이터만 조회하며, 트랜잭션을 순차적으로 진행시킴 이상현상이 없으나 성능이 낮음 이상현상 격리 수준을 완화하면 직렬화 가능에서 발생하지 않았던 현상 발생 Dirty Read 다른 트랜잭션이 아직 커밋하지 않은 데이터까지 읽음 사용자 A가 값을 변경하고 아직 커밋을 안해도 사용자 B가 변경 값을 읽음 NonRepeatable Read 한 트랜잭션 내에서 같은 행을 다시 조회할 때 값이 다름 행에 초점 사용자 A가 값을 읽고 사용자 B가 해당 값을 변경했을 때, 사용자 A가 다시 조회하면 최초 값이 아닌 변경된 값을 읽음 Phantom Read 한 트랜잭션 내에서두 번이상 범위 조회(count, 범위 검색 등)를 할 때, 데이터가 나타나거나 사라짐 전체 데이터에 초점 사용자 A가 범위 검색을 해 3행을 얻었는데 사용자 B가 범위 검색 조건에 해당하는 데이터 행을 하나 추가하고 커밋하면, 사용자 A가 범위 검색을 재실행했을 때 4행을 얻음 MySQL 테이블 종류 MyISAM형 테이블: 트랜잭션 사용이 불가능한 단순한 구조 InnoDB형 테이블: 트랜잭션 사용 가능 (MVCC 구조, multi versioning concurrency control) MVCC에 따른 MySQL의 특성 (Multi Versioning Concurrency Control) 갱신중이라도 읽기는 블록되지 않음 (읽기와 읽기도 서로 블록하지 않음) 갱신 시 락을 얻음 (락은 기본적으로 행 단위로 얻으며 트랜잭션 종료시까지 유지) 갱신과 갱신 상황에서 나중에 온 트랜잭션의락 획득 시도를 블록 (락 타임아웃만큼 대기) 갱신 시 갱신 전 데이터를 UNDO 로그로 롤백 세그먼트 영역에 유지 (트랜잭션 롤백, 격리수준 대응 용) Read Uncommitted 사용이 드문 이유 과거에는 MVCC가 주류가 아니어서, 시점에 따라 읽기가 블록되는 경우가 있었다. 해당 시기에는 값의 부정확함을 담보하더라도 읽기를 블록하지 않고 싶어 Read Uncommitted를 편리하게 사용했었는데, 현재는 MVCC가 읽기를 블록하지 않아서 필요성이 크게 줄었다. DBMS 차원에서 지원하지 않는 경우도 있다. (PostgreSQL, Firebird) 오토커밋(AutoCommit) 명시적 트랜잭션 개시: BEGIN TRANSACTION, START TRANSACTION, SET TRANSACTION 트랜잭션 개시가 명시적으로 지정되지 않았을 때, 오토커밋 모드에 여부에 따라 다음과 같이 트랜잭션을 구별 오토커밋 모드 하나의 SQL 문이 하나의 트랜잭션 (쿼리 실행 직후 자동 커밋) 보통 DBMS의 기본 설정(디폴트) 수동커밋 (오토커밋 모드 비활성) COMMIT 혹은 ROLLBACK 실행할 때까지가 하나의 트랜잭션 트랜잭션 기능을 제대로 수행하기 위한 조건 수동커밋을 설정하는 것을 트랜잭션을 시작한다고 표현 설정한 오토커밋 옵션은 해당 세션 내에서 계속 유지 (중간에 변경 가능) DDL은 실행시 자동으로 암묵적 커밋이 발생 DDL, DML, DCL SQL 명령은 DDL, DML, DCL로 구분되며, SQL문 대부분은 DML이다. 데이터 정의 언어 (DDL, Data Definition Language) 스키마 혹은 테이블 등의 데이터를 저장하는 그릇을 작성하거나 제거 CREATE, DROP, ALTER 데이터 조작 언어 (DML, Data Manipulation Language) 테이블의 행의 검색 및 변경에 사용 SELECT, INSERT, UPDATE, DELETE 데이터 제어 언어 (DCL, Data Control Language) 데이터베이스에서 실행한 변경을 확정하거나 취소하는 데 사용 COMMIT, ROLLBACK 테이블 설계의 기초 관계형 데이터베이스가 표준이 된 이유는 데이터 정합성을 높이기 위한 설계 노하우가 매우 발달했기 때문 테이블은 집합이자 함수다! 테이블의 개념 테이블 명은 반드시 복수형이나 집합명사로 표현해야 함 (=공통 속성을 가진 것의 집합) 테이블은 현실세계를 반영 집합과 사물의 계층을 지켜야 함 가장 상위의 개념집합으로 정리해야 함 중복 행을 허용하지 않음 (기본키의 중요성) 등록 후 변경이 전혀 없는 과거 이력 데이터 같은 경우는 기본키 관리가 엄격하지 않아도 됨 거래, 병력, 급여 명세 등 다만, 기본적으로 기본키는 자연키보다 대리키(surrogate key)를 권장 (자연키는 변화함) 테이블은 클래스와 비슷하지만 메소드를 가지지 않아서 액션이 없고 데이터 조작만 받는 수동적인 존재 함수 종속성 테이블은 함수다 (=함수 종속성) 함수는 입력 값과 출력 값의 대응표 테이블은 기본키를 특정하면 어떤 레코드의 열 값 전체가 고유하게 특정됨 제2정규형과 제3정규형은 함수 종속성을 정리해 가는 과정 정규화 기본적인 테이블 정의 이론 설계 감각이 없는 사람이라도 어느정도 기계적으로 정답에 도달할 수 있도록 고안된 절차 테이블 설계는 90%(제1,2,3정규형 충족) + 10%(성능을 고려한 반정규화) 정규형을 지키지 않으면 갱신이상이 발생할 수 있음 갱신이상: 갱신 시 데이터부정합 종류 제1정규형(1NF) 스칼라 값만 존재하는 테이블 (테이블 셀에 배열 같은 복합적인 값을 포함하지 않음) 관계형 데이터베이스 테이블은 전부 제1정규형을 자동으로 만족 (기술적으로 위반 불가능) 제2정규형(2NF) 부분함수 종속성이 없는 테이블 기본키가 1개 열이라면, 자동으로 제2정규형 만족 부분함수 종속성 기본키가 복합키일 때, 기본키를 구성하는 열의 일부에만 함수 종속성이 있는 것 부분함수 종속성이 있는 테이블 열: [“고객기업 ID”, “주문번호”, “주문접수일”, “고객기업명”, “고객기업 규모”] 기본키가 {“고객기업 ID”, “주문번호”}일 때 테이블에 “고객기업명”, “고객기업 규모” 열은 “고객기업 ID”만으로 특정됨 두 열에 대해서 “주문번호”는 쓸데없는 정보 부분함수 종속이 존재하면, 해당 키와 종속하는 열만 다른 테이블로 만들어 외부로 꺼내야 함 불만족시 갱신이상 고객기업 정보를 어느정도 알지 못하면 주문을 등록할 수 없음 고객기업 규모를 모르면 값을 넣기 어려움 (NULL, 더미값 등록은 권장 X) 같은 고객기업 행이 복수 행 존재 (잘못 등록될 위험) 제3정규형(3NF) 추이함수 종속이 없는 테이블 추이함수 종속 기본키 이외의 키 간에 발생하는 함수 종속 추이함수 종속이 있는 테이블 열: [“고객기업 ID”, “고객기업명”, “고객기업 규모”, “업계코드”, “업계명”] {업계코드} -> {업계명}의 함수 종속이 존재 추이함수 종속이 존재하면, 마찬가지로 테이블을 나누어 외부로 꺼내야 함 불만족시 갱신이상 기업 단위의 집합을 반영하는 테이블 업계 데이터만 추가하고 싶을 때, 기업과 실제 거래하지 않으면 새 레코드 추가 불가능 ER 다이어그램 (Entity-Relationship Diagram) 테이블 간의 관계를 그래픽으로 이해하기 쉽게 도와주는 기술 정규화로 인해 테이블이 많아지면, 시각적 표기가 중요해짐 IE(Information Engineering) 표기법이 널리 쓰임) 백업과 복구 데이터베이스는 크래시(비정상적 시스템 장애)가 일어날 때, 해당 시점까지 최신 커밋된 상태를 복구 지속성(Durability)을 지키며 성능을 높이기 위해 데이터베이스는 다음 구조를 가짐 DBMS의 데이터 보존 기억장치는 하드디스크 (느림) 로그 선행 쓰기 (WAL, Write Ahead Log) 우선 로그로 변경 내용을 기술하고 로그 레코드를 써서 하드디스크와 동기화 (MySQL InnoDB 로그) 디스크에 쓰는 횟수를 줄일 수 있어 성능이 좋음 크래시가 일어나면 메모리(버퍼) 상 데이터는 잃지만, WAL과 체크포인트를 참고해 복구 (=롤포워드) 백업 크래시 복원도 논리적 파괴(DDL 테이블 파기)나 물리적 파손(디스크 장치 고장)은 대응 불가능 정상 동작할 때 주기적으로 백업 중요 PITR (Point-in-time Recovery) 백업 이후 시점 실행된 갱신을 기록한 로그(archive)를 보존해서 복원한 DB에 순차 반영 백업으로 복원은 단순히 백업 시점으로 되돌리는 것이라 이후 수행한 갱신 반영 위해 필요 WAL로 쓰인 로그를 아카이브 지정해 PITR 용으로 보존할 수 있음 3가지 관점에 따른 백업 형태 데이터베이스 가동 여부 핫 백업 (=온라인 백업) 데이터베이스를 가동한채로 백업 데이터베이스 기능으로 백업 (mysqldump) 콜드 백업 (=오프라인 백업) 데이터베이스를 정지한 상태에서 백업 OS 기능으로 백업 (데이터 디렉토리의 모든 파일을 전부 복사) 백업 데이터 형식 구분 논리 백업 SQL 기반의 텍스트 형식으로 백업 데이터 기록 오픈 소스 DBMS 위주 물리 백업 데이터 영역을 그대로 덤프 (바이너리 형식) 벤더 DBMS 위주 백업 데이터 양 풀 백업 전체 데이터를 매일 백업 부분 백업 우선 풀 백업한 후, 갱신된 데이터 따로 백업 차등(Differential) 백업 풀 백업에서 차등만 백업 최초 풀 백업과 최후의 차등 백업으로 복원 증분(Incremental) 백업 전일로부터 증분만 백업 최초 풀 백업과 모든 증분으로 복원 백업 파일들은 떨어진 곳에 각각 보관하는 것이 중요 데이터 베이스와 백업 데이터를 다른 디스크 장치로 나눠 보관 장치를 지리적으로 떨어진 장소에 두면, 자연 재해로부터 데이터 보호도 가능 데이터베이스 장애는 일정 비율로 항상 일어나므로, 이를 고려해 대책을 세우고 비율을 줄이는 노력 필요 성능과 데이터베이스 성능 측정의 2가지 지표 처리시간 (Processing Time) = 응답시간 (Response Time) 어떤 특정 처리의 시작부터 종료까지 걸린 시간 처리율 (Throughput) 특정 처리를 단위 시간에 몇 건 처리 가능한가 50 TPS (트랜잭션을 초당 50건 처리), 50 PV/S (웹페이지를 초당 50회 열람) 시스템의 자원 용량을 결정하는 요인 처리율(동시 실행된 처리)에 비례해 필요한 자원 양 증가 시스템 자원 중 하나에서 병목 지점이 생기면, 한계점을 넘어 시스템 성능이 급격히 떨어짐 사이징(Sizing), 캐퍼시티 플랜(Capacity Plan) 한계점을 고려해 미리 자원을 확보해야 함 데이터베이스는 병목 되기 쉬운 포인트 취급하는 데이터 양이 가장 많음 스케일 아웃으로 해결이 어려움 데이터베이스 병목지점은 CPU, 메모리가 아닌 하드디스크 스케일 아웃은 Shared Nothing 정도만 해당 스케일 업을 통한 해결은 인메모리 데이터베이스로 실현 튜닝 애플리케이션을 효율화해 같은 양의 자원이라도 성능을 향상하게 하는 기술 = 어떻게 하면 SQL을 빠르게 할 수 있을까 데이터베이스는 성능 향상 제약 상황으로 인해 전통적으로 튜닝 기술이 발달 인덱스로 해결할 수 있는지 검사하는 것이 제1 선택 데이터베이스의 SQL 처리 과정 파스 (Parse) SQL 문이 문법적으로 잘못된 부분이 없는지 검사 파서(Parser)가 담당 실행계획 (Execution Plan) SQL 문에 필요한 데이터를 어떤 경로로 접근할지 계획 옵티마이저(Optimizer)가 담당 수많은 경로 중 가장 효율적인 경로를 선택 (풀 스캔, 레인지 스캔 판단 등…) 통계정보(Statistics) 옵티마이저가 실행계획을 세울 때 입력값으로 사용하는 정보 테이블 데이터를 샘플링 추출해 계산한 것으로 정확한 정보는 아니지만 속도적 이점을 줌 테이블 행열수, 각 열의 길이 및 데이터형, 테이블 크기, 기본키 및 NOT NULL 정보, 열 값의 분산 및 편향 등 DBMS가 자동으로 수집 (대체로 대량의 데이터가 변경될 때) 올바른 통계정보 수집이 중요 결과 정보 갱신 설정이 ON이 되게 해야함 (혹시 안되어 있다면 낡은 통계 정보 쓰게됨) 정기 갱신 형태에서 급격히 데이터 양이 변화하면, 실행계획이 비효율적일 수 있음 실행계획 평가 데이터 액세스 테이블 액세스 방법 실행 계획의 type 열 종류 풀 스캔 (All) 테이블에 포함된 레코드를 처음부터 끝까지 전부 읽어 들이는 방법 레인지 스캔 (range, ref…) 인덱스를 사용해 테이블의 일부 레코드에만 액세스하는 방법 인덱스 (Index) 책의 목차, 색인 구조 (B-tree) 핵심: 데이터를 반드시 정렬된 형태로 유지 균형 트리 구조 (Balanced-tree) 루트부터 리프까지의 거리가 일정한 트리구조 트리 중에서도 성능이 안정화 성능적이점 어떤 값에 대해서도 같은 시간에 결과를 얻음 (균일성) 이진 탐색 일반적으로 B-tree의 계층은 3~4 정도로 조절됨 어떤 값을 찾아도 2~4회 노드 액세스로 탐색 완료 데이터 양이 증가할 수록 성능 개선 효과 우수 (Log N) 1GB, 100만행도 소~중규모 데이터 인덱스의 큰 개선 효과는 더 큰 데이터에서 나옴 내부적으로 정렬을 사용하는 SQL의 정렬을 생략해 고속화 GROUP BY, 집계 함수, 집합 연산 (UNION, INTERSECT, EXCEPT)… 키로 지정된 열에 인덱스가 존재하면, 이미 정렬된 데이터를 바탕으로 정렬 생략 DB마다 차이는 있음 갱신 빈도가 높은 테이블은 정기적으로 인덱스 재구성으로 트리의 균형을 되찾아야 함 갱신이 반복되면 트리의 균형이 깨져가고, 인덱스 성능도 악화됨 어느정도 자동으로 균형 회복 기능 있지만, 수동 재구성도 필요 무분별한 인덱스 생성의 역효과 인덱스 갱신의 오버헤드로 성능 감소 통상 1행 레코드의 인덱스 갱신은 매우 빠름 몇천 몇만 몇억행 갱신이 모이면 인덱스 갱신 시간을 얕볼 수 없음 의도한 것과 다른 인덱스 사용되기도 함 인덱스 생성 기준 크기가 큰 테이블만 만들기 크기가 작은 테이블은 풀 스캔과 레인지 스캔의 차이가 없음 기본키 제약, 유일성 제약이 부여된 열에는 불필요 암묵적으로 이미 인덱스가 작성되어 있음 값의 중복 체크를 위한 데이터 정렬에 인덱스를 사용하면 편리하기 때문 Cardinality가 높은 열에 만들기 Cardinality: 값의 분산도 카디널리티가 높아야 인덱스 혜택을 받을 수 있음 예시 운전면허증 번호 »> 넘을 수 없는 벽 »> 한국 시도 행정구역 > 성별 Reference 데이터베이스 첫걸음 DB 격리 수준과 이상현상 스프링 DB 1편 - 데이터 접근 핵심 원리
Computer Science
· 2024-04-29
MySQL 주요 명령
MySQL 주요 관리명령 show status MySQL의 상태에 대한 여러 정보 확인 Threads_connected 커넥션의 상태 및 수 Uptime 서버 가동 후 경과 시간 Queries 실행한 SQL의 수 show databases 데이터베이스 목록 보기 show tables 테이블 목록 보기 show table status 통계정보 보기 show create table 테이블명\G 테이블 정의 보기 explain SQL문 해당 SQL문의 실행계획 취득 show index from 테이블명 인덱스를 표시 desc 테이블명 테이블 열 정보 보기 use 데이터베이스 이름 특정 데이터베이스 사용하기 quit 로그오프 MySQL 주요 SQL CREATE TABLE 테이블명 1 LIKE 테이블 2; 테이블 구조만 복제해 생성하기 INSERT INTO 테이블명 VALUES (..., ..., ...), (..., ..., ...), (..., ..., ...); 복수 행 입력 (Multi row insert) INSERT 문 처리를 1번으로 정리해서 기존 INSERT 문 복수 회 실행 보다 처리시간이 더 짧음 다른 DBMS도 구현되어 있는 경우가 있음 (PostgreSQL, SQLServer, DB2…)
Computer Science
· 2024-04-13
관계형 데이터베이스 모델 개념
Relational Data Model & Relational Database Relation in Mathematics Set 서로 다른 elements를 가지는 collection elements의 순서는 중요하지 않음 Cartesian Product Set A & Set B의 element로 만들 수 있는 모든 pair의 조합 Relation Cartesian product의 부분 집합 (subset of Cartesian product) n-ary relation: n개의 Set에 대한 cartesian product의 부분집합 tuple들의 집합 (set of tuples) tuple은 하나의 pair를 의미 Relational Data Model Relation이 Relational Data Model에서는 Table로 표시 Relation = Table = Set of Tuples tuple(행) & attribute(열) Relation Schema Relation의 구조를 나타냄 (constraints 포함) e.g. Student(id, name, grade, major, phone_num, emer_phone_num) Degree of Relation Relation schema에서 attributes의 수 Relational Database Relational data model에 기반하여 구조화된 database (여러개의 relations로 구성) Relational Database Schema relation schemas set + integrity constraints set Constraints Implicit constraints Relational Data Model 자체가 가지는 제약 Explicit constraints (Schema-based Constraints) 주로 DDL을 통해 schema에 직접 명시 종류 Domain Constraints Attribute value는 해당 attribute가 가질 수 있는 value여야 함 Key Constraints 서로 다른 tuple은 같은 key 값을 가질 수 없음 Null value Constraints Attribute가 NOT NULL로 명시 됐다면, NULL을 값으로 가질 수 없음 Entity Integrity Constraints Primary key는 NULL을 가질 수 없음 Referential Integrity Constraints FK는 PK에 없는 value를 값으로 가질 수 없음
Computer Science
· 2023-10-03
데이터베이스 기본 용어
Database 전자적으로 저장되고 사용되는 관련있는 데이터들의 조직화된 집합 Electronically, Related, Organized collection DBMS (Database Management System) 사용자에게 DB를 정의 및 관리하는 기능을 제공하는 소프트웨어 시스템 PostgreSQL, MySQL, Oracle Database, SQL Server Metadata(=Catalog, Data about Data) DB를 설명하는 데이터 (Descriptive) DBMS를 통해 관리됨 e.g. 데이터 유형, 구조, 제약 조건, 보안, 저장, 인덱스, 사용자 그룹 etc… Database System Database + DBMS + 연관된 applications 포괄적으로 database라고 부르기도 함 Data Model DB의 구조를 추상화해 설명하는 모형 (DB 구조: 데이터 유형, 데이터 관계, 제약 사항 etc…) DB 기본 Operations(CRUD)를 포함 종류 Conceptual Data Model (=high-level) 일반 사용자들이 쉽게 이해할 수 있게 DB를 구조화 (추상화 수준이 가장 높음) 비즈니스 요구사항 기술에 사용 Logical Data Model (=representational) 특정 DBMS에 종속되지 않는 수준에서 디테일하고 이해하기 쉽게 DB를 구조화 실제 DB 설계를 할 수 있는 수준 종류 (DBMS가 채택) relational data model (MySQL, Oracle DB, SQL Server) object data model object-relational data model (PostgreSQL) Physical Data Model (=low-level) 컴퓨터에 데이터가 어떻게 파일 형태로 저장되는지를 기술 data format, data orderings, access path(e.g. index…) Database Schema Data Model을 바탕으로 database의 구조를 기술한 것 Database State (=Snapshot =현재 instances의 집합) 특정 시점에 database에 있는 실제 데이터 Three-Schema Architecture User Application으로 부터 물리적인 database를 분리 각 레벨을 독립시켜 어느 레벨의 변화가 상위 레벨에 영향을 주지 않게 함 (안정적인 데이터베이스 운영) Database system을 구축하는 architecture 중 하나로 가장 많이 사용됨 대부분의 DBMS가 어느정도 따르나 three level을 완벽하게 나누지는 않음 Conceptual 변화는 External Level에 영향을 안 미치는 것이 상대적으로 힘들기 때문 각각의 Schema는 DB 구조를 표현만 함. 데이터가 실제 존재하는 곳은 internal level 분류 external schemas at external level (user view) 특정 유저들이 필요로 하는 데이터만 표현 (그 외 데이터는 숨김) logical data model을 통해 표현 conceptual schemas at conceptual level internal schema를 추상화해서 물리적인 저장 구조 내용은 숨기고 전체 DB 구조를 기술 entities, data types, relationships, user operations, constraints에 집중 logical data model을 통해 표현 internal schemas at internal level 물리적으로 데이터가 어떻게 저장되는지 physical data model을 통해 표현 data storage, data structure, access path 등 실체가 있는 내용 기술 Database Language 오늘날 DBMS는 DML, VDL, DDL이 따로 존재하기 보다는 통합된 언어로 존재 (e.g. SQL) 언어 종류 DDL (Data Definition Language) Conceptual Schema를 정의하기 위해 사용하는 언어 SDL (Storage Definition Language) Internal Schema를 정의하기 위해 사용하는 언어 최근엔 파라미터 설정으로 대체 (SDL은 거의 없음) VDL (View Definition Language) External Schema를 정의하기 위해 사용하는 언어 대부분의 DBMS에서 DDL이 VDL 역할까지 수행 DML (Data Manipulation Language) Database에 있는 실제 data를 활용하기 위한 언어 (CRUD)
Computer Science
· 2023-10-01
데이터베이스
SQL Overview SQL(Structured Query Language)은 데이터베이스에서 데이터를 저장, 조작 및 조회하기 위한 standard language입니다. Oracle, MySQL, Postgres 등의 다양한 데이터베이스에서 표준으로서 사용됩니다. 본 포스팅은 자세히보다는 가볍게 SQL 용법들을 정리하려고 합니다. Demo DB 예시로 사용하는 DB는 Northwind 데이터베이스입니다. 해당 데이터베이스에는 여러 table이 존재하는데, 그중 Customers 데이터베이스는 다음 표와 같은 모습을 가집니다. SQL basic SQL 작성 순서 SELECT FROM WHERE GROUP BY HAVING ORDER BY SELECT SELECT 구문은 데이터 조회를 위해 사용합니다. Syntax SELECT column1, column2, ... FROM table_name; 만일, Customers테이블에서 CustomerName과 City column만 조회하고 싶다면 다음과 같이 쿼리를 만듭니다. SELECT CustomerName, City FROM Customers; 특정 column이 아닌 전체 데이터를 조회하고 싶다면 *을 사용합니다. SELECT * FROM table_name; DISTINCT SELECT DISTINCT를 사용하면 중복되는 데이터를 unique하게 조회할 수 있습니다. Syntax SELECT DISTINCT column1, column2, ... FROM table_name; 만일, 고객들이 어떤 국적을 갖고 있는지만 파악하고 싶다면, SELECT DISTINCT로 City를 조회합니다. SELECT DISTINCT Country FROM Customers; 위와 동일한 SQL 결과를 GROUP BY로도 만들 수 있습니다. SELECT Country FROM Customers GROUP BY Country; WHERE Records를 특정 조건식으로 필터링하는데 사용합니다. SELECT 뿐만 아니라 UPDATE, DELETE 등의 명령어에서도 사용합니다. Syntax SELECT column1, column2, ... FROM table_name WHERE condition; 예를 들어, France 국적 고객들만 조회하고 싶다면 다음과 같이 사용합니다. SELECT * FROM Customers WHERE Country='France'; WHERE의 조건식에는 AND, OR, NOT 논리 연산자와 더불어 다음과 같은 연산자들이 사용됩니다. LIKE/NOT LIKE 또한, WHERE내에서는 column에서 Pattern을 찾아내는 LIKE 연산자도 사용할 수 있습니다. LIKE 연산자와 함께 쓰이는 wildcard는 데이터베이스 종류마다 다를 수 있지만, 다음은 SQL Server에서 자주 쓰이는 대표적 wildcard의 예시입니다. %: 0개 이상의 characters를 의미하는 기호입니다. _: 1개의 character를 의미하는 기호입니다. 다음은 LIKE의 사용 예시들입니다. IN/NOT IN IN은 특정 값들에 해당하는 record만 남겨주는 연산자입니다. OR을 여러번 사용한 것과 동일한 기능을 할 수 있습니다. Syntax 1 SELECT column_name(s) FROM table_name WHERE column_name IN (value1, value2, ...); Syntax 2 SELECT column_name(s) FROM table_name WHERE column_name IN (SELECT STATEMENT); BETWEEN/NOT BETWEEN BETWEEN은 특정 범위 내의 값들을 선택합니다. 범위로 사용할 수 있는 값으로 숫자, 문자, 날짜 자료형이 있습니다. 또한, 설정한 시작 값과 끝 값은 모두 범위 내에 포함됩니다. Syntax SELECT column_name(s) FROM table_name WHERE column_name BETWEEN value1 AND value2; ORDER BY ORDER BY는 특정 column을 기준으로 정렬을 수행합니다. Default는 오름차순 정렬이고, 내림차순으로 정렬하고 싶다면 DESC 키워드를 뒤에 붙여줍니다. Aggregate Function 사용도 가능합니다. Syntax SELECT column1, column2, ... FROM table_name ORDER BY column1, column2, ... ASC|DESC; Country column을 기준으로 내림차순 정렬을 하고 싶다면 다음과 같이 쿼리를 만듭니다. SELECT * FROM Customers ORDER BY Country DESC; INSERT INTO INSERT INTO는 새로운 records를 table에 추가합니다. Syntax 1 - column을 특정지어 추가할 때 (value가 빈 column에는 null 값이 삽입됩니다.) INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...); Syntax 2 - 모든 column에 value를 추가할 때 (value를 추가하는 순서는 해당 테이블의 column 이름 순서를 따릅니다.) INSERT INTO table_name VALUES (value1, value2, value3, ...); CustomerID의 경우 record가 생성될 때 자동으로 입력되어지므로 신경쓰지 않아도 됩니다. 모든 열에 대해서 생략은 기본값을 사용한다는 의미로 해석됩니다. 혹은 명시적으로 DEFAULT를 값으로 넣어주면 지정한 기본값을 사용해 생성합니다. IS NULL NULL 값은 =, <, <> 같은 비교 연산자로 처리할 수 없습니다. 대신에, NULL 값은 IS NULL과 IS NOT NULL을 사용해 비교합니다. UPDATE UPDATE는 기존의 records를 수정할 때 사용합니다. 수정되는 record의 수는 WHERE의 조건식을 통해 정해집니다. 만일 WHERE가 빠지면 table의 데이터가 모두 갱신되므로, 유의해야 합니다. Syntax UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition; 예를 들어, Customers의 테이블의 CustomerID가 1인 record에서 ContactName을 ‘Lucian’, City를 ‘Seoul’로 바꾸고 싶다면 다음의 쿼리를 만들면 됩니다. UPDATE Customers SET ContactName = 'Lucian', City= 'Seoul' WHERE CustomerID = 1; DELETE 기존의 records를 삭제할 때는 DELETE를 사용합니다. 삭제되는 record 수는 WHERE을 통해 정해집니다. 만일 WHERE가 빠지면 table의 데이터가 모두 삭제되므로, 유의해서 삭제해야 합니다. Syntax DELETE FROM table_name WHERE condition; 만일, CustomerName이 ‘Alfreds Futterkiste’인 record를 삭제하고 싶다면 다음과 같이 쿼리를 만듭니다. DELETE FROM Customers WHERE CustomerName='Alfreds Futterkiste'; 부분 조회 데이터베이스의 퍼포먼스를 위해 테이블의 records를 전부 조회하지 않고 일정 부분만 따로 조회하는 방법도 존재한다. 이를 위한 문법은 데이터베이스들마다 상이한데, MySQL은 LIMIT, SQL Server/MS Access는 SELECT TOP, Oracle은 FETCH를 사용한다. Aggregate functions 다음 함수들은 특정 Column의 values를 원하는 목적으로 계산하여 return합니다. (기본적으로 NULL을 제외하고 집계하며, COUNT 함수만 NULL을 포함한 전체 행 집계) COUNT() Syntax SELECT COUNT(column_name) FROM table_name WHERE condition; MAX() Syntax SELECT MAX(column_name) FROM table_name WHERE condition; MIN() Syntax SELECT MIN(column_name) FROM table_name WHERE condition; AVG() Syntax SELECT AVG(column_name) FROM table_name WHERE condition; SUM() Syntax SELECT SUM(column_name) FROM table_name WHERE condition; Aliases Table이나 column에 임의적으로 이름을 지어줄 수 있습니다. Alias는 해당 쿼리에 한해서만 유효합니다. Column Syntax SELECT column_name AS alias_name FROM table_name; Table Syntax SELECT column_name(s) FROM table_name AS alias_name; 만일 alias가 띄어쓰기를 포함한다면, double quotation(““)이나 square brackets([])를 사용해 감싸줍니다. SELECT CustomerName AS Customer, ContactName AS [Contact Person] FROM Customers; 다음과 같이 여러 개의 column을 합쳐 만든 새로운 column에 alias를 사용할 수도 있습니다. SELECT CustomerName, Address + ', ' + PostalCode + ' ' + City + ', ' + Country AS Address FROM Customers; 혹은, 길어지는 SQL 쿼리를 조금 더 짧게 쓰기 위해 table alias를 사용할 수도 있습니다. SELECT o.OrderID, o.OrderDate, c.CustomerName FROM Customers AS c, Orders AS o WHERE c.CustomerName='Around the Horn' AND c.CustomerID=o.CustomerID; JOIN 관련된 columns을 기준으로 두 개 이상의 table의 records를 합칩니다. INNER JOIN: 대상 tables에서 ON의 조건에 match되는 모든 records를 가져옵니다. FULL OUTER JOIN, FULL JOIN: 대상 tables에서 ON의 조건에 match되는 모든 records를 가져오고, 대상 tables에 남아있는 match되지 않은 records를 모두 가져옵니다. (이때, 빈 field는 NULL 값으로 채워서 가져옵니다) LEFT JOIN: 왼쪽 table의 모든 records를 가져오고, 오른쪽 table에서 ON의 조건에 match되는 records를 붙입니다. (이 때, 빈 field는 NULL 값으로 채웁니다.) RIGHT JOIN: 오른쪽 table의 모든 records를 가져오고, 왼쪽 table에서 ON의 조건에 match되는 records를 붙입니다. (이 때, 빈 field는 NULL 값으로 채웁니다.) UNION 2개 이상의 SELECT 쿼리의 결과를 하나로 합쳐서 내어줍니다. UNION 사용 시, 모든 SELECT문들은 동일한 개수의 column을 동일한 순서대로 가져야 하며, 각 column의 데이터 타입도 비슷해야 합니다. UNION syntax - unique values SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2; UNION ALL syntax - allow duplicated data SELECT column_name(s) FROM table1 UNION ALL SELECT column_name(s) FROM table2; GROUP BY 데이터를 특정 칼럼을 기준으로 그룹화하여 그룹별로 구분할 때 사용합니다. GROUP BY는 aggregate functions와 함께 자주 쓰입니다. Syntax SELECT column_name(s) FROM table_name WHERE condition GROUP BY column_name(s) ORDER BY column_name(s); HAVING Aggregate function을 사용해 조건식을 사용하고 싶을 때 HAVING을 사용합니다. WHERE 구문에서는 aggregate function을 사용할 수 없기 때문에 보통 GROUP BY 함께 사용됩니다. Syntax SELECT column_name(s) FROM table_name WHERE condition GROUP BY column_name(s) HAVING condition ORDER BY column_name(s); EXISTS 서브 쿼리가 반환하는 records가 1개 이상이면 True를 0개면 False를 반환합니다. Syntax SELECT column_name(s) FROM table_name WHERE EXISTS (SELECT column_name FROM table_name WHERE condition); 만일, suppliers 중 가격이 20 미만인 product를 팔고 있는 사람이 누구인지 파악하고 싶다면 다음과 같이 사용합니다. SELECT SupplierName FROM Suppliers WHERE EXISTS (SELECT ProductName FROM Products WHERE Products.SupplierID = Suppliers.supplierID AND Price < 20); EXISTS, IN, JOIN의 속도 차이 EXIST는 데이터의 존재 여부만 파악한 후, 더이상 수행되지 않습니다. 하지만, IN은 실제로 존재하는 데이터들의 모든 값까지 비교하기 때문에 EXISTS보다 느린 경우가 많습니다. JOIN은 일반적으로 EXISTS보다 빠르지만, 중복된 값이 많을 경우 EXISTS가 더 빠르다고 알려져 있습니다. ANY, ALL ANY는 서브 쿼리에 주로 쓰이며, 서브 쿼리의 값 중 하나라도 조건식에 맞는다면 True를 return합니다. Syntax SELECT column_name(s) FROM table_name WHERE column_name operator ANY (SELECT column_name FROM table_name WHERE condition); 반면에 ALL의 경우, 서브 쿼리의 값들이 모두 조건식에 만족되어야만 True를 return합니다. 보통, SELECT, WHERE 혹은 HAVING과 함께 많이 쓰입니다. Syntax SELECT column_name(s) FROM table_name WHERE column_name operator ALL (SELECT column_name FROM table_name WHERE condition); Operator used in ALL, ANY ALL, ANY syntax에 나오는 operator는 =, <>, !=, >, >=, <, <= 등의 비교 연산자입니다. SELECT INTO 한 table의 데이터를 새로운 table에 복사하여 저장합니다. Syntax SELECT column1, column2, column3, ... INTO newtable [IN externaldb] FROM oldtable WHERE condition; 만일, 데이터 없이 table의 schema만 복사해 가져오고 싶다면 다음과 같이 쓸 수도 있습니다. SELECT * INTO newtable FROM oldtable WHERE 1 = 0; INSERT INTO SELECT 특정 table의 데이터를 복사해 다른 table에 삽입합니다. 복사한 데이터의 타입은 삽입할 테이블 내 column의 데이터 타입과 일치해야 합니다. Syntax - All columns INSERT INTO table2 SELECT * FROM table1 WHERE condition; Syntax - Specify columns INSERT INTO table2 (column1, column2, column3, ...) SELECT column1, column2, column3, ... FROM table1 WHERE condition; CASE If… Else… 구문처럼, SQL에서도 조건에 따라 값을 return할 수 있습니다. 조건식이 true인 경우를 만나면 이후 조건은 읽지 않고 값을 return하며, true인 조건이 없으면 ELSE의 값을 return합니다. 만일 조건이 모두 false인데 ELSE가 없다면, NULL 값을 return합니다. Syntax CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 WHEN conditionN THEN resultN ELSE result END; NULL function 만일 NULL 값이 나와서는 안되는 상황이라면, column의 NULL 값 대신 함수를 통해 대체 값을 return해줄 수 있습니다. 다만, NULL function의 이름은 IFNULL(), ISNULL(), COALESCE(), NVL() 등으로 데이터베이스마다 상이합니다. Stored Procedure 자주 사용하는 SQL 코드를 stored procedure로 미리 저장해두고 재사용할 수 있습니다. Parameter를 여러개 설정하여 사용할 수도 있습니다. Syntax - Save CREATE PROCEDURE procedure_name AS sql_statement GO; Syntax - Execution EXEC procedure_name; Comment --: single line comment /*, */: multi line comment Database관련 SQL 데이터베이스 자체를 조작하는 것과 관련된 SQL 문법에 대해 살펴봅니다. CREATE 새로운 SQL 데이터베이스를 생성합니다. 다만, 데이터베이스를 생성할 때는 관리자 권한을 얻어야 합니다. Syntax CREATE DATABASE databasename; 존재하는 데이터베이스 리스트를 확인하고 싶다면 SHOW DATABASES를 사용합니다. DROP 기존에 존재하는 SQL 데이터베이스를 삭제합니다. 역시, 데이터베이스를 생성할 때는 관리자 권한을 얻어야 합니다. Syntax DROP DATABASE databasename; BACKUP 기존에 존재하는 SQL 데이터베이스를 다른 위치에 Backup시킵니다. 다음 SQL은 SQL server에서 적용되는 문법입니다. Full backup syntax 다른 디스크 주소에 데이터베이스를 백업하는 것이 안전합니다. BACKUP DATABASE databasename TO DISK = 'filepath'; Differential backup syntax 이전 버전의 backup에서 변화된 부분만 backup합니다. 덕분에, Backup time을 줄일 수 있습니다. BACKUP DATABASE databasename TO DISK = 'filepath' WITH DIFFERENTIAL; CREATE TABLE 데이터베이스에 새로운 table을 생성합니다. Syntax CREATE TABLE table_name ( column1 datatype, column2 datatype, column3 datatype, .... ); Column parameter에는 해당 column에 설정할 이름을, datatype parameter에는 varchar, integer, date 등의 타입을 명시합니다. 다음은 Persons 테이블을 만드는 예시입니다. CREATE TABLE Persons ( PersonID int, LastName varchar(255), FirstName varchar(255), Address varchar(255), City varchar(255) ); CREATE TABLE에 SELECT를 결합해 사용하면 기존의 테이블에서 원하는 부분을 복사하여 새 테이블을 만들 수도 있습니다. Syntax CREATE TABLE new_table_name AS SELECT column1, column2,... FROM existing_table_name WHERE ....; DROP TABLE 기존에 존재하는 table을 삭제합니다. Syntax DROP TABLE table_name; 만일 table 자체는 남겨두고 table 내의 데이터만 전부 삭제하고 싶다면 TRUNCATE을 사용합니다. Syntax TRUNCATE TABLE table_name; ALTER TABLE 기존 table에 새로운 column을 추가하거나 이미 존재하는 column을 수정 및 삭제할 수 있습니다. ADD column syntax ALTER TABLE table_name ADD column_name datatype; DROP column syntax ALTER TABLE table_name DROP COLUMN column_name; ALTER/MODIFY column syntax Column의 datatype을 수정합니다. SQL Server / MS Access는 ALTER를 사용합니다. MODIFY를 사용하는 데이터베이스도 다수 존재합니다. ALTER TABLE table_name ALTER COLUMN column_name datatype; SQL Constraints Table에 삽입될 수 있는 데이터에 대해 규칙을 정하는 키워드입니다. Table에 들어갈 데이터의 타입을 제한할 수 있어 데이터의 accuracy와 reliability를 높입니다. Constraint의 적용 범위는 column level 혹은 table level이 될 수 있습니다. Constraints는 CREATE TABLE로 table을 생성할 시 정해주거나 ALTER TABLE로 변경 및 삭제할 수 있습니다. Syntax는 대체로 밑의 형태를 따르지만 데이터베이스마다 상이합니다. CREATE TABLE Syntax CREATE TABLE table_name ( column1 datatype constraint, column2 datatype constraint, column3 datatype constraint, .... ); ALTER TABLE ADD syntax ALTER TABLE table_name ADD constraint (column1, column2...); ALTER TABLE DROP syntax ALTER TABLE table_name DROP constraint; Constraint에 이름을 짓고 여러 columns에 한번에 적용하고 싶다면 다음과 같은 방법도 있습니다. (ALTER TABLE에서도 적용됩니다.) CREATE TABLE Persons ( ID int NOT NULL, LastName varchar(255) NOT NULL, FirstName varchar(255), Age int, CONSTRAINT UC_Person UNIQUE (ID,LastName) ); Constraint 종류 NOT NULL: 특정 column에 NULL 값이 존재하지 않게끔 강제합니다. UNIQUE: 특정 column에 같은 값이 존재하지 않게끔 강제합니다. PRIMARY KEY: 각각의 record를 고유하게 구분해줍니다. NOT NULL과 UNIQUE를 자동으로 보장하며 table에 오직 1개만 존재할 수 있습니다. FOREIGN KEY: Table들 사이의 연결을 유지시켜줍니다. FOREIGN KEY는 table 내에 존재하는 하나의 필드이며, 다른 table에서는 PRIMARY KEY로 사용됩니다. FOREIGN KEY가 있는 table을 child table, FOREIGN KEY가 가리키는 PRIMARY KEY가 위치한 table을 parent table 혹은 referenced table이라고 합니다. CHECK: 특정 column에 들어갈 value의 범위를 제한합니다. 조건식을 활용해 원하는 constrain을 걸 수 있습니다. DEFAULT: 특정 column에 대하여 기본값을 지정해줍니다. INDEX: 특정 column에 index를 부여할 수 있습니다. 처음 index를 부여할 때 table 생성 시간은 조금 걸릴 수 있지만, 이후 빠른 데이터 탐색이 가능합니다. INDEX constrain을 부여하는 문법은 다른 constraint와 조금 상이합니다. Syntax - allow duplicated data CREATE INDEX index_name ON table_name (column1, column2, ...); Syntax - not allow duplicated data CREATE UNIQUE INDEX index_name ON table_name (column1, column2, ...); AUTO_INCREMENT: 새로운 record가 만들어질 때마다 값이 자동으로 1씩 증가하여 채워지는 필드를 설정합니다. 처음 시작 기본값은 1로 설정되어 있지만 변경 가능합니다. VIEW View란 SQL 쿼리 결과를 기반으로 만드는 가상 table을 의미합니다. View의 데이터는 그 자체로 실제 존재하는 것은 아니고 기존의 데이터를 어떻게 보여줄지 정의한 것입니다. 따라서, 여러 테이블로부터 가져온 데이터들을 마치 원래부터 하나의 table이었던 것처럼 보여줄 수 있습니다. 또한 기존의 데이터를 보기 좋게 가져오는 것이기 때문에, view의 데이터는 쿼리할 때마다 최신 데이터로 보여집니다. 장점 복잡한 SELECT 문을 일일이 매번 기술할 필요가 없음 필요한 열과 행만 사용자에게 보여줄 수 있고, 갱신도 뷰 정의에 따른 갱신으로 한정할 수 있음 데이터 저장 없이 실현되고, 뷰를 제거해도 참조 테이블은 영향 받지 않음 Create syntax CREATE VIEW view_name AS SELECT column1, column2, ... FROM table_name WHERE condition; Update syntax CREATE OR REPLACE VIEW view_name AS SELECT column1, column2, ... FROM table_name WHERE condition; Drop syntax DROP VIEW view_name; SQL Injection 만일 유저에게 ID 같은 input을 받아 앞에서 보았던 SQL 쿼리들을 사용한다면, 해커들의 위협에 쉽게 노출될 수 있습니다. 해커들은 교묘하게 SQL 문을 조작할 수 있는 형태로 input을 보내, 데이터베이스의 모든 records를 탈취할 수 있기 때문입니다. 이를 안전하게 처리하기 위해 SQL parameters를 사용할 수 있습니다. txtNam = getRequestString("CustomerName"); txtAdd = getRequestString("Address"); txtCit = getRequestString("City"); txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)"; db.Execute(txtSQL,txtNam,txtAdd,txtCit); 위와 같이 @를 사용한 부분은 parameter가 되어 데이터를 input으로 받을 수 있습니다. Execute로 인자들을 SQL 쿼리로 넘겨 실행하면, 보다 안전하게 쿼리를 처리할 수 있습니다. NULL NULL은 불명(Unknown), 적용불가(N/A, Not Aplicable)를 나타내기 위해 사용합니다. DBMS 세계에서는 NULL 사용을 권장하지 않습니다. (NOT NULL) 특히, 다음 2가지 문제로 인해 지양합니다. SQL 코딩 시 인간의 직감에 반하는 3개의 논리값을 고려하게 된다. true, false 외에 추가로 NULL 고려하는 것이 불편 사칙연산 또는 SQL 함수 인수에 NULL이 포함되면 NULL 전파가 일어난다. IS NULL이 아닌 = NULL을 사용하면 원치 않는 결과가 나올 수 있음 Scalar 값 SELECT 문은 일반적으로 열과 행으로 구성된 테이블 형식입니다. 스칼라 값(단일값)은 SELECT 결과의 특수한 형태로 하나의 열과 하나의 행으로 구성된 테이블을 의미합니다. 이러한 스칼라 값은 마치 데이터나 수치처럼 취급해 조건문에 이용할 수 있습니다. Reference w3school - SQL SQL 뷰(view) 소개 SQL에서 연관 서브쿼리 연산자 EXISTS 활용하기 Mysql Exists와 IN절 설명과 차이점
Computer Science
· 2021-06-21
<
>
Touch background to close