├── .gitignore ├── Chapter_01 └── README.md ├── Part_01 ├── Chapter_02 │ ├── 2.1 관계형 데이터베이스의 구조 │ │ └── README.md │ ├── 2.2 데이터베이스 스키마 │ │ └── README.md │ ├── 2.3 키 │ │ └── README.md │ ├── 2.4 스키마 다이어그램 │ │ └── README.md │ └── 2.5 관계형 질의어 │ │ └── README.md └── Chapter_03 │ ├── 3.1 SQL 질의어의 개요 │ └── README.md │ ├── 3.2 SQL 데이터 정의 │ └── README.md │ ├── 3.3 SQL 질의의 기본 구조 │ └── README.md │ ├── 3.4 부가적인 기본 연산 │ └── README.md │ ├── 3.5 집합 연산 │ └── README.md │ ├── 3.6 널 값 │ └── README.md │ └── 3.7 집계 함수 │ └── README.md ├── Part_02 ├── Chapter_06 │ ├── 6.1 설계 과정의 개요 │ │ └── README.md │ ├── 6.2 개체-관계 모델 │ │ └── README.md │ ├── 6.4 대응 카디널리티 │ │ └── README.md │ └── 6.5 주 키 │ │ └── README.md └── Chapter_07 │ ├── 7.1 좋은 관계형 설계의 특징 │ └── README.md │ ├── 7.2 함수 종속을 사용한 분해 │ └── README.md │ ├── 7.3 정규형 │ └── README.md │ └── 7.8 원자적 도메인과 제1정규형 │ └── README.md ├── Part_05 ├── Chapter_12 │ ├── 12.1 물리적 저장 장치 매체 개요 │ │ └── README.md │ ├── 12.2 저장 장치 인터페이스 │ │ └── README.md │ ├── 12.4 플래시 메모리 │ │ └── README.md │ └── 12.6 디스크 블록 접근 │ │ └── README.md ├── Chapter_13 │ ├── 13.1 데이터베이스 저장 장치 구조 │ │ └── README.md │ ├── 13.2 파일 구성 │ │ └── README.md │ └── 13.3 파일에 레코드를 구성하는 방법 │ │ └── README.md └── Chapter_14 │ ├── 14.1 기본 개념 │ └── README.md │ ├── 14.2 순서 인덱스 │ └── README.md │ └── 14.3 B+-트리 인덱스 파일 │ └── README.md ├── Part_07 └── Chapter_17 │ ├── 17.1 트랜잭션 개념 │ └── README.md │ ├── 17.2 간단한 트랜잭션 모델 │ └── README.md │ ├── 17.4 트랜잭션 원자성과 지속성 │ └── README.md │ └── 17.5 트랜잭션 고립성 │ └── README.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | 10 | *.DS_Store 11 | .DS_Store 12 | 13 | /.idea 14 | /.gradle 15 | -------------------------------------------------------------------------------- /Chapter_01/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 1. 서론 2 | 3 |
4 | 5 | ## 데이터베이스 관리 시스템(database-management system, DBMS) 6 | 7 | `서로 관계있는 데이터들의 모임`과 `그 데이터에 접근하기 위한 프로그램의 집합`으로 구성된다. 8 | 9 |
10 | 11 | ### 데이터베이스(database) 12 | 13 | - 보통 데이터들의 모임을 일컫는 말로서, 흔히 조직과 관련된 정보를 포함한다. 14 | - 대규모의 정보를 관리하도록 설계된다. 15 | - 데이터 관리 : 정보 저장 구조를 정의하는 작업 + 저장된 정보를 조작하기 위한 기법 16 | 17 |
18 | 19 | DBMS의 주요 목적은 데이터베이스의 정보를 저장하고 이를 검색하기 위한 **편리하고도 효율적인 환경을 제공**하는 데 있다. 20 | 21 | 또한 저장된 정보를 시스템 고장이나 모든 불법적인 접근 등으로부터 안전하게 **보호**해야 하며, 22 | 데이터가 여러 사용자 간에 공유될 경우 생길 수 있는 **예기치 않은 이상 결과를 방지**해야 한다. 23 | 24 |
25 |
26 |
27 | 28 | # 1.1 데이터베이스 시스템의 응용 29 | 30 | 데이터베이스 시스템은 양적으로 매우 크고, 내용적으로 복잡하고 다양한 데이터 집합을 관리하는 대규모의 소프트웨어 시스템이다. 31 | 32 |
33 | 34 | 복잡성 관리에서 중요한 것은 `추상화(abstraction)` 개념이다. 35 | 36 | > 추상화는 사람이 장치나 시스템이 어떻게 구성되었는지에 대한 자세한 사항을 알 필요 없이 복잡한 장치나 시스템을 사용할 수 있도록 해준다. 37 | 38 |
39 | 40 | 데이터베이스 시스템은 대규모의 복잡한 데이터에 대해서 단순하고 추상화된 관점을 제공하기에, 41 | 사용자와 응용 프로그래머들은 **데이터가 실제로 어떻게 저장되고 조직화되었는지에 대한 자세한 사항을 알 필요가 없다.** 42 | 43 | 데이터베이스 시스템의 높은 수준의 추상화를 제공함으로써 기업이 조직을 운영하는 데 필요한 다양한 형태의 데이터를 정보 저장소에 통합하는 것을 가능하게 만들어 준다. 44 | 45 |
46 |
47 |
48 | 49 | # 1.2 데이터베이스 시스템의 목적 50 | 51 | ## 파일 처리 시스템의 단점 52 | 53 | DBMS가 등장하기 전까지 사용한 `파일 처리 시스템(file-processing system)`의 단점은 다음과 같다. 54 | 55 |
56 | 57 | ### 데이터의 중복과 비일관성 58 | 59 | - 파일과 응용 프로그램은 장기간에 걸쳐 서로 다른 많은 프로그래머에 의해 개발되므로 60 | 파일이 서로 다른 형식을 갖기 쉽고, 응용 프로그램이 서로 다른 언어로 작성될 수도 있다. 61 | 62 | 63 | - 동일한 정보가 여러 파일에 **중복 저장**될 것이다. 64 | 65 | 66 | - `데이터의 비일관성(data inconsistency)`을 초래한다. 67 | - 동일한 데이터의 여러 사본이 서로 다른 값을 보유하고 있는 상태를 말한다. 68 | 69 |
70 | 71 | ### 데이터 접근의 어려움 72 | 73 | 필요한 데이터를 편리하고 효율적으로 검색하기 힘들다. 74 | 75 |
76 | 77 | ### 데이터 고립 78 | 79 | 데이터가 여러 파일에 흩어져 있는 데다 파일 형식이 서로 다르기 때문에 원하는 데이터를 검색하는 프로그램을 새로 작성하기 어렵다. 80 | 81 |
82 | 83 | ### 무결성(integrity) 문제 84 | 85 | 데이터베이스 내에 저장된 데이터 값은 어떤 형식의 `일관성 제약 조건(consistency constraint)`을 만족해야 한다. 86 | 87 | 프로그램 개발자는 여러 프로그램 내에 적절한 코드를 첨가함으로써, 시스템 내에서 데이터들에 대한 **제약 조건**(e.g., 대학이 각 학과의 계좌를 유지하고 각 계좌의 잔고를 저장하려고 할 때, 계좌 잔고가 0 88 | 이하로 떨어지지 않기를 원함)이 잘 지켜지도록 해야 한다. 89 | 90 | 그러나 새로운 제약 조건이 추가되었을 때 기존 프로그램을 일일이 변경하여 해당 제약 조건을 새로이 만족한다는 것은 쉬운 일이 아니다. 91 | 92 |
93 | 94 | ### 원자성 문제 95 | 96 | 시스템이 고장을 일으켰을 때 데이터를 고장 전의 **일관성** 있는 상태로 유지시키는 일은 매우 중요하다. 97 | 98 | 데이터베이스의 일관성을 지키기 위해서는 데이터베이스에 대한 어떠한 행위가 `원자적(atomic)`이어야 한다. 99 | 100 | **즉, 일련의 과정 전체가 수행되든지 아니면 어느 것도 수행되지 않아야 한다.** 101 | 102 | 기존의 파일 처리 시스템에서는 이러한 원자성을 보장하기가 어렵다. 103 | 104 |
105 | 106 | ### 동시 접근의 문제 107 | 108 | 시스템의 전반적인 성능을 향상하고 응답 시간을 단축하기 위해, **많은 시스템은 여러 사용자가 데이터를 동시에 갱신할 수 있도록 한다.** 109 | 110 | 이러한 상황하에서는 동일한 데이터가 여러 사용자에 의해 동시에 갱신될 수 있는데, 이는 **데이터의 비일관성**을 야기할 수 있다. 111 | 112 |
113 | 114 | ### 보안 문제 115 | 116 | 파일 처리 시스템에서는 응용 프로그램이 그때그때 바로 추가되므로 보안에 관한 제약 조건을 지키기 어렵다. 117 | 118 |
119 |
120 |
121 | 122 | # 1.3 데이터의 관점 123 | 124 | 데이터베이스 시스템은 서로 관련이 있는 파일의 모임이자 사용자로 하여금 이 파일에 접근하거나 이를 수정하도록 하는 프로그램의 집합이다. 125 | 126 |
127 | 128 | 데이터베이스 시스템의 주요 목적은 사용자에게 **데이터에 관한 추상적인 관점**을 제공하는 것이다. 129 | 130 | 즉, 시스템은 데이터가 어떻게 저장되고 유지되는지에 관한 세부 사항은 사용자로부터 은폐한다. 131 | 132 |
133 |
134 | 135 | ## 1.3.1 데이터 모델 136 | 137 | `데이터 모델(data model)`은 데이터, 데이터들 사이의 관계, 데이터의 의미 그리고 일관성 제약 조건 등을 기술하기 위한 개념적 표현의 집합이다. 138 | 139 |
140 | 141 | 데이터 모델은 크게 네 개로 분류한다. 142 | 143 | ### 관계형 모델(Relational Model) 144 | 145 | - 데이터와 이들 데이터 사이의 관계를 나타내기 위해 테이블의 모임을 사용한다. 146 | - 각 `테이블(또는 릴레이션(relation))`은 고유한 이름을 가진 여러 개의 `열(column)`로 구성된다. 147 | - **레코드 기반 모델**의 한 예다. 148 | - 데이터베이스가 몇 개의 타입(type)으로 이루어진 고정 형식의 `레코드(record 또는 행(row), 튜플(tuple))`로 구성되기 때문이다. 149 | - 각 테이블은 특정한 타입의 레코드를 포함한다. 150 | - 각 레코드 타입은 정해진 수의 필드(또는 속성)를 정의한다. 151 | - **테이블의 각 열은 레코드 타입의 속성에 대응한다.** 152 | - 가장 널리 쓰이는 데이터 모델이며, 대부분의 데이터베이스 응용의 기본이 된다. 153 | 154 |
155 | 156 | ### 개체-관계 모델(Entity-Relationship Model) 157 | 158 | - `개체-관계 모델(E-R 모델)`은 기본적인 객체들의 집합인 `개체(entity)`와 이러한 개체들 간의 `관계(relationship)`를 사용한다. 159 | - 개체-관계 모델은 데이터베이스를 설계하는 데 널리 쓰인다. 160 | 161 |
162 | 163 | ### 반구조형 데이터 모델(Semi-structured Data Model) 164 | 165 | - 같은 형식을 갖고 있으나, **다소 다른 속성을 가진 개별적 데이터 항목을 기술하기 위한** `비정형 데이터 모델`이다. 166 | - 앞에서 소개한 모델들이 특정 형식의 데이터 항목에 대해서는 동일한 속성의 집합만 갖도록 허용한다는 점에서 대조를 이룬다. 167 | - **JSON**과 확장성 마크업 언어(extensible markup language)인 **XML**이 반구조형 데이터를 표현하는 데 널리 사용된다. 168 | 169 |
170 | 171 | ### 객체 기반 데이터 모델(Object-Based Data Model) 172 | 173 | - 관계형 테이블에 객체를 저장하는 표준이 있다. 174 | - 관계형 모델에 캡슐화, 메서드, 객체 식별화의 개념을 더해 확장한 것처럼 보일 수 있다. 175 | 176 |
177 |
178 | 179 | ## 1.3.3 데이터 추상화 180 | 181 | 데이터베이스는 여러 단계의 `데이터 추상화(data abstraction)`을 통해 복잡한 구조를 되도록이면 감추어 사용자의 이해와 편의를 도와야 한다. 182 | 183 |
184 | 185 | ### 물리적 단계(Physical level) 186 | 187 | - 추상화의 최하위 단계 188 | - 데이터가 실제로 **어떻게** 저장되는지 기술한다. 189 | - 복잡한 하위 단계의 데이터 구조가 상세히 기술된다. 190 | 191 |
192 | 193 |

데이터 추상화 194 | 195 |
196 |
197 | 198 | ### 논리적 단계(Logical level) 199 | 200 | - **어떤** 데이터가 저장되었는지, 데이터들 사이에는 어떤 관계가 있는지를 기술한다. 201 | - 전체 데이터베이스를 몇 개의 비교적 간단한 데이터 구조를 이용하여 기술한다. 202 | - `물리적 데이터 독립성(physical data independence)` 203 | - 논리적 단계의 간단한 구조를 구현하기 위해서는 복잡한 물리적 단계의 구조를 알아야 하는 것이 사실이나, 204 | - 논리적 단계의 사용자는 이러한 복잡한 구조에 대해 전혀 알 필요가 없다. 205 | - 어떤 정보가 데이터베이스에 저장되어야 할지를 결정하는 `데이터베이스 관리자(database administrator, DBA)`가 이 단계에서 작업한다. 206 | 207 |
208 | 209 | ### 뷰 단계(View level) 210 | 211 | - 추상화의 최상위 단계 212 | - 전체 데이터베이스의 일부분만을 기술한다. 213 | - 사용자가 시스템을 간단히 이용할 수 있도록 정의한다. 214 | - 사용자는 데이터베이스에 저장된 데이터에 대해서 극히 일부분만 관심이 있다. 215 | - 한 데이터베이스에 대해서 수많은 뷰가 존재할 수 있다. 216 | 217 |
218 |
219 | 220 | ## 1.3.4 인스턴스와 스키마 221 | 222 | ### 인스턴스 223 | 224 | 어느 특정한 순간에 데이터베이스에 저장되어 있는 정보의 모임을 데이터베이스의 `인스턴스(instance)`라 한다. 225 | 226 |
227 | 228 | ### 스키마 229 | 230 | 데이터베이스의 전체적인 설계를 이야기할 때는 데이터베이스 `스키마(shema)`라 한다. 231 | 232 |
233 | 234 | 데이터베이스 시스템에서는 추상화의 단계에 따라 여러 개의 스키마가 존재한다. 235 | 236 | - `물리적 스키마(physical schema)` : 물리적 단계에서 데이터베이스 설계를 기술한다. 237 | - `논리적 스키마(logical schema)` : 논리적 단계에서 데이터베이스 설계를 기술한다. 238 | - `서브 스키마(subschema)` : 데이터베이스는 여러 가지 서로 다른 뷰를 기술하는 뷰 단계의 스키마를 여러 개 가질 수 있다. 239 | 240 |
241 | 242 | 응용 프로그램에 가장 큰 영향을 미치는 것은 논리적 스키마이다. 243 | 244 | 대부분의 응용 프로그램이 논리적 스키마에 기반하여 작성되기 때문이다. 245 | 246 |
247 | 248 | ### 물리적 데이터 독립성(physical data independence) 249 | 250 | 물리적 스키마는 논리적 스키마 아래에 감추어져 있으나, 대개 상위의 응용 프로그램에 영향을 주지 않고서도 이를 쉽게 변경할 수 있다. 251 | 252 | 즉, **응용 프로그램이 물리적 스키마에 의존하지 않아서** 물리적 스키마가 변경되어도 고칠 필요가 없다. 253 | 254 |
255 |
256 |
257 | 258 | # 1.4 데이터베이스 언어 259 | 260 | 데이터베이스 시스템은 데이터베이스 스키마를 기술하는 `데이터 정의 언어(data definition language, DDL)`와 데이터베이스 질의 및 갱신을 261 | 표현하는 `데이터 조작 언어(data manipulation language, DML)`를 제공한다. 262 | 263 |
264 | 265 | ## 1.4.1 데이터 정의 언어 266 | 267 | `데이터 정의 언어(DDL)`**라는 특수한 언어로 표현된 정의들의 집합**을 이용해 데이터베이스 스키마를 구체화한다. 268 | 269 | DDL은 데이터의 추가적인 특성을 표현하는 데에도 사용된다. 270 | 271 |
272 | 273 | 데이터베이스에 저장된 데이터는 해당 데이터베이스가 요구하는 일관성 제약 조건을 만족해야 한다. 274 | 275 | 데이터베이스 시스템은 데이터베이스가 갱신될 때마다 이러한 제약 조건을 검토하는데, 이런 `술어(predicate)`를 검증하는데에는 처리 비용이 많이 든다. 276 | 277 |
278 | 279 | 따라서 데이터베이스 시스템은 최소한의 비용으로 검증될 수 있는 `무결성 제약 조건`을 이행한다. 280 | 281 |
282 | 283 | ### 도메인 제약 조건(Domain Constraints) 284 | 285 | - 모든 속성은 가능한 값의 도메인(e.g., 정수형, 문자형, 날짜/시간형)이 지정되어 있어야 한다. 286 | - 속성을 선언하는 데 각각의 도메인은 값에 대한 제약 조건으로 작용한다. 287 | 288 |
289 | 290 | ### 참조 무결성(Referential Integrity) 291 | 292 | - 어떤 속성들의 집합에 대해 **릴레이션의 한 값이 다른 릴레이션의 해당 속성 집합의 값으로 반드시 나타나야 하는** 경우가 있다. (`참조 무결성`) 293 | - 예를 들어, 각 수업에 **열거된** 학과가 실제로 존재해야 하는 상황이다. 294 | - 데이터베이스의 수정이 참조 무결성을 위반할 수 있는데, 이 경우 기본적인 절차는 **위반을 유발한 동작을 거부**하는 것이다. 295 | 296 |
297 | 298 | ### 권한(Authorization) 299 | 300 | `권한(authorization)`은 데이터베이스의 다양한 데이터에 대해서 사용자마다 접근을 다르게 하고 싶을 때의 차별을 말한다. 301 | 302 |
303 | 304 | 아래처럼 여러 유형의 권한들이 존재하는데, 305 | 이들은 사용자에게 전부 허가하거나, 혹은 전혀 할당하지 않거나, 조합해서 일부만 할당할 수도 있다. 306 | 307 |
308 | 309 | > ✅ 읽기 권한(read authorization) 310 | 311 | - 데이터의 읽기를 허용한다. 312 | - 데이터의 수정(쓰기)를 허용하지 않는다. 313 | 314 |
315 | 316 | > ✅ 삽입 권한(insert authorization) 317 | 318 | - 새로운 데이터의 삽입을 허용한다. 319 | - 존재하는 데이터의 수정은 허용하지 않는다. 320 | 321 |
322 | 323 | > ✅ 갱신 권한(update authorization) 324 | 325 | - 데이터의 수정은 허용한다. 326 | - 데이터의 삭제는 허용하지 않는다. 327 | 328 |
329 | 330 | > ✅ 삭제 권한(delete authorization) 331 | 332 | - 데이터의 삭제를 허용한다. 333 | 334 |
335 |
336 | 337 | DDL은 명령문(statements)을 입력으로 받아 결과를 생성한다. 338 | 339 | DDL의 결과는 `메타데이터(metadata, 데이터에 대한 데이터)`를 수록하는 `데이터 사전(data dictionary)`에 저장된다. 340 | 341 | - 데이터 사전은 특별한 형태의 테이블로서 **오직 데이터베이스 시스템에 의해서만 접근되고 갱신될 수 있다.** 342 | - 데이터베이스 시스템이 실제 데이터를 읽거나 갱신할 때에는 데이터 사전을 참조하여 작업을 수행한다. 343 | 344 |
345 |
346 | 347 | ## 1.4.2 SQL 데이터 정의 언어 348 | 349 | `SQL`은 데이터 타입과 무결성 제약 조건을 갖는 테이블을 정의할 수 있도록 풍부한 DDL을 제공한다. 350 | 351 | SQL DDL은 다수의 무결성 제약 조건을 제공한다. (3장, 4장에서 설명) 352 | 353 | e.g., department 테이블을 정의하는 SQL DDL 구문 354 | 355 | ```sql 356 | create table department 357 | ( 358 | department char(20), 359 | building char(15), 360 | budget numeric(12, 2) 361 | ); 362 | ``` 363 | 364 |
365 |
366 | 367 | ## 1.4.3 데이터 조작 언어 368 | 369 | `데이터 조작 언어(DML)`는 사용자가 적절한 데이터 모델로 구성된 데이터에 접근하거나 이것을 조작할 수 있도록 하는 언어다. 370 | 371 |
372 | 373 | ### 접근의 형태 374 | 375 | - 데이터베이스 내에 저장된 정보를 **검색(read)** 376 | - 데이터베이스에 새로운 정보를 **삽입(create)** 377 | - 데이터베이스로부터 정보를 **삭제(delete)** 378 | - 데이터베이스 내에 저장된 데이터를 **수정(update)** 379 | 380 |
381 | 382 | ### DML의 두 가지 형태 383 | 384 | #### 절차적 DML(procedural DML) 385 | 386 | 어떤 데이터가 필요하며 그 데이터를 어떻게 구할지 지정할 것을 요구한다. 387 | 388 | #### 선언적 DML(declartive DML 또는 비절차적 DML(nonprocedural DML)) 389 | 390 | 필요한 데이터를 어떻게 구할지 명시할 필요 없이, 어떠한 데이터가 필요한지 지정할 것만 사용자에게 요구한다. 391 | 392 |
393 | 394 | ### 질의 395 | 396 | `질의(query)`는 **정보 검색을 요청하는 구문**이다. 397 | 398 | 데이터 조작 언어에서 정보 검색을 담당하는 부분을 `질의어(query language)`라고 한다. 399 | 400 |
401 |
402 | 403 | ## 1.4.4 SQL 데이터 조작 언어 404 | 405 | SQL 질의어는 `비절차적 언어`다. 406 | 407 | **입력으로 한 개 이상의 테이블을 받아 항상 한 개의 테이블을 반환한다.** 408 | 409 | e.g., 역사학과의 모든 교수의 이름을 찾는 SQL 질의어 410 | 411 | ```sql 412 | select instructor.name 413 | from instructor 414 | where instructor.dept_name = 'History'; 415 | ``` 416 | 417 |
418 | 419 | 질의는 하나 이상의 테이블에 있는 정보를 포함할 수도 있다. 420 | 421 | e.g., 예산이 $95,000보다 많은 학과의 모든 교수의 ID와 학과 이름을 찾아주는 SQL 질의어 422 | 423 | ```sql 424 | select instructor.ID, department.dept_name 425 | from instructor, 426 | department 427 | where instructor.dept_name = department.dept_name 428 | and department.budget > 95000; 429 | ``` 430 | 431 |
432 |
433 |
434 | 435 | # 1.5 데이터베이스 설계 436 | 437 | 1. 데이터베이스 설계의 초기 단계는 장래의 데이터베이스 사용자들이 **필요로 하는 데이터를 충분히 규정하는 것**이다. 438 | - 이 단계의 결과물은 사용자의 `요구 명세서(specification of user requirements)`이다. 439 | 440 | 441 | 2. `개념적 설계(conceptual-design) 단계` 442 | - 설계자는 데이터 모델을 선택한다. 443 | - 선택한 데이터 모델의 개념을 적용함으로써 사용자 요구를 데이터베이스의 개념적인 스키마로 바꾼다. 444 | - 설계자의 초점은 물리적으로 어떻게 저장할 것인지 자세히 규정하는 것보다는 **데이터와 그들의 관계**를 기술하는 데 맞추어져 있다. 445 | - 데이터베이스에서 우리가 포착하길 원하는 **어떤 속성**과, 다양한 테이블을 구성하는 이러한 속성을 **어떻게 그룹화**할 것인가에 대한 결정과 관련된다. 446 | - `개체-관계 모델`의 사용 447 | - 모든 속성의 집합을 입력으로 받아 테이블의 집합을 생성하는 `정규화(normalization)`로 알려진 알고리즘의 사용 448 | 449 | 450 | 3. 사용자는 `기능적 요구 사항 명세서(specification of functional requirement)`에 데이터에 적용될 연산(혹은 트랜잭션)의 종류를 기술한다. 451 | - 연산의 예시 : 데이터의 변경 혹은 갱신, 특정 데이터의 검색 및 추출, 데이터의 삭제 452 | - 개념적 설계의 이 단계에서 설계자는 스키마가 기능적인 요구 사항을 잘 만족하는지 검토할 수 있다. 453 | 454 |
455 | 456 | > **추상 데이터 모델로부터 데이터베이스 구현으로 이동하는 과정**은 마지막 두 설계 단계에서 이루어진다. 457 | 458 | 4. 논리 설계 단계(logical-design phase) 459 | - 설계자는 상위의 개념적 스키마를 사용할 데이터베이스의 구현 데이터 모델에 대응시킨다. 460 | 461 | 462 | 5. 물리 설계 단계(physical-design phase) 463 | - 데이터베이스의 물리적 속성이 구체화된다. 464 | - 이러한 속성은 파일 구성(file organization)의 형식과 내부적인 저장 구조를 포함한다. 465 | 466 |
467 |
468 |
469 | 470 | # 1.6 데이터베이스 엔진 471 | 472 | 데이터베이스 시스템은 여러 모듈로 구성되며, 각 모듈은 데이터베이스의 여러 책무를 나누어 맡는다. 473 | 474 | 1. `저장 장치 관리자(storage manager)` 475 | 2. `질의 처리기(query processor)` 476 | 477 |
478 | 479 | ## 1.6.1 저장 장치 관리자 480 | 481 | - 데이터베이스 하부에 저장된 **데이터와 응용 프로그램 및 질의 사이의 인터페이스를 제공**하는 데이터베이스 시스템 요소다. 482 | - 파일 관리자(file manager)와 상호작용하는 책무가 있다. 483 | - 저장 장치 관리자는 다양한 DML 구문을 하위 단계의 파일 시스템 명령으로 변환한다. 484 | - 그러므로 이는 **데이터베이스 내의 데이터를 저장하고 검색하며, 갱신하는 책임이 있다.** 485 | 486 |
487 | 488 | ### 구성요소 489 | 490 | - `권한과 무결성 관리자` 491 | - `트랜잭션 관리자` 492 | - `파일 관리자` 493 | - `버퍼 관리자` 494 | 495 |
496 | 497 | ### 구현하는 데이터 구조 498 | 499 | - `데이터 파일` : 데이터베이스 자체를 저장한다. 500 | - `데이터 사전` 501 | - 데이터베이스의 구조에 관한 메타데이터를 저장한다. 502 | - 특히 데이터베이스의 스키마를 여기에 저장한다. 503 | - `인덱스` : 특정한 값을 가지고 있는 데이터 항목에 빠르게 접근하기 위한 것이다. 504 | 505 |
506 |
507 | 508 | ## 1.6.2 질의 처리기 509 | 510 | ### 구성요소 511 | 512 | - `DDL 인터프리터` : DDL 문을 해독하여 데이터 사전 내에 기록한다. 513 | - `DML 컴파일러` 514 | - 질의어 내의 DML 문을 질의 평가 엔진이 이해할 수 있는 하위 단계 명령어로 구성된 `질의 평가 계획`으로 바꾼다. 515 | - DML 컴파일러의 책무 중 하나는 `질의 최적화(query optimization)`이다. 516 | - 여러 질의 평가 계획 중 **가장 낮은 비용의 계획을 선택**하는 것이다. 517 | - `질의 평가 엔진` : DML 컴파일러가 생성한 하위 단계 명령을 실행한다. 518 | 519 |
520 |
521 | 522 | ## 1.6.3 트랜잭션 관리 523 | 524 | 보통 데이터베이스에 대한 몇 개의 연산이 하나의 논리적 작업 단위를 이룬다. 525 | 526 | 예금 이체를 생각해보자. A는 출금 계좌이고, B는 입금 계좌다. 527 | 528 |
529 | 530 | ### 원자성 531 | 532 | 분명히, 입금과 출금이 **모두 일어나든지, 모두 일어나지 않든지** 하는 것이 필수적이다. 533 | 534 | 즉, 예금 이체는 전체가 완전히 수행되거나, 전혀 수행되지 않아야 한다. 535 | 536 | 이러한 **all or none 요구 조건**을 `원자성(atomicity)`이라고 한다. 537 | 538 |
539 | 540 | ### 일관성 541 | 542 | 또한 예금 이체의 실행은 데이터베이스의 **일관성을 보존해야 한다.** 543 | 544 | 즉, A의 잔고와 B의 잔고를 합한 값이 보존되어야 한다. 545 | 546 | 이러한 정확성에 관한 요구 조건을 `일관성(consistency)`이라고 한다. 547 | 548 |
549 | 550 | ### 지속성 551 | 552 | 시스템 고장의 가능성에도 불구하고 마침내 예금 이체가 성공적으로 끝난 뒤 A의 잔고와 B의 잔고의 새로운 값이 유지되어야 하는데, 이러한 **영속성의 요구 조건**을 `지속성(durability)`이라고 한다. 553 | 554 |
555 | 556 | ### 트랜잭션(transaction) 557 | 558 | 이는 데이터베이스 응용 프로그램에서 **하나의 논리적 기능을 수행하는 연산의 모임이다.** 559 | 560 |
561 | 562 | 각 트랜잭션은 원자성과 일관성을 모두 지닌 단위로 수행되어야 한다. 563 | 564 | 그러므로 **트랜잭션은 어떤 데이터베이스 일관성 제약 조건도 위반해서는 안 된다.** 565 | 566 | 즉, 트랜잭션이 시작될 때 데이터베이스가 일관성 있는 상태였다면, 트랜잭션이 성공적으로 종료되었을 때에도 일관성 있는 상태여야 한다. 567 | 568 |
569 | 570 | 각각의 트랜잭션이 데이터베이스의 일관성을 유지하도록 여러 트랜잭션을 적절하게 정의하는것은 프로그래머의 책임이다. 571 | 572 |
573 | 574 | ### 트랜잭션 관리자 575 | 576 | `트랜잭션 관리자(transaction manager)`는 복구 관리자와 동시성 제어 관리자로 구성된다. 577 | 578 | - 원자성과 지속성을 보장하는 것은 데이터베이스 시스템, 특히 `복구 관리자(recovery manager)`의 책임이다. 579 | - 원자성의 특성을 보장하려면 **실패한 트랜잭션이 데이터베이스의 상태에 아무런 영향을 주지 말아야 한다.** 580 | - 즉, 데이터베이스는 실패한 트랜잭션이 일어나기 전 상태로 재저장되어야 한다. 581 | - 그러므로 데이터베이스는 `고장 복구(failure recovery)`를 수행해야만 한다. 582 | - 데이터베이스의 일관성을 보장하기 위해 동시에 실행되는 트랜잭션들 간의 상호작용을 제어하는 것은 583 | `동시성 제어 관리자(concurrency-control manager)`의 책임이다. 584 | 585 |
586 |
587 |
588 | 589 | # 1.7 데이터베이스 및 응용 구조 590 | 591 |
592 | 593 |

시스템 구조 594 | 595 |
596 |
597 |
598 | 599 | ## 계층 구조 600 | 601 | 백엔드(back-end)로 데이터베이스를 사용하는 응용의 구조는 다음과 같이 두 부분 또는 세 부분으로 나뉜다. 602 | 603 |
604 | 605 |

계층 구조 606 | 607 |
608 |
609 | 610 | ### 2계층 구조 611 | 612 | 초기 데이터베이스 응용은 `2계층 구조(two-tier architecture)`를 이용했다. 613 | 614 | 이 구조에서는 응용 프로그램이 클라이언트 상에 존재하고 특정 질의문을 보냄으로써 서버에 있는 데이터베이서 시스템의 기능을 불러온다. 615 | 616 |
617 | 618 | ### 3계층 구조 619 | 620 | `3계층 구조(three-tier architecture)`에서 클라이언트는 어떤 데이터베이스 호출도 직접적으로 수행하지 않고 단지 전처리 시스템으로서의 역할만 한다. 621 | 622 | - 프런트엔드(혹은 클라이언트)는 `응용 서버(application server)`와 통신을 한다. 623 | - 응용 서버는 차례로 데이터에 접근하기 위해 데이터베이스 시스템과 통신한다. 624 | 625 |
626 | 627 | 어떤 작업(action)이 어떠한 조건하에서 수행되는지를 의미하는 `비즈니스 로직(business logic)`은 **응용 서버 쪽에 포함되어 있다.** 628 | 629 | 이는 2계층 응용보다 더 좋은 성능뿐만 아니라 더 나은 보안을 제공한다. 630 | 631 |
632 |
633 |
634 | 635 | # 1.8 데이터베이스 사용자와 관리자 636 | 637 | ## 1.8.2 데이터베이스 관리자 638 | 639 | `DBMS`를 도입하는 중요한 이유 중의 하나는 **데이터와 데이터에 접근하는 프로그램 모두에 대해서 중앙 제어를 가하자**는 것이다. 640 | 641 |
642 | 643 | 중앙에서 제어하는 사람을 `데이터베이스 관리자(database administrator, DBA)`라고 한다. 644 | 645 | 데이터베이스 관리자는 다음과 같은 일을 한다. 646 | 647 | - 스키마 정의 648 | - 저장 구조와 접근 방법 정의 649 | - 스키마 및 물리 구조 수정 650 | - 데이터 접근 권한 인정 651 | - 일상적인 유지 보수 652 | -------------------------------------------------------------------------------- /Part_01/Chapter_02/2.1 관계형 데이터베이스의 구조/README.md: -------------------------------------------------------------------------------- 1 | # 2.1 관계형 데이터베이스의 구조 2 | 3 |
4 | 5 | # 테이블 6 | 7 | `관계형 데이터베이스`는 `테이블(table)`의 모임으로 구성되며, 각 테이블은 고유한 이름을 가지고 있다. 8 | 9 |
10 | 11 | e.g., insructor 테이블 12 | 13 |

instructor 14 | 15 |
16 |
17 | 18 | - 네 개의 `열(column)` : ID, name, dept_name, salary 19 | 20 | 21 | - 테이블의 각 `행(row)`은 **교수의 ID, name, dept_name, salary로 구성된** 한 명의 교수에 관한 정보를 저장하고 있다. 22 | 23 | 24 | - 교수 개개인은 ID 값에 의해서 구별된다. 25 | - 즉, 특정 ID와 나머지 name, dept_name, salary 값이 **서로 연관되어 있다**고 생각할 수 있다. 26 | 27 |
28 |
29 |
30 | 31 | # 용어 32 | 33 | ## 릴레이션(relation) 34 | 35 | 일반적으로 테이블의 각 행은 일련의 값 사이의 `관계(relationship)`를 표현한다. 36 | 37 |
38 | 39 | 테이블이란 이러한 관계들의 모임이므로, 테이블의 개념은 `릴레이션(relation)`이라는 수학적인 개념과 밀접한 관련이 있다. 40 | 41 |
42 |
43 | 44 | ## 튜플(tuple) 45 | 46 | 테이블의 행을 의미한다. 47 | 48 |
49 | 50 | 수학적 의미의 튜플은 간단한 값의 나열 혹은 값의 리스트를 의미한다. 51 | 52 | > n개의 값에 관한 관계 = 값의 `n-튜플` 53 | 54 | **즉, n개의 값을 가진 하나의 튜플이 테이블에서 하나의 행이 된다.** 55 | 56 |
57 | 58 | **릴레이션은 튜플들의 집합**이기 때문에 릴레이션에서 튜플이 어떤 순서로 나타나는지는 상관없다. 59 | 60 |
61 |
62 | 63 | ## 속성(attribute) 64 | 65 | 테이블의 열을 의미한다. 66 | 67 |
68 | 69 | ### 도메인(domain) 70 | 71 | 릴레이션의 각 속성은 `도메인(domain)`이라고 하는 **허가된 값의 집합**을 가지고 있다. 72 | 73 | e.g., instructor 릴레이션의 name 속성의 도메인은 가능한 모든 교수의 이름이다. 74 | 75 |
76 | 77 | 모든 릴레이션 r에 대해서 r의 모든 속성의 도메인은 `원자적(atomic)`이어야 한다. 78 | 79 | 즉, 도메인의 요소(element)는 더 이상 나뉠 수 없는 단위라는 것이다. 80 | 81 |
82 | 83 | ### 널 값(null value) 84 | 85 | **알려지지 않거나 존재하지 않는 값**을 의미하는 특별한 값이다. 86 | 87 |
88 | 89 | 릴레이션에 있는 튜플이 어떤 속성을 아예 가지고 있지 않거나, 그것을 데이터베이스에 저장하지 않았을 수 있다. 90 | 91 | 이러한 경우에는 해당 속성에 어떤 값도 넣을 수 없기 때문에 널 값을 사용한다. 92 | 93 |
94 | 95 | > 가능하면 널 값은 제거하는 것이 좋다. 96 | 97 | 데이터베이스의 접근이나 갱신을 하는 데 널 값이 어려움을 가져올 수 있기 때문이다. (뒤에서 자세히 논의) 98 | 99 |
100 |
101 | 102 | ## 릴레이션 인스턴스(relation instance) 103 | 104 | 행의 특정 집합을 포함하고 있는 릴레이션의 특정 인스턴스를 지칭한다. 105 | -------------------------------------------------------------------------------- /Part_01/Chapter_02/2.2 데이터베이스 스키마/README.md: -------------------------------------------------------------------------------- 1 | # 2.2 데이터베이스 스키마 2 | 3 |
4 | 5 | 데이터베이스에 대해서 언급할 때, 아래 두 개념을 잘 구별해야 한다. 6 | 7 | - `데이터베이스 스키마(database schema)` : 데이터베이스의 논리적 설계 8 | 9 | 10 | - `데이터베이스 인스턴스(database instance)` : 어느 한순간에 데이터베이스에 저장되어 있는 데이터의 스냅샷(snapshot) 11 | 12 |
13 | 14 | ## 릴레이션 스키마(relation schema) 15 | 16 | 이는 속성과 그 속성이 가지는 도메인의 명세로 구성된다. 17 | 18 |
19 | 20 | > 릴레이션의 개념 ≈ 프로그래밍 언어에서 변수의 개념 21 | 22 | > 릴레이션 스키마의 개념 ≈ 프로그래밍 언어의 타입 정의(type definition) 23 | 24 |
25 | 26 | ## 릴레이션 인스턴스(relation instance) 27 | 28 | > 릴레이션 인스턴스의 개념 ≈ 프로그래밍 언어에서 변수의 값 29 | 30 |
31 | 32 | 릴레이션 인스턴스의 튜플도 릴레이션이 변경됨에 따라 변하게 된다. 33 | 34 | **하지만 일반적으로 릴레이션의 스키마는 변하지 않는다.** 35 | 36 |
37 |
38 | 39 | ## e.g., 40 | 41 | ### instructor 릴레이션 42 | 43 |

instructor 44 | 45 |
46 |
47 | 48 | ### department 릴레이션 49 | 50 |

department 51 | 52 |
53 |
54 | 55 | department 릴레이션의 스키마는 다음과 같다. 56 | 57 | ``` 58 | department(dept_name, building, budget) 59 | ``` 60 | 61 |
62 |
63 | 64 | `dept_name` 속성은 위 두 스키마에 모두 나타나는 것을 볼 수 있다. 65 | 66 | 릴레이션 스키마에서 공통적인 속성을 사용하는 것은, **서로 다른 릴레이션에 있는 튜플을 연관시키는 방법** 중 하나다. 67 | 68 | -------------------------------------------------------------------------------- /Part_01/Chapter_02/2.3 키/README.md: -------------------------------------------------------------------------------- 1 | # 2.3 키 2 | 3 |
4 | 5 | 1️⃣ 주어진 릴레이션 안에서 튜플을 구별하는 방법이 있어야 한다. 6 | 7 | 2️⃣ 이것은 릴레이션의 속성으로 표현되어야 한다. 8 | 9 | 즉, 튜플의 속성값은 그 튜플을 **유일하게 식별**할 수 있어야 한다. 10 | 11 |
12 | 13 | # 키(key) 14 | 15 |
16 | 17 |

keys 18 | 19 |
20 |
21 | 22 | ## 슈퍼 키(super key) 23 | 24 | `슈퍼 키`는 한 릴레이션에서 그 튜플을 유일하게 식별할 수 있도록 해주는 **하나 혹은 그 이상의 속성들의 집합**이다. 25 | 26 |
27 | 28 | e.g., instructor 릴레이션 29 | 30 | - `ID 속성`은 하나의 instructor 튜플을 다른 튜플로부터 구별하는 데 충분하다. 31 | - `name 속성`은 같은 이름을 가진 교수가 있을 수 있기 때문에 슈퍼 키가 아니다. 32 | 33 |
34 | 35 | 릴레이션 r의 스키마에 존재하는 속성들의 집합을 R라고 하자. K는 R의 부분집합이다. (K ⊆ R) 36 | 37 | K가 r의 슈퍼 키가 되기 위해서는, **서로 다른 두 튜플의 K의 모든 속성이 같아서는 안 된다.** 38 | 39 | (튜플 t1과 t2가 r에 존재하고 t1 ≠ t2라면, t1.K ≠ t2.K여야 함) 40 | 41 |
42 | 43 | 슈퍼 키는 관련 없는 속성을 포함할 수 있다. 44 | 45 | instructor 릴레이션에서 `{ ID }`, `{ ID, name }` 전부 슈퍼 키이다. 46 | 47 | **즉, 해당 정보를 갖고 특정인을 구별할 수 있다면 모두 슈퍼 키이다.** 48 | 49 |
50 |
51 | 52 | ## 후보 키(candidate key) 53 | 54 | 슈퍼 키들 중 **최소한의 정보만을 갖고 있는 것**을 `후보 키`라 한다. 55 | 56 | 다른 여러 속성들의 집합이 하나의 후보 키 역할을 할 수도 있다. 57 | 58 |
59 | 60 | instructor 릴레이션에서의 후보 키는 `{ ID }`이다. 61 | 62 |
63 |
64 | 65 | ## 주 키(primary key) 66 | 67 | 릴레이션 안에서 튜플을 구별하기 위한 수단으로 **데이터베이스 설계자에 의해 선택된 후보 키**는 `주 키`라고 지칭한다. 68 | 69 |
70 | 71 | > ✅ 주 키, 후보 키, 수퍼 키는 각 튜플의 특성이 아니라 전체 릴레이션의 특성이다. 72 | 73 | 릴레이션의 어떠한 튜플도 동시에 키 속성에 대해 같은 값을 가질 수 없다. 74 | 75 | 따라서 주 키는 `주 키 제약 조건(primary key constraint)`을 갖는다. 76 | 77 |
78 | 79 | > ✅ 주 키는 신중하게 선택해야 한다. 80 | 81 | 한 사람의 주민등록 번호를 속성으로 사용한다면 이것은 후보 키가 될 수 있다. 82 | 83 | 그러나 외국인에게는 주민등록번호가 주어지지 않으므로, 내국인과 외국인을 동시에 고용하는 기관은 자체적인 식별 방법이 필요할 것이다. 84 | 85 | **키를 정하는 방법으로 여러 개의 속성을 동시에 이용하는 방법도 있다.** 86 | 87 |
88 | 89 | > ✅ 주 키는 그 속성이 절대로 변하지 않거나 매우 드물게 변하도록 선택해야 한다. 90 | 91 |
92 |
93 | 94 | ## 외래 키(foreign key) 95 | 96 | instructor 릴레이션의 `dept_name` 속성을 생각해보자. 97 | 98 | instructor 릴레이션에 나오는 어떤 튜플의 dept_name이 department 릴레이션에 나오지 않는다면 매우 이상할 것이다. 99 | 100 |
101 | 102 | instructor 릴레이션의 어떤 튜플 ta가 있다면, ta의 dept_name 속성값이 반드시 department 릴레이션에 존재해야 한다. 103 | 104 | 즉, ta의 dept_name 속성값이 dept_name을 주 키로 가지는 **department 릴레이션의 어떤 튜플 tb의 주 키로 나와야 한다**는 것이다. 105 | 106 |
107 | 108 | ### 외래 키 제약 조건(foreign-key constraint) 109 | 110 | 릴레이션 스키마 r1의 속성 A와 다른 릴레이션 스키마 r2의 주 키 B 사이의 `외래 키 제약 조건`은 111 | 모든 데이터베이스 인스턴스에 대해서 `r1에 존재하는 각 튜플의 A 값이 r2에 있는 어떤 튜플의 B 값으로 반드시 나와야 한다`는 것을 의미한다. 112 | 113 |
114 | 115 | - **속성 집합 A**를 r1으로부터 r2를 참조하는 `외래 키(foreign key)`라고 한다. 116 | - 릴레이션 r1은 외래 종속을 가진 `참조하는 릴레이션(referencing relation)`이라고 부른다. 117 | - 릴레이션 r2는 `참조된 릴레이션(referenced relation)`이라고 한다. 118 | 119 |
120 | 121 | 즉, instructor의 속성 `dept_name`은 **instructor에서 department를 참조하는 외래 키다.** 122 | 123 | `dept_name은` **department의 주 키다.** 124 | 125 |
126 | 127 | ### 참조 무결성 제약 조건(referential integrity constraint) 128 | 129 | 참조하는 릴레이션의 어떤 튜플의 특정 속성에 출현하는 값이 **참조되는 릴레이션에서 적어도 하나의 튜플의 특정 속성으로 출현해야 한다.** 130 | 131 |
132 | 133 | 외래키 제약 조건은 참조되는 속성이 참조된 릴레이션의 주 키를 구성하기 때문에 참조 무결성 제약 조건의 특별한 경우라고 볼 수 있다. 134 | 135 | 오늘날 데이터베이스 시스템은 외래 키 제약 조건을 지원하나, **참조되는 속성이 주 키가 아닌 참조 무결성 제약 조건은 지원하지 않는다.** 136 | -------------------------------------------------------------------------------- /Part_01/Chapter_02/2.4 스키마 다이어그램/README.md: -------------------------------------------------------------------------------- 1 | # 2.4 스키마 다이어그램 2 | 3 |
4 | 5 | 데이터베이스 스키마는 **주 키와 외래 키 종속성**을 가지고 있는데, 이는 `스키마 다이이어그램(schema diagram)`을 이용해 시각적으로 나타낼 수 있다. 6 | 7 |
8 | 9 | ### 대학교 데이터베이스의 스키마 10 | 11 |

대학교 데이터베이스의 스키마 12 | 13 |
14 |
15 | 16 | ### 대학교 데이터베이스의 스키마 다이어그램 17 | 18 |

대학교 데이터베이스의 스키마 다이어그램 19 | 20 |
21 |
22 | 23 | - `주 키`로 쓰이는 속성은 밑줄을 그어서 표현한다. 24 | 25 | 26 | - `외래 키 종속성`은 참조하는 릴레이션의 외래 키 속성으로부터 참조된 릴레이션의 주 키로 이르는 화살표로 나타낸다. 27 | 28 | 29 | - 외래 키 제약 조건이 아닌 `참조 무결성 제약 조건`을 표시하기 위해 이중 화살표를 사용했다. 30 | -------------------------------------------------------------------------------- /Part_01/Chapter_02/2.5 관계형 질의어/README.md: -------------------------------------------------------------------------------- 1 | # 2.5 관계형 질의어 2 | 3 |
4 | 5 | # 질의어(query language) 6 | 7 | 질의어는 사용자가 데이터베이스로부터 정보를 요청할 때 사용하는 언어다. 8 | 9 | 이들은 대체로 표준 프로그래밍 언어보다 고급 단계의 언어다. 10 | 11 |
12 | 13 | - 명령형 언어 14 | - 함수형 언어 15 | - 선언형 언어 16 | 17 |
18 |
19 | 20 | ## 명령형 질의어(imperative query language) 21 | 22 | `명령형 질의어`에서 사용자는 원하는 결과를 계산하기 위해 데이터베이스에 특별한 일련의 연산을 수행하도록 명령한다. 23 | 24 | 이러한 언어는 일반적으로 계산 과정에서 갱신되는 상태 변수(state variable)를 갖는다. 25 | 26 |
27 |
28 | 29 | ## 함수형 질의어(functional query language) 30 | 31 | `함수형 질의어`에서 계산은 데이터베이스에 있는 데이터나 다른 함수의 결과에 대해서 동작하는 함수의 실행으로 표현된다. 32 | 33 | 함수는 부작용(side-effect)이 없고 프로그램 상태를 갱신하지 않는다. 34 | 35 |
36 |
37 | 38 | ## 선언형 질의어(declarative query language) 39 | 40 | `선언형 질의어`에서 사용자는 원하는 정보만 기술하며 이 정보를 얻기 위한 구체적인 단계나 함수 호출을 기술하지 않는다. 41 | 42 | 원하는 정보는 전형적으로 수학적 논리의 형태로 기술되며, 원하는 정보를 어떻게 획득할지는 데이터베이스 시스템의 일이다. 43 | 44 |
45 |
46 | 47 | 다음 2.6절에서 살펴볼 `관계 대수`는 **함수형 언어**다. 48 | 49 | 관계 대수는 SQL 질의어의 이론적 토대를 구성한다. 50 | 51 | 27장에서 살펴볼 튜플 관계 해석과 도메인 관계 해석은 **선언형 언어**다. 52 | -------------------------------------------------------------------------------- /Part_01/Chapter_03/3.1 SQL 질의어의 개요/README.md: -------------------------------------------------------------------------------- 1 | # 3.1 SQL 질의어의 개요 2 | 3 |
4 | 5 | IBM은 1970년대 초반 System R 프로젝트의 일부분으로 초기에 Sequel이라고 불리는 SQL의 초기 버전을 개발했고, 6 | 그 후 Sequel 언어는 계속 발전되다가 `SQL(Structured Query Language)`로 그 이름을 바꾸었다. 7 | 8 |
9 |
10 | 11 | ## SQL 언어의 구성 12 | 13 | ### 데이터 정의 언어(Data-definition language, DDL) 14 | 15 | SQL DDL은 릴레이션 스키마를 정의하고, 릴레이션을 삭제하고, 릴레이션 스키마를 수정하는 명령어를 제공한다. 16 | 17 |
18 | 19 | ### 데이터 조작 언어(Data-manipulation language, DML) 20 | 21 | SQL DML은 정보를 찾기 위해 데이터베이스에 질의하고, 튜플을 삽입・삭제・수정하는 기능을 제공한다. 22 | 23 |
24 | 25 | ### 무결성(Integrity) 26 | 27 | SQL DDL은 데이터베이스에 저장될 데이터가 반드시 만족해야 하는 `무결성 제약 조건`을 명시하는 명령어를 포함한다. 28 | 29 | DBMS는 무결성 제약 조건을 위반하는 갱신을 허용하지 않는다. 30 | 31 |
32 | 33 | ### 뷰 정의(View definition) 34 | 35 | SQL DDL은 뷰를 정의할 수 있는 명령어를 포함한다. 36 | 37 |
38 | 39 | ### 트랜잭션 제어(Transaction control) 40 | 41 | SQL은 트랜잭션의 시작과 끝을 명시하는 명령어를 포함한다. 42 | 43 |
44 | 45 | ### 내장 SQL(Embedded SQL)과 동적 SQL(Dynamic SQL) 46 | 47 | 내장 SQL과 동적 SQL은 C, C++, Java와 같은 범용 프로그래밍 언어에 내장되어 사용될 수 있다. 48 | 49 |
50 | 51 | ### 권한 부여(Authorization) 52 | 53 | SQL DDL은 릴레이션과 뷰에 접근할 권한을 부여하는 명령어를 포함한다. 54 | 55 |
56 |
57 | 58 | ## DBMS 59 | 60 | DBMS는 이번 장에서 설명하는 대부분의 SQL 표준 특성을 지원한다. 61 | 62 |
63 | 64 | > SQL을 특정 DBMS가 이해할 수 있도록 표현하는 것은 DBMS별로 차이가 있다. 65 | 66 | 대부분의 DBMS는 일부 SQL 표준이 아닌 특성을 지원하는 반면, 여러 고급 혹은 최신 특성은 지원하지 않기도 한다. 67 | -------------------------------------------------------------------------------- /Part_01/Chapter_03/3.2 SQL 데이터 정의/README.md: -------------------------------------------------------------------------------- 1 | # 3.2 SQL 데이터 정의 2 | 3 |
4 | 5 | `데이터 정의 언어(DDL)`을 이용하면 **데이터베이스의 릴레이션을 정의**할 수 있으며, 다음과 같은 각 릴레이션에 관한 정보도 명세할 수 있게 해준다. 6 | 7 | - 각 릴레이션의 스키마 8 | - 각 속성값의 타입 9 | - 무결성 제약 조건 10 | - 각 릴레이션을 위해 만들어진 인덱스의 집합 11 | - 각 릴레이션에 대한 보안 및 권한 부여 정보 12 | - 디스크에 저장된 릴레이션의 물리적 저장 구조 13 | 14 |
15 |
16 |
17 | 18 | # 3.2.1 기본 타입 19 | 20 | SQL 표준은 다음의 다양한 내장 타입을 지원한다. 21 | 22 |
23 | 24 | ### char(n) 25 | 26 | - 사용자가 지정한 길이 n을 갖는 **고정 길이 문자** 27 | - e.g., char(10) 타입의 속성에 “Avi”라는 문자열을 저장하면, **10문자 길이를 맞추기 위해 일곱 개의 공백이 추가된다.** 28 | - char 타입의 두 값을 비교할 때 두 값의 길이가 다르면, 비교하기 전에 길이가 짧은 값에 공백을 자동으로 더해 두 값이 같은 크기가 되도록 만든다. 29 | - char 대신 `character`가 사용될 수도 있다. 30 | 31 |
32 | 33 | ### varchar(n) 34 | 35 | - 사용자가 지정한 최대 길이 n을 갖는 **가변 길이 문자** 36 | - e.g., varchar(10) 타입의 속성에 “Avi”라는 문자열을 저장하면, **공백 추가는 생기지 않는다.** 37 | - varchar 대신 `character varying`이 사용될 수도 있다. 38 | 39 |
40 | 41 | ### int 42 | 43 | - **정수**(시스템에 따라 달라질 수 있는 정수의 부분 집합) 44 | - int 대신 `integer`가 사용될 수도 있다. 45 | 46 |
47 | 48 | ### smallint 49 | 50 | - **작은 정수**(시스템에 따라 달라질 수 있는 정수 타입의 부분집합) 51 | 52 |
53 | 54 | ### numeric(p, d) 55 | 56 | - 사용자가 지정한 정밀도(precision)를 갖는 **고정 소수점 수(fixed-point number)** 57 | - 수는 `p`개의 숫자(및 부호)로 구성된다. 58 | - p개의 숫자 중 `d`개는 소수점 이하에 있는 숫자의 개수를 나타낸다. 59 | 60 |
61 | 62 | ### real 63 | 64 | - 시스템에 따라 달라질 수 있는 정밀도를 가지는 **부동 소수점 수** 65 | 66 |
67 | 68 | ### double precision 69 | 70 | - 시스템에 따라 달라질 수 있는 정밀도를 가지는 **배정밀도(double-precision) 부동 소수점 수** 71 | 72 |
73 | 74 | ### float(n) 75 | 76 | - 적어도 n개의 숫자로 나타낼 수 있는 정밀도를 갖는 **부동 소수점 수** 77 | 78 |
79 | 80 | --- 81 | 82 |
83 | 84 | ### null 85 | 86 | 각각의 타입은 특수값인 `널(null)` 값도 포함할 수 있다. 87 | 88 | 널 값은 값이 존재하지만 알 수 없거나, 값이 전혀 존재하지 않는 경우에 **값의 부재**를 나타낸다. 89 | 90 | 어떤 경우에는 널 값 입력 자체가 금지될 수 있다. *(’4.4.2 Not Null 제약 조건’에서 자세히 설명)* 91 | 92 |
93 | 94 | ### char 타입과 varchar 타입의 비교 95 | 96 | `char` 타입과 `varchar` 타입을 비교할 때, 97 | 데이터베이스 세스템에 따라 비교하기 전에 길이가 같도록 varchar 타입에 여분의 공백이 더해질 수도 있고, 안 더해질 수도 있다. 98 | 99 | 따라서 char(10) 타입의 속성과 varchar(10) 타입의 속성에 “Avi”라는 동일한 문자열을 저장한 것의 비교 결과는 거짓(false)이 될 수 있다. 100 | 101 | > 이런 문제를 없애기 위해 **항상 char 타입 대신 varchar 타입을 사용**하는 것을 추천한다. 102 | 103 |
104 | 105 | ### nvarchar 106 | 107 | SQL은 `nvarchar` 타입을 제공해 유니코드(Unicode)를 통해 다국어 데이터를 저장할 수 있다. 108 | 109 | 그럼에도 많은 데이터베이스는 varchar 타입으로도 (**UTF-8 기반**) 유니코드를 저장할 수 있다. 110 | 111 |
112 |
113 |
114 | 115 | # 3.2.2 기본 스키마 정의 116 | 117 | SQL의 `create table` 문(statement)을 사용하여 어떤 릴레이션을 정의할 수 있다. 118 | 119 | ```sql 120 | create table r 121 | ( 122 | A1, D1, 123 | A2, D2, 124 | ..., 125 | An, Dn, 126 | , 127 | .., 128 | 129 | ); 130 | ``` 131 | 132 | - `r` : 릴레이션의 이름 133 | - `Ai` : 릴레이션 r의 스키마 속성의 이름 134 | - `Di` : 속성 Ai의 도메인 135 | - 속성 Ai의 타입을 지정한다. 136 | - 속성 Ai가 특정 도메인에 해당하는 허용된 값만 가지도록 하는 선택적인 제약 조건을 명시한다. 137 | - 세미콜론(`;`) : DBMS에 따라 필요할 수도 있고 필요 없을 수도 있다. 138 | 139 |
140 | 141 | e.g., department 릴레이션의 생성 142 | 143 | ```sql 144 | create table department 145 | ( 146 | dept_name varchar(20), 147 | building varchar(15), 148 | budget numeric(12, 2), # 총 12개의 숫자, 그중 2개는 소수점 이하 숫자 149 | primary key (dept_name) # 주 키 선언 150 | ); 151 | ``` 152 | 153 |
154 |
155 | 156 | ## 무결성 제약 조건 157 | 158 | SQL은 서로 다른 다수의 무결성 제약 조건을 지원한다. 159 | 160 | *(더 자세한 내용은 4.4절에서 다룸)* 161 | 162 |
163 | 164 | ### primary key(Aj1, Aj2, … , Ajm) 165 | 166 | `주 키(primary key) 명세`는 속성 Aj1, Aj2, … , Ajm 등이 **릴레이션의 주 키를 구성한다**는 것을 나타낸다. 167 | 168 | 주 키 명세는 생략될 수 있으나, 일반적으로 각 릴레이션에 대해 주 키를 명시하는 것이 좋다. 169 | 170 |
171 | 172 | > 주 키 속성은 널이 아니거나 유일해야 한다. 173 | 174 | - 어떤 튜플도 주 키 속성에 대해 널 값을 가질 수 없다. 175 | - 어떠한 두 개의 튜플도 모든 주 키 속성에 대해 같은 값을 가질 수 없다. 176 | 177 |
178 | 179 | ### foreign key(Ak1, Ak2, … , Akn) references s 180 | 181 | `외래 키(foreign key) 명세`는 릴레이션의 어떤 튜플에 대한 속성값(Ak1, Ak2, … , Akn)이 182 | 반드시 `(상대) 릴레이션 s`**가 갖고 있는 일부 튜플의 주 키 속성값에 상응해야 한다.** 183 | 184 |
185 | 186 | e.g., 187 | 188 | ```sql 189 | create table department 190 | ( 191 | dept_name varchar(20), 192 | building varchar(15), 193 | budget numeric(12, 2), 194 | primary key (dept_name) 195 | ); 196 | 197 | create table course 198 | ( 199 | course_id varchar(7), 200 | title varchar(50), 201 | dept_name varchar(20), 202 | credits numeric(2, 0), 203 | primary key (course_id), 204 | foreign key (dept_name) references department(dept_name) # 외래 키 선언 205 | ); 206 | ``` 207 | 208 | - 각 course 튜플에 대해, 그 튜플이 지정한 학과 이름은 반드시 department 릴레이션의 주 키 속성인 (dept_name)에 존재해야 한다. 209 | - MySQL을 포함한 일부 데이터베이스 시스템에서는 참조된 테이블의 참조된 속성이 명시적으로 나열되어야 한다. 210 | foreign key (dept_name) references department`(dept_name)` 211 | 212 |
213 | 214 | ### not null 215 | 216 | 속성에 대한 `not null` 제약 조건은 **그 속성에 대한 널 값을 불허한다.** 217 | 218 | 즉, 이 제약 조건은 그 속성의 도메인에서 널 값을 제외한다. 219 | 220 |
221 | 222 | e.g., 223 | 224 | ```sql 225 | create table instructor 226 | ( 227 | ID varchar(5), 228 | name varchar(20) not null, 229 | dept_name varchar(20), 230 | salary numeric(8, 2), 231 | primary key (ID), 232 | foreign key (dept_name) references department (dept_name) 233 | ); 234 | ``` 235 | 236 | instructor 릴레이션의 name 속성에 대한 not null 제약 조건은 교수의 이름이 **널이 될 수 없음을 보장한다.** 237 | 238 |
239 |
240 | 241 | SQL은 무결성 제약 조건을 위반하는 모든 데이터베이스 갱신을 막는다. (SQL이 오류를 표시하고 해당 갱신을 막음) 242 | 243 | - 릴레이션에 새롭게 추가되거나 수정된 튜플이 주 키 속성에 대해 널 값을 가지는 경우 244 | - 튜플이 주 키 속성에 대해 릴레이션 내의 다른 튜플과 같은 값을 가지는 경우 245 | - 외래 키 제약 조건에 위배되는 경우 246 | - e.g., department 릴레이션에 없는 dept_name 값을 갖는 course 튜플의 삽입 247 | 248 |
249 |
250 | 251 | 252 | ## 데이터 조작 명령문 253 | 254 | 새로 생성되는 릴레이션은 초기에는 비어 있다. 255 | 256 | 릴레이션에서 튜플을 삽입, 갱신, 삭제하는 작업은 데이터 조작 명령문인 `insert`, `update`, `delete`에 의해 수행된다. 257 | 258 | *(3.9절에서 다룸)* 259 | 260 |
261 |
262 | 263 | ## 릴레이션의 제거 264 | 265 | 데이터베이스에서 릴레이션을 제거하기 위한 명령문은 `drop table`이다. 266 | 267 | 이는 데이터베이스에서 제거될 릴레이션과 관련된 모든 정보를 삭제한다. 268 | 269 | ```sql 270 | drop table r; # 릴레이션 r의 모든 튜플 뿐만 아니라 r의 스키마까지도 삭제한다. 271 | ``` 272 | 273 | r가 제거되면 create table 문을 통해 r를 다시 생성하지 않는다면 r에 튜플 삽입은 불가능하다. 274 | 275 |
276 | 277 | drop table 명령문은 삭제 명령어 `delete from`보다 더 과감한, 파급력이 큰 명령이라고 할 수 있다. 278 | 279 | ```sql 280 | delete from r; # 릴레이션 r만 남기고 r의 모든 튜플을 제거한다. 281 | ``` 282 | 283 |
284 |
285 | 286 | ## 속성의 추가와 제거 287 | 288 | alter table 문은 이미 존재하는 릴레이션에 속성을 추가할 수 있게 한다. 289 | 290 | **릴레이션의 모든 튜플에 새로운 속성값으로 널이 할당된다.** 291 | 292 | ```sql 293 | alter table r add A D; 294 | ``` 295 | 296 | - `r` : 이미 존재하는 릴레이션의 이름 297 | - `A` : 추가될 속성의 이름 298 | - `D` : 추가될 속성의 도메인 299 | 300 |
301 | 302 | 릴레이션에서 속성을 제거하려면 다음 구문을 사용할 수 있다. 303 | 304 | ```sql 305 | alter table r drop A; 306 | ``` 307 | 308 | - `r` : 이미 존재하는 릴레이션의 이름 309 | - `A` : 릴레이션의 속성 이름 310 | 311 |
312 | 313 | 다수의 데이터베이스 시스템이 어떤 테이블을 통째로 제거하는 것을 허용할 수 있으나, 속성을 제거하는 것은 지원하지 않는 경우가 많다. 314 | -------------------------------------------------------------------------------- /Part_01/Chapter_03/3.3 SQL 질의의 기본 구조/README.md: -------------------------------------------------------------------------------- 1 | # 3.3 SQL 질의의 기본 구조 2 | 3 |
4 | 5 | ## SQL 표현의 기본 구조 6 | 7 | SQL 표현의 기본 구조는 `select`, `from`, `where`의 세 개의 절로 이루어진다. 8 | 9 | - 질의는 `from` 절에 나열된 릴레이션을 입력으로 받는다. 10 | - `where`와 `select` 절에 명시된 대로 수행해 결과로 릴레이션을 산출한다. 11 | 12 |
13 | 14 | > **select** 절 : 질의의 결과에 나타나야 할 속성을 나열하는 데 사용된다. 15 | 16 | > **from** 절 : 질의를 수행하기 위해 접근해야 하는 릴레이션을 나열한다. 17 | 18 | > **where** 절 : from 절에 있는 릴레이션의 속성과 관련된 술어로 구성된다. 19 | 20 |
21 | 22 | ### 일반적인 SQL 질의의 형식 23 | 24 | ```sql 25 | select A1, A2, ... , An 26 | from r1, r2, ... , rm 27 | where P; 28 | ``` 29 | 30 | - `Ai` : 속성 31 | - `ri` : 릴레이션 32 | - `P` : 술어 (where 절이 없다면 술어 P는 true) 33 | 34 |
35 | 36 | > 질의는 반드시 `select, from, where` 절 순서로 작성되어야 하지만, 37 | > **질의가 명시한 연산을 from 절, where 절, select 절 순서대로 이해하면 가장 쉽다.** 38 | 39 |
40 |
41 |
42 | 43 | # 3.3.1 단일 릴레이션에 대한 질의 44 | 45 | instructor 릴레이션 46 | 47 |

instructor 48 | 49 |
50 |
51 |
52 | 53 | ## select, from 54 | 55 | e.g., 질의 : “모든 교수의 이름을 찾아라” 56 | 57 | ```sql 58 | select name # 교수의 이름은 name 속성에 있다. 59 | from instructor; # 교수의 이름은 instructor 릴레이션에서 발견된다. 60 | ``` 61 | 62 | 질의 결과 : 표제로 **name**이라는 단일 속성만으로 구성된 릴레이션 63 | 64 |
65 | 66 |

결과1 67 | 68 |
69 |
70 | 71 | e.g., 질의 : “모든 교수의 소속 학과 이름을 찾아라” 72 | 73 | ```sql 74 | select dept_name # 소속 학과 이름은 dept_name 속성에 있다. 75 | from instructor; 76 | ``` 77 | 78 | - 한 학과에 한 명 이상의 교수가 소속될 수 있으므로 학과 이름은 instructor 릴레이션에서 한 번 이상 나타날 수 있다. 79 | - 질의 결과 : 표제로 **dept_name**이라는 단일 속성만으로 구성된 릴레이션 80 | 81 |

결과2 82 | 83 |
84 |
85 | 86 | 관계형 모델의 공식적이며 수학적인 정의에서는 릴레이션은 `집합`이기 때문에 중복된 튜플은 릴레이션에서 나타날 수 없다. 87 | 88 | **그러나 SQL은 SQL 표현의 결과에서뿐만 아니라 릴레이션에서도 중복을 허용한다.** 89 | 90 | 단, 스키마에 주 키 선언이 포함된 데이터베이스 릴레이션은 중복 튜플을 포함할 수 없다. (주 키 제약 조건의 위배되기 때문) 91 | 92 |
93 | 94 | 따라서 2번째 질의는 instructor 릴레이션에 있는 모든 튜플에 대해 각 학과 이름을 한 번씩 나열한다. 95 | 96 |
97 | 98 | ### distinct 99 | 100 | 중복된 튜플을 제거하고 싶을 경우, `select` 뒤에 `distinct`라는 키워드를 삽입하면 된다. 101 | 102 | ```sql 103 | select distinct dept_name # 중복 제거 104 | from instructor; 105 | ``` 106 | 107 | 질의 결과 : 각 학과 이름은 한 번만 포함된다. 108 | 109 |
110 | 111 | SQL에서 중복 제거를 명시적으로 하지 않으려면 `all`이라는 키워드를 사용할 수 있는데, 기본적으로 중복이 허용되기 때문에 이는 잘 사용하지 않는다. 112 | 113 | ```sql 114 | select all dept_name # 중복을 허용하여 모든 튜플을 나열한다. 115 | from instructor; 116 | ``` 117 | 118 |
119 | 120 | ### 산술 표현 121 | 122 | select 절에 상수나 튜플의 속성에 적용되는 `+`, `-`, `*`, `/` 연산자를 포함하는 산술 표현을 사용할 수 있다. 123 | 124 |
125 | 126 | e.g., 질의 : “각 교수의 급여를 10% 인상한 것의 결과” 127 | 128 | ```sql 129 | select ID, name, dept_name, salary * 1.1 130 | from instructor; 131 | ``` 132 | 133 | 질의 결과 : 속성 salary 1.1에 곱하는 것을 제외하고 instructor 릴레이션과 똑같은 릴레이션을 반환한다. 134 | 135 |
136 | 137 | 또한 SQL은 **날짜 타입과 같은 특수한 데이터 타입을** 제공하며 이러한 데이터 타입에 적용 가능한 여러 산술 함수를 허용한다. *(4.5.1절에서 다룸)* 138 | 139 |
140 |
141 | 142 | ## where 143 | 144 | `where` 절은 from 절의 릴레이션에 있는 튜플 중 **where 절에 명시된 술어를 만족하는 행만 반환하게 한다.** 145 | 146 |
147 | 148 | e.g., 질의 : “컴퓨터 과학(Computer Science)과에서 급여가 $70,000이 넘는 모든 교수의 이름을 구하라” 149 | 150 | ```sql 151 | select name 152 | from instructor 153 | where dept_name = 'Comp. Sci.' and salary > 70000; 154 | ``` 155 | 156 | 질의 결과 157 | 158 |

결과3 159 | 160 |
161 |
162 | 163 | ### 논리 접속사 164 | 165 | SQL에서 where 절에 `and`, `or`, `not`과 같은 논리 접속사를 사용할 수 있다. 166 | 167 | `>`, `≥`, `=`, `<>(≠)`를 포함하는 표현식은 논리 접속사의 피연산자가 될 수 있다. 168 | 169 | SQL에서 날짜 타입과 같은 특수 타입뿐만 아니라 문자열이나 산술 표현의 비교를 위한 연산자도 사용할 수 있다. *(3.4.5절에서 더 다룸)* 170 | 171 |
172 |
173 |
174 | 175 | # 3.3.2 복수의 릴레이션에 관한 질의 176 | 177 | department 릴레이션 178 | 179 |

department 180 | 181 |
182 |
183 | 184 | e.g., 질의 : “모든 교수의 이름과 함께, 그들의 학과 이름과 건물 이름을 구하라” 185 | 186 | - instructor 릴레이션에서 **dept_name** 속성으로부터 학과 이름을 가져올 수 있다. 187 | - department 릴레이션에서 **building** 속성으로부터 건물 이름을 가져올 수 있다. 188 | 189 |
190 | 191 | 이 질의에 답을 하려면, 192 | 193 | 1. SQL에 접근해야 하는 릴레이션을 `from`으로 나열하고 194 | 2. 일치 조건을 `where` 절에 지정해야 한다. 195 | 196 |
197 | 198 | ```sql 199 | select name, instructor.dept_name, building 200 | from instructor, department 201 | where instructor.dept_name = department.dept_name; 202 | ``` 203 | 204 | - `instructor.dept_name` 205 | - dept_name 속성은 두 릴레이션에 모두 나타나고, **참고하고자 하는 속성이 어느 릴레이션에 속해 있는지 명시적으로 나타나도록** 릴레이션 이름이 앞에 붙었다. 206 | - name, building 207 | - 이 둘은 릴레이션들 중 하나에서만 나타나므로 릴레이션 이름을 앞에 붙일 필요가 없다. 208 | 209 |
210 | 211 | 질의 결과 212 | 213 |

결과4 214 | 215 |
216 |
217 | 218 | > 위의 명명법을 사용하려면 from 절에 존재하는 릴레이션이 고유한 이름을 가져야 한다. 219 | 220 | 이때 같은 릴레이션의 다른 두 튜플의 정보가 결합되어야 하는 경우 문제가 생길 수 있는데, 221 | 이는 `rename` 연산을 통해 해결할 수 있다. *(3.4.1절에서 자세히 설명함)* 222 | 223 |
224 |
225 | 226 | ## from 절 227 | 228 | from 절 자체는 나열된 릴레이션의 `카티션 곱(Cartesian product, ×)`을 정의한다. 229 | 230 | **결과 릴레이션은 from 절의 모든 릴레이션에 있는 모든 속성을 다 가진다.** 231 | 232 |
233 | 234 | e.g., 235 | 236 | teaches 릴레이션 237 | 238 |

teaches 239 | 240 |
241 |
242 | 243 | instructor와 teaches 릴레이션의 카티션 곱의 릴레이션 스키마는 다음과 같다. 244 | 245 | ``` 246 | (instructor.ID, instructor.name, instructor.dept_name, instructor.salary, 247 | teaches.ID, teaches.course_id, teaches.sec_id, teaches.semester, teaches.year) 248 | ``` 249 | 250 | - 이 스키마에서 instructor.ID와 teaches.ID는 서로 구분된다. 251 | - **두 스키마 중에서 한 스키마에만 나타나는 속성에 대해서는** 간단히 표기해도 어떤 릴레이션의 속성인지 바로 알 수 있기 때문에 **릴레이션 이름이 생략된다.** 252 | 253 |
254 | 255 | 따라서 결과 릴레이션의 스키마는 다음과 같다. 256 | 257 | ``` 258 | (instructor.ID, name, dept_name, salary, 259 | teaches.ID, course_id, sec_id, semester, year) 260 | ``` 261 | 262 |
263 | 264 | ### Cartesian product과 where 절 265 | 266 | 카티션 곱은 스스로 서로 관계가 없는 instructor와 teaches 튜플과 결합한다. 267 | 268 | instructor의 각 튜플은 teaches의 다른 교수를 지칭하는 튜플을 포함한 모든 튜플과 결합한다. 269 | 270 |
271 | 272 |

카티션 곱 273 | 274 |
275 |
276 | 277 | 이러한 카티션 곱은 거의 잘못된 것이다. 278 | 279 |
280 | 281 | > `where` 절의 술어는 카티션 곱에 의해 생성되는 조합을 필요에 따라 걸러내기 위해 사용된다. 282 | 283 | instructor와 teaches에 관련된 질의는 일반적으로 284 | (1) instructor의 특정 튜플 t와 285 | (2) t가 참조하는 같은 교수를 가리키는 teaches의 튜플과 결합할 것을 기대한다. 286 | 287 | **즉, 같은 ID 값을 가진 teaches 튜플과 instructor 튜플이 일치하기를 기대한다.** 288 | 289 |
290 | 291 | 다음의 SQL 질의는 이러한 조건을 보장하고, 이렇게 일치한 튜플로부터 교수 이름과 과목 식별자(ID)를 출력한다. 292 | 293 | ```sql 294 | select name, course_id 295 | from instructor, teaches 296 | where instructor.ID = teaches.ID; 297 | ``` 298 | 299 | - 이 질의는 일부 과목을 가르쳤던 교수만 출력한다. 300 | - **어떤 과목도 가르치지 않았던 교수는 출력되지 않는다.** 301 | - 이러한 튜플도 보고 싶다면 `외부 조인(outer join)`이라고 불리는 연산을 사용해야 한다. *(4.1.3절에서 설명)* 302 | 303 |
304 | 305 | > 💡 질의 작성 시 적절한 where 절 조건을 포함해야 한다. 306 | 307 |
308 |
309 | 310 | ## where 절 - and 311 | 312 | e.g., 질의 : “대학교 내에서 일부 과목을 가르친 적이 있는 모든 교수에 대해, 그들의 이름과 그들이 가르쳤던 과목 아이디를 찾아라” 313 | 314 | ```sql 315 | select name, course_id 316 | from instructor, teaches 317 | where instructor.ID = teaches.ID and instructor.dept_name = 'Comp. Sci'; 318 | ``` 319 | 320 | - 속성 **dept_name**은 instructor 릴레이션에서만 나타나기 때문에 instructor.dept_name 대신에 dept_name만 사용해도 된다. 321 | - 질의 결과 322 | 323 |

결과5 324 | 325 |
326 |
327 |
328 | 329 | # SQL 질의의 의미 330 | 331 | SQL 질의의 의미는 일반적으로 다음과 같다. 332 | 333 | 1. `from` 절에 나열된 릴레이션의 **카티션 곱**을 생성하라. 334 | 335 | 2. 1번의 결과에 대해 `where` 절에 명시된 술어를 적용하라. 336 | 337 | 3. 2번의 결과의 모든 튜플에 대해 `select` 절에 명시된 속성(또는 표현의 결과)을 출력하라. 338 | 339 |
340 | 341 | 이러한 순서는 SQL 질의의 실행 방법은 아니며, 결과가 무엇인지 명확하게 하는 데 도움이 된다. 342 | 343 |
344 | 345 | 실제 DBMS는 이런 방식으로 SQL 질의를 수행하지 않는다. 346 | 347 | 대신, where 절의 술어를 만족하는 카티션 곱의 (결과) 튜플만 생성하여 질의 수행을 최적화할 수 있다. *(이는 15장, 16장에서 학습함)* 348 | -------------------------------------------------------------------------------- /Part_01/Chapter_03/3.4 부가적인 기본 연산/README.md: -------------------------------------------------------------------------------- 1 | # 3.4 부가적인 기본 연산 2 | 3 |
4 | 5 | # 3.4.1 재명명 연산 6 | 7 | ```sql 8 | select name, course_id 9 | from instructor, teaches 10 | where instructor.ID = teaches.ID; 11 | ``` 12 | 13 | 위 질의에서 결과는 name, course_id의 속성을 갖는 릴레이션이었다. 14 | 15 | 결과 릴레이션의 속성의 이름은 `from` **절에 있는 릴레이션의 속성 이름으로부터 파생되었다.** 16 | 17 |
18 | 19 | 그러나 아래의 상황에서는 이와 같은 방법으로 이름을 파생시킬 수 없다. 20 | 21 | 1. from 절에 있는 두 개의 릴레이션이 같은 이름을 갖는 경우 22 | - 그 속성의 이름이 결과 내에서 중복될 수 있다. 23 | 24 | 25 | 2. select 절에서 산술식을 사용했을 경우 26 | - 그 결과의 속성은 이름을 가지지 않는다. 27 | 28 |
29 | 30 | 또한, 앞선 예제처럼 속성 이름을 원래의 릴레이션으로부터 얻는다고 하더라고 결과에서 그 속성의 이름을 바꾸고 싶은 경우도 있다. 31 | 32 |
33 |
34 | 35 | ## as 절 36 | 37 | 이에 따라 SQL은 **결과 릴레이션에서 속성의 이름을 다시 짓는 방법**, 즉 `as 절(as clause)`을 제공한다. 38 | 39 | ```sql 40 | old-name as new-name 41 | ``` 42 | 43 |
44 | 45 | > as 절은 `select` 절과 `from` 절 둘 다에서 나타날 수 있다. 46 | 47 | (SQL의 초기 버전에는 as 키워드가 포함되지 않았기에 일부 DBMS, 특히 Oracle은 from 절에 as와 같은 키워드를 허용하지 않음) 48 | 49 | e.g., 50 | 51 | ```sql 52 | select name as instructor_name, course_id 53 | from instructor, teaches 54 | where instructor.ID = teaches.ID; 55 | ``` 56 | 57 |
58 | 59 | > 릴레이션의 이름을 다시 짓는 한 가지 이유는 질의의 어디에서나 더 편리하게 사용하기 위해 60 | > 길이가 긴 릴레이션 이름을 길이가 짧은 것으로 바꾸기 위함이다. 61 | 62 | e.g., 질의 : “대학교 내에서 일부 과목을 가르친 적이 있는 모든 교수에 대해, 그들의 이름과 그들이 가르쳤던 과목의 과목 아이디를 찾아라” 63 | 64 | ```sql 65 | select T.name, S.course_id 66 | from instructor as T, teaches as S 67 | where T.ID = S.ID; 68 | ``` 69 | 70 |
71 | 72 | ### 테이블 별칭(table alias) 73 | 74 | > 릴레이션의 이름을 다시 짓는 또 다른 이유는 같은 릴레이션에서 튜플을 비교할 때다. 75 | 76 | 릴레이션을 자기 자신과 카티션 곱을 수행해야 하는 경우, 릴레이션의 이름을 다시 지을 수 없다면 카티션 곱에 참여하는 릴레이션의 튜플을 구분할 수 없다. 77 | 78 |
79 | 80 | e.g., 질의 : “적어도 생물학과 한 교수보다 급여가 많은 모든 교수의 이름을 구하라” 81 | 82 | ```sql 83 | select distinct T.name 84 | from instructor as T, instructor as S 85 | where T.salary > S.salary and S.dept_name = 'Biology'; 86 | ``` 87 | 88 | - 여기서 `T`와 `S`는 instructor 릴레이션에 대해 대체되는 이름으로 선언되었다. (별칭) 89 | - 즉, instructor 릴레이션의 복사본이 아니다. 90 | 91 | 92 | - T, S와 같은 식별자는 릴레이션의 이름을 다시 짓기 위해 사용되며 SQL 표준에서는 `상관 이름(correlation name)`이라고 불리기도 한다. 93 | - 흔히 `테이블 별칭(table alias)`, `상관 변수(correlation variable)`, `튜플 변수(tuple variable)`라고도 불린다. 94 | 95 |
96 | 97 | 앞의 질의를 더 잘 표현하자면 “생물학과에서 가장 낮은 급여를 받는 교수보다 더 많이 버는 교수의 이름을 찾아라”라고 할 수 있다. 98 | 99 | 원래 썼던 표현이 우리가 쓰는 SQL에 더 가까우나, 후자가 더 직관적이고 SQL로 직접 표현하기도 쉽다. *(3.8.2절에서 재등장)* 100 | 101 |
102 |
103 |
104 | 105 | # 3.4.2 문자열 연산 106 | 107 | 108 | - SQL은 문자열을 `작은 따옴표(’)`를 사용하여 표기한다. 109 | - e.g., `‘Biology’` 110 | 111 | 112 | - 문자열 일부로 사용된 작은 따옴표 문자는 작은 따옴표 문자 두 개를 사용하여 표기한다. 113 | - e.g., “It’s right”는 `‘It’’s right’`라고 표기한다. 114 | 115 |
116 | 117 | SQL 표준은 문자열에 대한 등호 연산에서 대소 문자를 구분한다고 명시하고 있다. 118 | 119 | 따라서 `’comp. sci.’ = ‘Comp.Sci’` 표현의 결과는 거짓이 된다. 120 | 121 |
122 | 123 | > 그러나 MySQL, SQL Server와 같은 **일부 DBMS는 문자열 비교를 할 때 대소문자를 구별하지 않는다.** 124 | 125 | 이들 DBMS는 `’comp. sci.’ = ‘Comp.Sci’`의 결과는 참이 된다. 126 | 127 | 데이터베이스나 특정 속성의 수준에서 이러한 기본 동작을 변경할 수 있다. 128 | 129 |
130 |
131 | 132 | ## 문자열에 대한 함수들 133 | 134 | SQL은 문자열에 대한 다양한 함수를 제공한다. 135 | 136 | - 문자열 합병 (”`||`” 사용) 137 | - 부분 문자열 추출 138 | - 문자열의 길이 찾기 139 | - 문자열을 대문자 혹은 소문자로 변경하기 (`upper(s)` 또는 `lower(s)`,이때 s는 문자열) 140 | - 문자열 끝의 공백 제거하기 (`trim(s)`) 141 | 142 |
143 | 144 | 서로 다른 데이터베이스 시스템에서 제공되는 문자열 함수는 다양하다. 145 | 146 | 각 데이터베이스 시스템에서 어떤 문자열 함수가 지원되는지는 해당 데이터베이스 시스템의 설명서를 참조하도록 하자. 147 | 148 |
149 | 150 | ### like 연산자 151 | 152 | 문자열에서 `like` 연산자를 사용하여 **패턴 일치**를 수행할 수 있다. 153 | 154 |
155 | 156 | 패턴은 다음과 같은두 개의 특수문자를 사용하여 나타낼 수 있다. 157 | 158 | > 퍼센트(`%`) : % 문자는 **어떠한 부분 문자열**과도 일치한다. 159 | 160 | > 밑줄(`_`) : _ 문자는 **어떠한 문자**와도 일치한다. 161 | 162 |
163 | 164 | 패턴은 대소 문자를 구분한다. (MySQL은 제외) 165 | 166 | 일부 데이터베이스는 대소문자를 구별하지 않는 like 연산의 변종을 제공한다. 167 | 168 |
169 | 170 | e.g., 171 | 172 | - `‘Intro%’`는 “Intro”로 시작하는 어떠한 문자열과도 일치한다. 173 | - `‘%Comp%’`는 ‘Intro. to Computer Science’, ‘Computational Biology’와 같은 **“Comp”를 부분 문자열로 포함하는** 어떠한 문자열과도 일치한다. 174 | - `‘___’`은 정확히 세 개의 문자로 이루어진 문자열과 일치한다. 175 | - ‘`___%’`는 세 문자 이상으로 이루어진 문자열과 일치한다. 176 | 177 |
178 | 179 | e.g., 질의 : “건물 이름에 ‘Watson’이라는 부분 문자열을 포함하는 모든 학과 이름을 구하라” 180 | 181 | ```sql 182 | select dept_name 183 | from department 184 | where building like '%Watson%'; 185 | ``` 186 | 187 |
188 | 189 | ### not like 비교 연산자 190 | 191 | SQL은 `not like` 비교 연산자를 사용하여 일치하지 않은 문자열에 대해 검색을 할 수도 있다. 192 | 193 |
194 | 195 | e.g., 질의 : “건물 이름에 ‘Watson’이라는 부분 문자열을 포함하지 않는 모든 학과 이름을 구하라” 196 | 197 | ```sql 198 | select dept_name 199 | from department 200 | where building not like '%Watson%'; 201 | ``` 202 | 203 |
204 | 205 | ### like 비교에서의 escape 키워드 206 | 207 | SQL은 패턴에서 (`%`와 `_`와 같은) 특수 패턴 문자를 포함할 수 있도록 `이스케이프(escape) 문자`에 관한 명시를 하고 있다. 208 | 209 | 이스케이프 문자는 특수 패턴 문자가 일반 문자처럼 사용되기를 원할 대 특수 패턴 문자 바로 앞에 사용한다. 210 | 211 |
212 | 213 | e.g., `역슬래시(\)` 문자를 이스케이프 문자로 사용하는 패턴 214 | 215 | - `like ‘ab\%cd%’ escape ‘\’`는 “ab%cd”로 시작하는 모든 문자열과 일치한다. 216 | - `like ‘ab\\cd%’ escape ‘\’`는 “ab/cd”로 시작하는 모든 문자열과 일치한다. 217 | 218 |
219 |
220 |
221 | 222 | # 3.4.3 Select 절의 속성 지정 223 | 224 | 별표 “`*`”는 select 절에서 “**모든 속성**”을 가리키기 위해 사용된다. 225 | 226 | `select *`의 형식을 갖는 select 절은 from 절에서 선택된 결과 릴레이션의 모든 속성을 가리킨다. 227 | 228 |
229 | 230 | e.g., 231 | 232 | ```sql 233 | select instructor.* # instructor의 모든 속성을 선택하도록 가리킨다. 234 | from instructor, teaches 235 | where instructor.ID = teaches.ID; 236 | ``` 237 | 238 |
239 |
240 |
241 | 242 | # 3.4.4 튜플 출력의 순서 243 | 244 | SQL은 릴레이션에 있는 튜플의 출력될 순서를 사용자가 제어할 수 있도록 한다. 245 | 246 |
247 | 248 | ## order by 절 249 | 250 | `order by` 절은 질의의 결과 튜플이 **정렬된 순서**로 나타나도록 한다. 251 | 252 |
253 | 254 | e.g., 질의 : “물리학과의 모든 교수를 알파벳 순서로 나열하라” 255 | 256 | ```sql 257 | select name 258 | from instructor 259 | where dept_name = 'Physics' 260 | order by name; # 기본값 : 오름차순 정렬 261 | ``` 262 | 263 |
264 | 265 | ### desc, asc 266 | 267 | > 기본적으로, order by 절은 **오름차순**으로 항목을 나열한다. 268 | 269 | 정렬 순서를 명시하기 위해서 내림차순을 위해서 `desc`를, 오름차순을 위해서 `asc`를 명시할 수 있다. 270 | 271 |
272 | 273 | > 정렬은 **복수의 속성에 대해** 이루어질 수 있다. 274 | 275 | e.g., 276 | 277 | - instructor 릴레이션 전체를 salary에 대해서 내림차순으로 정렬하기를 원한다. 278 | - 만약 여러 교수가 같은 급여를 받는다면, 교수 이름에 대한 오름차순으로 이들을 정렬할 수 있다. 279 | 280 | ```sql 281 | select * 282 | from instructor 283 | order by salary desc, name asc; 284 | ``` 285 | 286 |
287 |
288 |
289 | 290 | # 3.4.5 Where 절의 술어 291 | 292 |
293 | 294 | ## between 비교 연산자 295 | 296 | e.g., 질의 : “급여가 $90,000과 $100,000 사이에 있는 교수들의 이름을 찾으시오” 297 | 298 | ```sql 299 | select name 300 | from instructor 301 | where salary >= 90000 and salary <= 100000; 302 | ``` 303 | 304 |
305 | 306 | SQL은 where 절에서 어떤 값보다는 작거나 같고 어떤 값보다는 크거나 같은 값을 명시하기 위해 `between` 비교 연산자를 제공한다. 307 | 308 | 위의 질의문 대신, between 비교를 사용해서 아래와 같은 SQL 질의를 작성할 수 있다. 309 | 310 | ```sql 311 | select name 312 | from instructor 313 | where salary between 90000 and 100000; 314 | ``` 315 | 316 |
317 | 318 | 이와 유사하게 `not between` 비교 연산자도 사용할 수 있다. 319 | 320 |
321 |
322 | 323 | ## 행 생성자(row constructor) 324 | 325 | SQL에서는 n개의 값 v1, v2, … , vn을 가지는 **n차 튜플**을 나타내기 위해 `(v1, v2, … , vn)`와 같은 표현이 가능하다. 326 | 327 | 이를 `행 생성자(row constructor)`라고 한다. 328 | 329 |
330 | 331 | 비교 연산자는 튜플에서 사용될 수 있고, 순서는 사전 순서대로 정의된다. 332 | 333 | e.g., `a1 < b1 and a2 ≤ b2`라면 `(a1, a2) ≤ (b1, b2)`는 참이다. 334 | 335 |
336 | 337 | 유사하게, 두 튜플의 속성이 같으면 두 튜플은 같다. 338 | 339 | 따라서 아래 질의는 다음과 같이 다시 작성될 수 있다. 340 | 341 | ```sql 342 | select name, course_id 343 | from instructor, teaches 344 | where instructor.ID = teaches.ID and dept_name = 'Biology'; 345 | ``` 346 | 347 | ```sql 348 | select name, course_id 349 | from instructor, teaches 350 | where (instructor.ID, dept_name) = (teaches.ID, 'Biology'); 351 | ``` 352 | 353 | (SQL-92 표준의 일부이긴 하나 몇몇 DBMS의 경우, 특히 Oracle은 이 구문을 지원하지 않음) 354 | -------------------------------------------------------------------------------- /Part_01/Chapter_03/3.5 집합 연산/README.md: -------------------------------------------------------------------------------- 1 | # 3.5 집합 연산 2 | 3 |
4 | 5 | SQL 연산 `union`, `intersect`, `except`는 릴레이션에 대해 각각 관계 대수 연산 `⋃`, `⋂`, `-`와 같은 연산을 수행한다. 6 | 7 |
8 | 9 | e.g., 10 | 11 | 1. 2017년 가을에 가르쳤던 모든 과목의 집합 12 | 13 | - 질의문 14 | 15 | ```sql 16 | select course_id 17 | from section 18 | where semester = 'Fall' and year == 2017; 19 | ``` 20 | 21 | - 질의 결과 : c1 릴레이션 22 | 23 |

결과1 24 | 25 |
26 |
27 | 28 | 2. 2018년 봄에 가르쳤던 모든 과목의 집합 29 | 30 | - 질의문 31 | 32 | ```sql 33 | select course_id 34 | from section 35 | where semester = 'Spring' and year == 2018; 36 | ``` 37 | 38 | - 질의 결과 : c2 릴레이션 39 | 40 |

결과2 41 | 42 |
43 |
44 |
45 | 46 | ## 3.5.1 합집합 연산 47 | 48 | 질의 : “2017년 가을과 2018년 봄에 연속해서 강의가 되었던 **모든 과목의 집합**” 49 | 50 | ```sql 51 | (select course_id 52 | from section 53 | where semester = 'Fall' and year == 2017) 54 | union 55 | (select course_id 56 | from section 57 | where semester = 'Spring' and year == 2018); 58 | ``` 59 | 60 |
61 | 62 | 질의 결과 : `c1 union c2` 63 | 64 |

결과3 65 | 66 |
67 |
68 | 69 | > `union` 연산은 select 절과는 다르게 **자동으로 중복을 제거한다.** 70 | 71 |
72 | 73 | > 만약 모든 중복을 보유하고 싶다면 union 대신 `union all`을 써야 한다. 74 | 75 | ```sql 76 | (select course_id 77 | from section 78 | where semester = 'Fall' and year == 2017) 79 | union all 80 | (select course_id 81 | from section 82 | where semester = 'Spring' and year == 2018); 83 | ``` 84 | 85 | 위 결과의 중복 튜플 개수는 c1과 c2 둘 다에서 나타나는 중복된 튜플의 총 개수와 같다. 86 | 87 |
88 |
89 | 90 | ## 3.5.2 교집합 연산 91 | 92 | 질의 : “2017년 가을과 2018년 봄에 **모두 가르친** 모든 과목의 집합” 93 | 94 | ```sql 95 | (select course_id 96 | from section 97 | where semester = 'Fall' and year == 2017) 98 | intersect 99 | (select course_id 100 | from section 101 | where semester = 'Spring' and year == 2018); 102 | ``` 103 | 104 |
105 | 106 | 질의 결과 : `c1 intersect c2` 107 | 108 |

결과4 109 | 110 |
111 |
112 | 113 | > `intersect`는 자동으로 중복을 제거한다. 114 | 115 | MySQL은 intersect 연산을 구현하지 않는다. 대신 한 가지 해결책은 하위 질의를 사용하는 것이다. *(3.8.1절에서 논의)* 116 | 117 |
118 | 119 | > 만약 모든 중복을 보유하고 싶다면 intersect 대신 `intersect all`이라고 써야 한다. 120 | 121 | ```sql 122 | (select course_id 123 | from section 124 | where semester = 'Fall' and year == 2017) 125 | intersect all 126 | (select course_id 127 | from section 128 | where semester = 'Spring' and year == 2018); 129 | ``` 130 | 131 | 위 결과의 중복 튜플의 개수는 c1과 c2 둘 다에서 나타나는 중복 튜플 개수의 최솟값과 같다. 132 | 133 |
134 |
135 | 136 | ## 3.5.3 차집합 연산 137 | 138 | 질의 : “2017년 가을 학기**에는 있지만** 2018년 봄 학기**에는 없는** 모든 과목” 139 | 140 | ```sql 141 | (select course_id 142 | from section 143 | where semester = 'Fall' and year == 2017) 144 | except 145 | (select course_id 146 | from section 147 | where semester = 'Spring' and year == 2018); 148 | ``` 149 | 150 |
151 | 152 | 질의 결과 : `c1 except c2` 153 | 154 |

결과5 155 | 156 |
157 |
158 | 159 | > `except` 연산은 첫 번째 입력 릴레이션의 모든 튜플 중에서 두 번째 입력 릴레이션에 없는 모든 튜플을 출력한다. 160 | 161 | - 즉, 차집합 연산을 수행한다. 162 | - **차집합 연산을 수행하기 전에 자동으로 입력의 중복이 제거된다.** 163 | 164 |
165 | 166 | - 일부 DBMS, 특히 Oracle은 except 대신 키워드 `minus`를 사용하는 반면, Oracle 12c는 except all 대신 키워트 `multiset except`를 사용한다. 167 | - MySQL은 except 연산을 구현하지 않으며, 한 가지 해결책은 하위 질의를 사용하는 것이다. *(3.8.1절에서 논의)* 168 | 169 |
170 | 171 | > 만약 모든 중복을 보유하고 싶다면 except 대신에 `except all`이라고 써야 한다. 172 | 173 | ```sql 174 | (select course_id 175 | from section 176 | where semester = 'Fall' and year == 2017) 177 | except all 178 | (select course_id 179 | from section 180 | where semester = 'Spring' and year == 2018); 181 | ``` 182 | 183 | 위 결과의 중복 튜플 개수는 c1에서 중복된 개수에서 c2에서 중복된 개수를 뺀 것에서 그 차가 양수일 때와 같다. 184 | -------------------------------------------------------------------------------- /Part_01/Chapter_03/3.6 널 값/README.md: -------------------------------------------------------------------------------- 1 | # 3.6 널 값 2 | 3 |
4 | 5 | 산술 연산, 비교 연산, 집합 연산을 포함한 관계 연산을 수행할 때 `널 값(null value)`이 있으면 특별한 처리가 필요하다. 6 | 7 |
8 |
9 | 10 | ## 산술 연산에서의 null 11 | 12 | > `산술 연산식(+, -, *, /)`의 결과는 **입력 값이 널이면 널**이다. 13 | 14 |
15 | 16 | 예를 들어, 17 | 18 | - `r.A + 5`의 표현이 있고, 19 | - `r.A`가 특정 튜플에 대해 널일 때 20 | 21 | → 그 튜플에 대한 연산식의 결과는 반드시 널이어야 한다. 22 | 23 |
24 |
25 | 26 | ## 비교 연산에서의 null 27 | 28 | `1 < null`의 비교를 고려해보자. 29 | 30 | **널 값이 무엇을 나타내는지 모르기 때문에** 이 비교 값의 결과가 참이라고 하는 것은 옳지 않을 수 있고, 31 | 결과가 거짓이라고 주장하는 것도 옳지 않다. 32 | 33 |
34 | 35 | > 따라서 SQL은 널 값을 포함하는 비교의 결과를 `unknown`으로 처리한다. 36 | 37 | unknown은 true와 false 외에 추가된 제3의 논리 값을 나타낸다. 38 | 39 |
40 | 41 | ### and, or, not 42 | 43 | where 절의 술어는 비교의 결과에 대한 `and`, `or`, `not`과 같은 `불리언(Boolean) 연산`을 포함하기 때문에, 44 | 다음과 같이 불리언 연산의 정의는 unknown 값을 다룰 수 있도록 확장되어야 한다. 45 | 46 |
47 | 48 | > and 49 | 50 | - `true and unknown`의 결과는 unknown 51 | - `false and unknown`의 결과는 false 52 | - `unknown and unknown`의 결과는 unknown 53 | 54 |
55 | 56 | > or 57 | 58 | - `true or unknown`의 결과는 true 59 | - `false or unknown`의 결과는 unknown 60 | - `unknown or unknown`의 결과는 unknown 61 | 62 |
63 | 64 | > not 65 | 66 | - `not unknown`의 결과는 unknown 67 | 68 |
69 | 70 | --- 71 | 72 |
73 | 74 | **r.A가 널이라면**, “`1 < r.A`”뿐만 아니라 “`not(1 < r.A)`”도 unknown이 됨을 알 수 있다. 75 | 76 |
77 | 78 | > **where 절의 술어가 어떤 튜플에 대해 false나 unknown으로 판명되면 그 튜플은 결과에 포함하지 않는다.** 79 | 80 |
81 |
82 | 83 | ## null, is not null 술어 84 | 85 | SQL은 널 값을 테스트하는 술어 안에 특수한 키워드 `null`을 사용한다. 86 | 87 | `is not null` 술어는 적용된 값이 널이 아닐 때 참이다. 88 | 89 |
90 | 91 | e.g., 질의 : “instructor 릴레이션에서 salary의 값이 널 값인 모든 교수” 92 | 93 | ```sql 94 | select name 95 | from instructor 96 | where salary is null; 97 | ``` 98 | 99 |
100 |
101 | 102 | ## select distinct 절과 집합 연산에서의 null 103 | 104 | 질의가 `select distinct` 절을 사용할 때, **중복된 튜플은 반드시 제거되어야 한다.** 105 | 106 |
107 | 108 | 이러한 목적으로, 두 튜플의 상응하는 속성값을 비교할 때 값이 둘 다 널이 아닌 같은 값을 가지거나 **둘 다 널일 때 값이 같은 것으로 간주한다.** 109 | 110 |
111 | 112 | 예를 들어, `{(’A’, null), (’A’, null)}`과 같이 어떤 속성이 널 값을 가지더라도 두 튜플은 같은 것으로 간주한다. 113 | 114 | 따라서 `distinct` 절을 사용하면 값이 같은 튜플 중 하나만 유지하게 된다. 115 | 116 |
117 | 118 | 위에서 보인 널 값의 처리는 “`null = null`”의 비교 결과가 unknown이 아니라 **true**를 반환하는 것으로, 119 | 술어에서 일반적으로 널 값을 처리하는 방식과는 다르다. 120 | 121 |
122 | 123 | > **일부 값이 널이라도 모든 속성값이 같으면 튜플을 같은 것으로 보는 방법**은 합집합, 교집합, 차집합 연산에서도 사용된다. 124 | -------------------------------------------------------------------------------- /Part_01/Chapter_03/3.7 집계 함수/README.md: -------------------------------------------------------------------------------- 1 | # 3.7 집계 함수 2 | 3 |
4 | 5 | ## 집계 함수(aggregate function) 6 | 7 | - 입력 : 값의 모음(collection, 즉 집합 혹은 다중 집합) 8 | - 결과 : 단일 값을 반환 9 | 10 |
11 | 12 | SQL은 다섯 개의 표준 내장 집계 함수를 제공한다. 13 | 14 | (대부분의 DBMS는 부가적으로 많은 집계 함수를 제공함) 15 | 16 | - 평균 : `avg` 17 | - 최솟값 : `min` 18 | - 최댓값 : `max` 19 | - 총합 : `sum` 20 | - 개수 : `count` 21 | 22 |
23 | 24 | `sum`과 `avg`의 입력은 숫자의 모음이어야 하지만, 다른 연산자는 문자열과 같이 숫자가 아닌 데이터 타입의 모음에서도 동작한다. 25 | 26 |
27 |
28 |
29 | 30 | # 3.7.1 기본 집계 31 | 32 | ## 평균(avg) 33 | 34 | e.g., 질의 : “컴퓨터 과학과 교수들의 평균 급여를 구하라” 35 | 36 | ```sql 37 | select avg(salary) 38 | from instructor 39 | where dept_name = 'Comp. Sci.'; 40 | ``` 41 | 42 |
43 | 44 | ### as 45 | 46 | DBMS는 집계로 인해 생성된 결과 릴레이션의 속성에 임의의 이름을 부여할 수 있다. 47 | 48 | 하지만 속성에 의미 있는 이름을 부여하기 위해서는 다음과 같이 `as` 절을 사용할 수 있다. 49 | 50 | ```sql 51 | select avg(salary) as avg_salary 52 | from instructor 53 | where dept_name = 'Comp. Sci.'; 54 | ``` 55 | 56 |
57 | 58 | ### distinct 59 | 60 | 집계 함수를 구하기 전에 중복을 제거해야 하는 경우도 있는데, 이때 키워드 `distinct`를 집계 함수 표현에 사용하면 된다. 61 | 62 |
63 | 64 | e.g., 질의 : “2018년 봄 학기에 어떤 과목을 가르치는 교수의 수를 구하라” 65 | 66 | ```sql 67 | select count(distinct ID) # 교수가 하나 이상의 과목을 가르치더라도 결과에는 한 번만 포함된다. 68 | from teaches 69 | where semester = 'Spring' and year = 2018; 70 | ``` 71 | 72 |
73 |
74 | 75 | ## 개수(count) 76 | 77 | 릴레이션에서 몇 개의 튜플이 있는지 알아보기 위해 집계 함수 `count`를 자주 사용한다. 78 | 79 | SQL에서 이 함수의 표기는 `count(*)`이다. 80 | 81 |
82 | 83 | e.g., 질의 : “course 릴레이션에서 튜플의 개수를 구하라” 84 | 85 | ```sql 86 | select count(*) 87 | from course; 88 | ``` 89 | 90 |
91 | 92 | ### distinct과 all 93 | 94 | > SQL은 count(*)에서 distinct를 사용하는 것을 금하고 있다. 95 | 96 |
97 | 98 | max와 min에서는 distinct를 사용하는 것이 가능하지만, 그 결과는 변하지 않는다. 99 | 100 | 중복 보유를 명시하기 위해 distinct 대신 키워드 all을 사용할 수 있지만, **all은 기본값이기 때문에** 그렇게까지 할 필요는 없다. 101 | 102 |
103 |
104 |
105 | 106 | # 3.7.2 그룹단위 집계 107 | 108 | 109 | 튜플들의 단일 집합이 아니라 **복수의 튜플 집합에 대해 집계 함수를 적용하고 싶을 때**가 있는데, 이때 `group by` 절을 사용할 수 있다. 110 | 111 | - group by 절에 주어진 속성(들)은 그룹을 형성하기 위해 사용된다. 112 | - **group by 절에서 모든 속성이 같은 값을 가지는 튜플들은 하나의 그룹으로 묶인다.** 113 | 114 |
115 | 116 | > e.g., 질의 : “각 학과의 평균 급여를 구하라” 117 | 118 | ```sql 119 | select dept_name, avg(salary) as avg_salary 120 | from instructor 121 | group by dept_name; 122 | ``` 123 | 124 | 1. dept_name 속성으로 그룹화한 instructor 릴레이션의 튜플 125 | 126 |

결과1 127 | 128 |
129 |
130 | 131 | 2. 각 그룹에 대해 집계 연산을 수행하여 얻은 결과 132 | 133 |

결과2 134 | 135 |
136 |
137 | 138 | > e.g., 질의 : “모든 교수의 평균 급여를 구하라” 139 | 140 | ```sql 141 | select avg(salary) 142 | from instructor; 143 | ``` 144 | 145 | **이 경우에 group by 절은 제외되므로 전체 릴레이션을 하나의 그룹으로 간주한다.** 146 | 147 |
148 | 149 | > e.g., 질의 : “2018년 봄 학기에 각 학과에서 어떤 과목을 가르친 교수의 수를 구하라” 150 | 151 | - teaches 릴레이션에는 어떤 교수가 어떤 과목 분반을 어느 학기에 했는지에 대한 정보가 존재한다. 152 | - 이 정보는 각 교수가 소속된 학과명을 알아내기 위해 instructor 릴레이션과 `join`되어야 한다. 153 | 154 | ```sql 155 | select dept_name, count(distinct ID) as instr_count 156 | from instructor, teaches 157 | where instructor.ID = teaches.ID 158 | and semester = 'Spring' 159 | and year = 2018 160 | group by dept_name; 161 | ``` 162 | 163 |

결과3 164 | 165 |
166 |
167 | 168 | --- 169 | 170 |
171 | 172 | SQL 질의가 그룹화를 사용할 때, 집계되지 않고 select 절에 나타나는 속성은 오직 group by 절에 존재하는 속성이다. 173 | 174 | > **즉, group by 절에 없는 속성은 집계 함수에 대한 인자로만 select 절 안에 나타날 수 있다.** 175 | 176 | 그렇지 않다면 오류로 간주한다. 177 | 178 |
179 | 180 | 예를 들어, 다음 질의는 ID가 group by 절에 나타나지 않았고, select 절에서 집계되지 않은 상태로 나타나기 때문에 잘못된 질의다. 181 | 182 | ```sql 183 | # erroneous query 184 | select dept_name, ID, avg(salary) 185 | from instructor 186 | group by dept_name; 187 | ``` 188 | 189 |
190 | 191 | 위 질의에서 192 | 193 | - dept_name에 따라 정의된 특정 그룹의 각 교수는 각기 다른 ID를 가질 수 있고, 194 | - 각 그룹에 대해 하나의 튜플만 출력되기 때문에 195 | 196 | 출력해야 할 ID 값을 선택하는 특별한 방법은 없다. 197 | 198 |
199 | 200 | 결과적으로 이러한 경우는 SQL에서 허용되지 않는다. 201 | 202 |
203 |
204 |
205 | 206 | # 3.7.3 Having 절 207 | 208 | 튜플보다 그룹에 대한 조건을 적용하는 것이 때로는 더 유용할 수 있다. 209 | 210 |
211 | 212 | 예를 들어, `교수들의 평균 급여가 $42,000을 넘는 학과`에만 관심이 있다고 하자. 213 | 214 | 이 조건은 하나의 튜플에만 적용될 수 없고 group by 절이 만든 각 그룹에 적용된다. 215 | 216 |
217 | 218 | 이러한 질의를 표현하기 위해 SQL은 `having` 절을 사용한다. 219 | 220 | SQL은 **그룹이 형성된 다음에 having 절의 술어를 적용**하기 때문에 집계 함수가 사용될 수 있다. 221 | 222 | ```sql 223 | select dept_name, avg(salary) as avg_salary 224 | from instructor 225 | group by dept_name 226 | having avg(salary) > 42000; 227 | ``` 228 | 229 |

결과4 230 | 231 |
232 |
233 | 234 | > select 절에서의 경우와 같이 `having` 절에 집계 함수와 함께 나타나지 않은 속성들은 반드시 `group by` 절에 나타나야 한다. 235 | 236 | 그렇지 않다면 잘못된 질의다. 237 | 238 |
239 | 240 | ### 집계 함수, group by, having 241 | 242 | `집계 함수`, `group by`, `having` 절을 포함하는 질의의 의미는 다음과 같은 연산의 순서로 정의된다. 243 | 244 |
245 | 246 | 1. 집계가 없는 질의의 경우와 마찬가지로, `from` 절은 릴레이션을 얻기 위해 먼저 수행된다. 247 | 248 | 249 | 2. `where` 절이 존재하면, where 절의 술어는 from 절의 결과 릴레이션에 적용된다. 250 | 251 | 252 | 3. where 절의 술어를 만족하는 튜플은 253 | - `group by` 절이 존재하면 group by 절에 의해 그룹화된다. 254 | - group by 절이 없다면 where 절의 술어를 만족하는 전체 튜플의 집합은 하나의 그룹으로 간주된다. 255 | 256 | 257 | 4. `having` 절이 존재한다면 각각의 그룹에 적용된다. 258 | - having 절의 술어를 만족하지 못하는 그룹은 제거된다. 259 | 260 | 261 | 5. `select` 절은 남아 있는 그룹을 사용하여 질의의 결과 튜플을 생성하는데, 이때 그룹별로 집계 연산을 적용하여 단일 결과 항을 만든다. 262 | 263 |
264 | 265 | e.g., 질의 : “2017년에 개설한 각 과목 분반에 대해서, 그 분반에 적어도 두 명의 학생이 있으면 해당 분반에 등록한 학생들의 평균과 전체 학점(tot_cred)을 구하라” 266 | 267 | ```sql 268 | select course_id, semester, year, sec_id, avg(tot_cred) 269 | from student, takes 270 | where student.ID = takes.ID and year = 2017 271 | group by course_id, semester, year, sec_id 272 | having count(ID) >= 2; 273 | ``` 274 | 275 |
276 |
277 |
278 | 279 | # 3.7.4 널 값과 불리언 값의 집계 280 | 281 | ### 널 값의 집계 282 | 283 | 널 값이 존재할 때 널 값은 집계 함수의 처리를 복잡하게 만든다. 284 | 285 |
286 | 287 | 예를 들어, instructor 릴레이션의 몇몇 튜플에 salary에 대해 널 값을 가진다고 가정하여 모든 급여의 총합을 구하는 다음 질의를 고려해보자. 288 | 289 | ```sql 290 | select sum(salary) 291 | from instructor; 292 | ``` 293 | 294 | - 위 질의에서 합해지는 값은 일부 튜플이 salary에 대해 널 값을 가지고 있으므로 널 값을 포함한다. 295 | - 전체 합이 null이라고 말하기보다는, SQL 표준은 `sum 연산은 입력의 null 값을 무시한다`고 말한다. 296 | 297 |
298 | 299 | > count(*)를 제외한 모든 집계 함수는 입력 값에서 널을 무시한다. 300 | 301 | - 널 값을 무시한 결과로, 값의 모음은 비어 있을 수도 있다. 302 | - **빈 모음에 대한** `count`**는 0**으로 정의되고, 다른 모든 집계 연산은 빈 모음이 적용되었을 때 널 값을 반환한다. 303 | 304 |
305 | 306 | ### 불리언 값의 집계 307 | 308 | **Boolean 데이터 타입**은 `true`, `false`, `unknown` 값을 가질 수 있다. 309 | 310 | `some`과 `every`와 같은 집계 함수는 불리언 값의 모음에 적용될 수 있고, 311 | 그 값들의 이접(disjunction)(`or`)과 연접(conjunction)(`and`)을 각각 계산할 수 있다. 312 | -------------------------------------------------------------------------------- /Part_02/Chapter_06/6.1 설계 과정의 개요/README.md: -------------------------------------------------------------------------------- 1 | # 6.1 설계 과정의 개요 2 | 3 |
4 | 5 | ## 6.1.1 설계 단계 6 | 7 | 설계자는 8 | (1) 응용 프로그램의 사용자와 상호작용하여 요구 조건을 이해하고, 9 | (2) 사용자가 이해할 수 있도록 상위 모델로 나타내야 하며, 10 | (3) 요구 조건을 설계의 하위 단계에 알맞게 변형해야 한다. 11 | 12 |
13 | 14 | 1. 장래의 데이터베이스 사용자가 필요로 하는 데이터를 충분히 규정해야 한다. 15 | 16 | - 이 단계의 결과물은 `사용자 요구 사항 명세서(specification of user requirement)`이다. 17 | 18 |
19 | 20 | 2. **개념적 설계(conceptual design) 단계** 21 | 22 | - 설계자는 데이터 모델을 선택하고, 선택한 데이터 모델의 개념을 적용함으로써 이러한 요구 사항을 데이터베이스의 개념 스키마로 변환한다. 23 | - 일반적으로 이 단계에서 `개체-관계 다이어그램(E-R diagram, ERD`)을 생성한다. 24 | - `개체-관계(E-R) 모델`은 일반적으로 개념적 설계를 표현한다. 25 | - `개념 스키마`는 데이터베이스의 모든 개체 집합, 개체의 속성, 개체들 간의 관계, 개체와 관계에 대한 제약 조건을 명시한다. 26 | - 완전히 개발된 개념 스키마는 조직의 기능적인 요구 사항을 보여준다. 27 | - `기능적 요구 사항 명세서(specification of functional requirement)`는 사용자가 데이터에 적용할 연산(혹은 트랜잭션)의 종류를 기술한다. 28 | e.g., 데이터 수정 도는 갱신, 특정 데이터 검색 및 추출(retrieve), 데이터 삭제 등 29 | - 설계자는 개념적 설계 단계에서 스키마를 재검토하여 기능적인 요구 사항을 만족하는지 확인한다. 30 | 31 |
32 | 33 | 추상 데이터 모델(abstract data model)로부터 데이터베이스 구현으로 이동하는 과정은 마지막 두 가지 설계 단계로 구성된다. 34 | 35 |
36 | 37 | 3. **논리적 설계 단계(logical-design phase)** 38 | 39 | - 설계자는 상위의 개념 스키마를 사용할 데이터베이스의 구현 데이터 모델에 대응시킨다. 40 | - 구현 데이터 모델은 일반적으로 관계형 데이터 모델이며, 이 단계는 개체-관계 모델로 정의한 개념적 스키마를 관계형 스키마로 대응시키는 작업으로 구성된다. 41 | 42 |
43 | 44 | 4. **물리적 설계 단계(physical-design phase)** 45 | 46 | - 시스템 특유의 데이터베이스 스키마를 이용하여 데이터베이스의 물리적 특성을 구체화한다. 47 | - 이러한 물리적 특성은 파일 구성(file organization)의 형식과 인덱스 구조에 대한 선택을 포함한다. *(13, 14장에서 다룸)* 48 | 49 |
50 | 51 | --- 52 | 53 |
54 | 55 | - 데이터베이스의 물리적 스키마는 응용 프로그램이 완성된 후 상대적으로 쉽게 바꿀 수 있다. 56 | - 논리적 스키마를 바꾸는 것은 응용 프로그램 코드에 흩어져 있는 많은 질의와 갱신 작업에 영향을 미칠 수 있으므로 실행하기 어렵다. 57 | 58 | 따라서 데이터베이스 응용 프로그램의 나머지 부분을 완성하기 전에 데이터베이스 설계 단계를 주의해서 수행하는 것이 중요하다. 59 | 60 |
61 |
62 | 63 | ## 6.1.2 설계 대안 64 | 65 | > `개체(entity)` : 식별할 수 있는 항목을 지칭하는 데 사용한다. 66 | 67 | 다양한 개체는 여러 가지 방법으로 다른 개체와 관계를 맺는데, 이런 관계도 데이터베이스 설계 시 포착해야 한다. 68 | 69 |
70 | 71 | 데이터베이스 스키마를 설계할 때 다음 두 가지 중요한 **위험성**을 피할 수 있도록 확인해야 한다. 72 | 73 | ### 1️⃣ 중복성(Redundancy) 74 | 75 | > 좋지 않은 설계는 정보를 여러 번 반복한다. 76 | 77 | 정보의 중복적인 표현이 지니는 가장 큰 문제는 78 | 중복되어 저장한 모든 복사본을 수정할 수있는 예방책을 세우지 않음으로 인해 **어떤 일부 복사본이 일관되지 않은 저보를 지닐 수도 있다는 것이다.** 79 | 80 | 이상적으로, 정보는 정확히 한 장소에만 위치해야 한다. 81 | 82 |
83 | 84 | ### 2️⃣ 불완전성(Incompleteness) 85 | 86 | > 좋지 않은 설계는 조직의 특성을 모델링하기 어렵거나 불가능하게 한다. 87 | 88 | e.g., 89 | 90 | - 분반(section, 각 과목의 개설 방식)에 해당하는 개체만 있고 과목에 해당하는 개체는 없다고 가정해보자. 91 | - 과목이 제공하는 각각의 분반에 대해서 한 번씩 모든 과목 정보를 중복 저장하는 단일 릴레이션이 있다고 가정해보자. 92 | 93 | 이런 상황에서 어떤 새로운 과목에 대해 기술하고자 할 때, 그 과목이 개설되지 않으면 그 과목에 대한 정보를 저장하는 것은 불가능하다. 94 | 95 | 분반 정보에 대해 널 값을 저장하는 (문제 있는) 설계는 그다지 좋은 방법이 아닐 뿐만 아니라, 주 키 제약 조건에 의해 금지되어 있다. 96 | -------------------------------------------------------------------------------- /Part_02/Chapter_06/6.2 개체-관계 모델/README.md: -------------------------------------------------------------------------------- 1 | # 6.2 개체-관계 모델 2 | 3 |
4 | 5 | > `개체-관계(E-R) 데이터 모델(entity-relationship data model)`은 6 | > 데이터베이스의 전체 논리 구조를 나타내는 조직의 스키마(enterprise schema)를 명시함으로써 데이터베이스 설계를 쉽게 하도록 개발되었다. 7 | 8 | - E-R 데이터 모델은 세 가지 기본 개념인 개체 집합, 관계 집합, 속성을 가지고 있다. 9 | - E-R 모델은 `E-R 다이어그램(diagram)`이라는 연관된 다이어그램 형태의 표현을 지닌다. 10 | 11 |
12 |
13 | 14 | ## 6.2.1 개체 집합 15 | 16 | > `개체(entity)`는 실세계에서 다른 모든 객체와 구별되는 유무형의 사물이다. 17 | 18 | - 개체는 구체적인 것(사람이나 책)일 수도 있고, 추상적인 것(과목, 분반, 예약)일 수도 있다. 19 | 20 | 21 | - **개체는 속성의 집합을 가지며, 속성 중 일부 집합은 개체를 고유하게 구별하기도 한다.** 22 | - `속성(attribute)` : 개체 집합의 구성원들이 소유하는 설명 특성 23 | - e.g., 과목(course) 개체 집합의 가능한 속성 : course_id(과목 번호), title(제목), dept_name(학과명), credits(학점) 24 | - 어떤 개체 집합에 대해서 속성을 부여한다 = 데이터베이스가 개체 집합 내의 각 개체와 관련해 비슷한 정보를 저장한다. 25 | 26 | 27 | - 각 개체는 속성 각각에 대해 `값(value)`을 가진다. 28 | 29 |
30 | 31 | > `개체 집합(entity set)`은 같은 속성을 공유하는 **같은 유형의 개체의 집합**이다. 32 | 33 | - 개체 집합은 서로 중첩될 수도 있다. 34 | - e.g., 어떤 대학교의 모든 사람의 개체 집합 person에서, 35 | 어떤 person 개체는 instructor 개체이거나 student 개체이거나, 양쪽 모두이거나, 양쪽 어디에도 속하지 않을 수 있다. 36 | 37 | 38 | - E-R 다이어그램에서 **사각형**으로 표현하며 두 부분을 가진다. 39 | 1. 개체 집합의 이름을 포함한다. 40 | 2. 개체 집합의 모든 속성 이름을 포함한다. 41 | - 주 키를 구성하는 속성은 밑줄이 그어져 있다. 42 | 43 |

개체 집합 44 | 45 |
46 |
47 | 48 | 역사적으로 많은 조직은 개인을 고유하게 식별하는 속성으로 정부에서 발급한 식별 번호를 편리하게 사용했다. 49 | 50 | 그러나 이는 보안 및 사생활 보호 측면에서 나쁜 관행이다. 51 | 52 | **→ 일반적으로 각 개체를 유일하게 구별하는 식별자를 생성하고 할당한다.** 53 | 54 |
55 | 56 | 데이터베이스는 개체 집합의 모임을 포함하는데, 그 각각은 같은 유형의 개체를 임의의 수만큼 포함한다. 57 | 58 |
59 |
60 | 61 | ## 6.2.2 관계 집합 62 | 63 | > `관계(relationship)`는 여러 개체들 사이의 연관성이다. 64 | 65 | > `관계 집합(relationship set)`은 같은 유형의 관계들의 집합이다. 66 | 67 |
68 | 69 | e.g., instructor와 student 70 | 71 | 학생과 지도교수 역할을 하는 교수 사이의 연관성을 표현하기 위해 관계 집합 advisor를 정의할 수 있다. 72 | 73 |

관계 집합 74 | 75 |
76 |
77 | 78 | > E-R 스키마에서 `관계 인스턴스(relationship instance)`는 모델링하는 실세계 조직 내의 명명된 개체들 사이에 존재하는 연관성을 나타낸다. 79 | 80 | e.g., instructor 개체 Katz(instructor ID = 45565)와 학생 개체 Shankar(학생 ID = 12345)는 advisor 관계 인스턴스에 참여한다. 81 | 82 | 이 관계 인스턴스는 대학교에서 교수 Katz가 학생 Shankar를 지도하고 있음을 나타낸다. 83 | 84 |
85 | 86 | 관계 집합은 E-R 다이어그램에서 **다이아몬드**로 표시하며, 여러 다른 개체 집합(사각형)을 **선**으로 연결한다. 87 | 88 |

관계 집합 다이어그램 89 | 90 |
91 |
92 |
93 | 94 | 형식적으로 `관계 집합`은 n ≥ 2개의 개체 집합(중복 허용) 사이의 수학적 릴레이션이다. 95 | 96 | 만약 E1, E2, …. , En이 **개체 집합**일 때 **관계 집합 R**은 97 | 98 |

관계 집합 R 99 | 100 | 의 부분집합이다. 여기서 (e1, e2, … , en)은 **관계 인스턴스**다. 101 | 102 |
103 | 104 | **개체 집합 사이의 연관**을 `참여(participation)`라 한다. 105 | 106 | 즉, 개체 집합 E1, E2, … , En은 관계 집합 R에 `참여(participate)`한다. 107 | -------------------------------------------------------------------------------- /Part_02/Chapter_06/6.4 대응 카디널리티/README.md: -------------------------------------------------------------------------------- 1 | # 6.4 대응 카디널리티 2 | 3 |
4 | 5 | > `대응 카디널리티(mapping cardinality)` 혹은 `카디널리티 비율(cardinality ratio)`은 6 | > 관계 집합을 통해 **다른 개체와 관련될 수 있는 개체의 수**를 나타낸다. 7 | 8 |
9 | 10 | 개체 집합 A와 B 사이의 이진 관계 집합 R에서 대응 카디널리티는 다음 중 하나여야 한다. 11 | 12 | - 일대일 13 | - 일대다 14 | - 다대일 15 | - 다대다 16 | 17 |
18 | 19 | 어떤 관계 집합의 적절한 대응 카디널리티는 그 관계 집합이 모델링하는 실세계의 상황을 따라야 한다. 20 | 21 |
22 | 23 | ### 일대일(One-to-one) 24 | 25 | A의 한 개체는 B의 **최대** 하나의 개체와 연관을 가지고, B의 한 개체는 A의 **최대** 하나의 개체와 연관을 가진다. 26 | 27 |

일대일 28 | 29 |
30 |
31 | 32 | ### 일대다(One-to-many) 33 | 34 | A의 한 개체는 임의의 수(0 또는 그 이상)의 B의 개체와 연관을 가진다. 35 | 36 | 그러나 B의 한 개체는 A의 **최대** 하나의 개체하고만 연관을 갖는다. 37 | 38 |

일대다 39 | 40 |
41 |
42 | 43 | ### 다대일(Many-to-one) 44 | 45 | A의 한 개체는 B의 최대 한 개체와 연관을 갖는다. 46 | 47 | 그러나 B의 한 개체는 A의 임의의 수(0 또는 그 이상)의 개체와 연관을 갖는다. 48 | 49 |

다대일 50 | 51 |
52 |
53 | 54 | ### 다대다(Many-to-many) 55 | 56 | A의 한 개체는 임의의 수(0 또는 그 이상)의 B의 개체와 연관을 갖고 57 | B의 한 개체도 임의의 수(0 또는 그 이상)의 A의 개체와 연관을 갖는다. 58 | 59 |

다대다 60 | 61 |
62 |
63 |
64 | 65 | ## 관계 집합의 대응 카디널리티 표현 66 | 67 | E-R 다이어그램 표기법에서 관계 집합과 연관된 개체 집합 사이에 방향을 가진 `화살표(→)`나 `직선(-)`을 이용하여 관계에 대한 카디널리티 제약을 표시한다. 68 | 69 | 화살표는 관계의 “일” 쪽으로 그린다. 70 | 71 |
72 | 73 |

관계 집합의 대응 카디널리티 표현 74 | -------------------------------------------------------------------------------- /Part_02/Chapter_06/6.5 주 키/README.md: -------------------------------------------------------------------------------- 1 | # 6.5 주 키 2 | 3 |
4 | 5 | 주어진 개체 집합 내의 개체와 주어진 관계 집합 내의 관계를 구별하는 방법을 명세하는 방법이 있어야 한다. 6 | 7 |
8 | 9 | ## 6.5.1 개체 집합 10 | 11 | > 한 개체를 표현하는 속성의 값은 그 개체를 유일하게 구별(uniquely identify)할 수 있어야 한다. 12 | 13 | 한 개체 집합에서 모든 속성의 값이 정확히 동일한 두 개의 객체가 존재하면 안 된다. 14 | 15 |
16 | 17 | 2.3절에서 정의한 바와 같이, 어떤 릴레이션 스키마에 대한 `키`의 개념은 개체 집합에 직접적으로 적용된다. 18 | 19 | **즉, 어떤 개체에 대한 키는 각각의 개체를 서로 구별해주기에 충분한 속성의 집합인 것이다.** 20 | 21 | 수퍼 키, 후보 키, 주 키는 릴레이션 스키마에 적용 가능한 것과 마찬가지로 개체 집합에도 적용 가능하다. 22 | 23 |
24 |
25 | 26 | ## 6.5.2 관계 집합 27 | 28 | `키`는 또한 관계를 유일하게 식별하고, 서로 구별해준다. 29 | 30 | > 관계 집합은 관계 인스턴스의 집합이며, 각 인스턴스는 참여하는 개체에 의해 고유하게 식별할 수 있다. 31 | 32 |
33 |
34 | 35 | ## 6.5.3 약한 개체 집합 36 | 37 | `약한 개체 집합(weak entity set)`은 `식별 개체 집합(identifying entity set)`이라 하는 **다른 개체 집합에 의존하여 존재**하는 개체 집합이다. 38 | 39 |
40 | 41 | 주 키를 약한 개체와 연결하는 대신, 42 | 식별 개체의 주 키와 `구별자 속성(discriminator attribute)`을 함께 사용하여 **약한 개체를 유일하게 식별한다.** 43 | 44 |
45 | 46 | > 모든 약한 개체는 `식별 개체(identifying entity)`와 연관되어야 한다. 47 | 48 | 즉, 약한 개체 집합은 식별 개체 집합에 존재 종속적(existence dependent)이다. 49 | 50 | - 식별 개체 집합은 그것이 식별하는 약한 개체 집합을 소유한다(own)고 말한다. 51 | - 약한 개체 집합과 식별 개체 집합을 연관 짓는 관계를 `식별 관계(identifying relationship)`라 부른다. 52 | 53 |
54 | 55 | > 식별 관계는 약한 개체 집합으로부터 식별 개체 집합으로 `다대일 관계`이고, 약한 개체 집합은 식별 관계에 전체 참여한다. 56 | 57 |
58 | 59 | E-R 다이어그램에서 약한 개체 집합은 **이중 사각형**으로 표시하며, 구별자는 실선이 아닌 점선으로 밑줄이 그어져 있다. 60 | 61 | 약한 개체 집합을 식별 (강한) 개체 집합에 연관 짓는 관계 집합은 **이중 다이아몬드**로 표현한다. 62 | 63 | 또한 약한 개체 집합의 관계에 대한 전체 참여를 표시하기 위해 **이중선**을 사용한다. 64 | 65 |

약한 개체 집합 66 | 67 |
68 |
69 | 70 | **일반적으로 약한 개체 집합은 식별 관계 집합에 전체 참여해야 하며, 식별 개체 집합으로 다대일 관계다.** 71 | -------------------------------------------------------------------------------- /Part_02/Chapter_07/7.1 좋은 관계형 설계의 특징/README.md: -------------------------------------------------------------------------------- 1 | # 7.1 좋은 관계형 설계의 특징 2 | 3 |
4 | 5 | 예를 들어, 대학교 조직을 위한 데이터베이스를 설계할 대 in_dep 스키마로 시작했다고 가정하자. 6 | 7 | 이는 두 릴레이션 instructor와 department를 자연 조인(natural join)한 결과를 나타낸다. 8 | 9 | ```sql 10 | in_dep 11 | (ID, name, salary, dept_name, building, budget) 12 | ``` 13 | 14 |
15 | 16 | 이 방법은 더 적은 수의 조인을 이용하여 질의를 표현할 수 있으므로 좋은 방법처럼 보이지만, 17 | E-R 설계 대상인 대학교 조직에 대한 여러 사실을 생각해보면 그렇지 않다. 18 | 19 |
20 | 21 | 1. 학과 정보인 건물(building)과 예산(budget)을 학과 내의 각 교수에 대해서 반복해야 한다. (**중복성** 문제) 22 | 23 | 24 | 2. 같은 학과 교수에 대한 튜플이 동일한 예산 액수를 가져야 한다. 25 | - 그렇지 않으면 데이터베이스가 **일관성**을 잃게 된다. 26 | 27 | 28 | 3. 대학교 내에 새로운 학과를 하나 만든다고 하면, 29 | 학과에 교수가 적어도 한 명 이상 존재하지 않는다면 학과의 (dept_name, building, budget)에 관한 정보를 직접적으로 나타낼 수 없다. 30 | - 즉, building과 budget에 대해서 널 값을 가지는 튜플을 생성해야 한다. 31 | 32 |
33 |
34 | 35 | ## 7.1.1 분해 36 | 37 | in_dep 스키마에서 정보의 반복 문제를 방지하는 유일한 방법은 두 개의 스키마(instructor와 department 스키마)로 `분해(decomposition)`하는 것이다. 38 | 39 |
40 | 41 | > 일반적으로 **정보의 반복이 나타나는 스키마를 여러 개의 작은 스키마로 분해한다**고 기억하자. 42 | 43 |
44 | 45 | ### 손실 분해 46 | 47 | > 하지만 스키마를 분해하는 것이 항상 도움이 되는 것은 아니다. 48 | 49 |
50 | 51 | 예를 들어, 아래의 employee 스키마를 분해하기로 결정했다고 해보자. 52 | 53 | ```sql 54 | employee 55 | (ID, name, street, city, salary) 56 | ``` 57 | 58 | 이는 다음과 같은 두 스키마로 분해할 수 있다. 59 | 60 | ```sql 61 | employee1 62 | (ID, name) 63 | employee2(name, street, city, salary) 64 | ``` 65 | 66 | 이 분해의 문제점은 이 조직에 동명이인이 있을 때 발생한다. 67 | 68 |
69 | 70 | 아래 그림은 두 튜플, 분해한 두 스키마가 포함하는 튜플, 분해한 두 스키마에 자연 조인을 적용하여 원래의 튜플을 생성했을 때의 결과를 보여준다. 71 | 72 |

손실 분해 73 | 74 |
75 |
76 | 77 | 최종 결과는 Kim이라는 이름을 가진 본래의 두 튜플과 이 튜플에 속한 값을 잘못 혼합한 새로운 두 튜플을 추가로 포함하고 있는 것을 알 수 있다. 78 | 79 | **분해 스키마를 자연 조인한 결과가 더 많은 튜플을 가지고 있음에도 불구하고,** 80 | 어떤 도로, 도시, 급여가 Kim이라는 이름을 가진 누군가에게 속함은 파악할 수 있으나 두 Kim 중에 누구에게 속하는지는 구별할 수 없기 때문에 81 | **실제로는 정보를 덜 가지고 있다.** 82 | 83 | 따라서 위의 분해는 대학교 지원에 대한 어떤 중요한 사실을 표현할 수 없다. 84 | 85 |
86 | 87 | 이러한 분해를 `손실 분해(lossy decomposition)`이라고 부르며, 이처럼 중요한 사실을 다 표현하지 못하는 분해를 피해야 한다. 88 | 89 |
90 |
91 | 92 | ## 7.1.2 무손실 분해 93 | 94 | R를 관계 스키마라 하고, R1과 R2는 R의 분해라고 하자. 95 | 96 | 즉, R, R1, R2는 속성의 집합이고, **R= R1 ⋃ R2로 분해하여 대체할 때 정보 손실이 없다면** 그 분해는 `무손실 분해(lossless decomposition)`라고 한다. 97 | 98 |
99 | 100 | 릴레이션 r(R)의 인스턴스 대신 r1(R1)과 r2(R2)의 인스턴스를 사용해야만 하는데, 101 | 이때 **r1(R1)과 r2(R2)의 인스턴스가 표현할 수 없는 정보를 r(R) 인스턴스가 가지고 있는 경우 정보의 손실이 발생한다.** 102 | 103 |
104 | 105 | > 모든 적법한(legal, 7.2.2절에서 정의함) 데이터베이스 인스턴스에 대해서 106 | > 릴레이션 r이 다음 SQL 질의의 결과와 동일한 튜플의 집합을 포함하는 경우 무손실 분해라고 한다. 107 | 108 | ```sql 109 | select * 110 | from (select R1 from r) 111 | natural join (select R2 from r) 112 | ``` 113 | 114 |
115 | 116 | 즉, 릴레이션 r에 대해 R1, R2를 각각 추출(project)하고, 이 추출 결과에 대해 자연 조인을 계산하면 다시 정확히 r를 얻는다. 117 | 118 | 반대로, 추출 결과의 자연 조인을 계산할 때 원래 릴레이션의 적절한 확대 집합(superset)을 얻는다면 이 분해는 손실 분해다. 119 | 120 |
121 |
122 | 123 | ## 7.1.3 정규화 이론 124 | 125 | 관계형 데이터베이스를 설계하는 방법은 일반적으로 `정규화(normalization)`로 알려진 절차를 따르는 것이다. 126 | 127 | > 목표는 **불필요한 중복 없이 정보를 저장하고 쉽게 검색할 수 있도록** 릴레이션 스키마의 집합을 생성하는 것이다. 128 | 129 |
130 | 131 | ### 접근 방식 132 | 133 | - 주어진 릴레이션 스키마가 ‘좋은 형식’인지 결정한다. (7.3절에서 다룸, 다양한 형식(`정규형`)이 존재함) 134 | - 주어진 릴레이션 스키마가 ‘좋은 형식’이 아닌 경우, 이를 여러 개의 더 작은 릴레이션 스키마로 분해하여 각 릴레이션 스키마는 적절한 정규형이 되도록 한다. 135 | - 이때 적용한 분해는 **무손실 분해**여야 한다. 136 | -------------------------------------------------------------------------------- /Part_02/Chapter_07/7.2 함수 종속을 사용한 분해/README.md: -------------------------------------------------------------------------------- 1 | # 7.2 함수 종속을 사용한 분해 2 | 3 |
4 | 5 | 데이터베이스는 실제 세계의 개체(entity)와 관계(relationship)의 집합을 모델링하며, 일반적으로 실제 세계의 데이터에는 다양한 제약 조건(규칙)이 있다. 6 | 7 | e.g., 8 | 9 | - 각각의 학생과 교수는 하나의 이름만 가진다. 10 | - 각각의 학과는 하나의 예산 값을 가지며, 하나의 건물에만 연결되어 있다. 11 | 12 |
13 | 14 | 모든 실제 세계의 제약 조건을 만족하는 릴레이션의 인스턴스를 `적법한(legal) 릴레이션`이라고 한다. 15 | 16 | 모든 릴레이션 인스턴스가 적법한 인스턴스일 때 데이터베이스에 대한 `적법한 인스턴스(legal instance)`가 된다. 17 | 18 |
19 |
20 |
21 | 22 | # 7.2.1 표기 관습 23 | 24 | - 속성의 집합으로 그리스 문자(a.g., α)를 쓰며, 릴레이션 스키마를 참조하기 위해 로마 대문자를 쓴다. 25 | 26 | 27 | - 릴레이션 이름은 소문자로 표기한다. 28 | 29 | 30 | - `스키마 R`가 `릴레이션 r`를 위한 것임을 표기하기 위해 `r(R)` 표기법을 사용한다. 31 | - r(R) 표기법을 사용하면 릴레이션과 스키마 둘 다 참조한다. 32 | - 릴레이션 스키마는 속성의 집합이지만, 모든 속성의 집합이 스키마인 것은 아니다. 33 | 34 | 35 | - 릴레이션은 어떤 주어진 시간에 특정한 값, 즉 인스턴스를 가질 수 있다. → ‘`r의 인스턴스다`’ 36 | 37 | 38 | - 속성의 집합이 수퍼 키일 때 그것을 K로 나타낸다. → ‘`K는 r(R)의 수퍼 키다`’ 39 | 40 |
41 |
42 |
43 | 44 | # 7.2.2 키와 함수 종속 45 | 46 | 실제 세계 제약 조건 중에서 가장 널리 쓰이는 유형은 `키(수퍼 키, 후보 키, 주 키)` 또는 `함수 종속`으로 표현할 수 있다. 47 | 48 |
49 |
50 | 51 | ## 수퍼 키 52 | 53 | 2.3절에서는 수퍼 키에 대하여, **릴레이션에서 튜플을 유일하게 식별하게 해 주는 하나 혹은 그 이상의 속성의 전체적인 집합**으로 정의했다. 54 | 55 |
56 | 57 | 주어진 r(R)에 대해 R의 부분집합 K는 다음의 조건을 만족하면 r(R)의 `수퍼 키(superkey)`다. 58 | 59 | 조건 : 만약 r(R)의 어떠한 적법한 인스턴스에서, r의 인스턴스에 존재하는 모든 튜플의 쌍 t1과 t2에 대해 t1 ≠ t2이면 t1[K] ≠ t2[K]가 성립해야 한다. 60 | 61 | > 즉, 어떠한 r(R)의 적법한 인스턴스에 존재하는 서로 다른 두 개의 튜플은 **속성 집합 K에서 동일한 값을 가질 수 없다**는 뜻이다. 62 | 63 | → K개의 값이 r에서 튜플을 유일하게 식별한다. 64 | 65 |
66 |
67 | 68 | ## 함수 종속 69 | 70 | 수퍼 키는 전체 튜플을 유일하게 식별하는 속성의 집합인 반면, `함수 종속`은 **어떤 속성들의 값을 유일하게 식별하는 제약 조건**을 표현한다. 71 | 72 |
73 | 74 | 릴레이션 스키마 r(R), α ⊆ R, β ⊆ R 75 | 76 | > 주어진 r(R)의 인스턴스에 대해, 77 | > 인스턴스 내의 모든 튜플의 쌍 t1과 t2가 ‘**t1[α] = t2[β]이면, t1[α] = t2[β]이다**’라는 조건을 만족한다면 78 | > 인스턴스는 `함수 종속 α → β`를 만족한다고 한다. 79 | 80 | > 만약 모든 적법한 r(R)의 인스턴스가 함수 종속을 만족한다면, 스키마 r(R) 위에서 `함수 종속 α → β를 보존(성립, 유지, 만족)한다`고 한다. 81 | 82 |
83 | 84 | - r(R)에서 함수 종속 K → R이 성립한다면 K는 r(R)의 수퍼 키이다. 85 | - 즉, r(R)의 모든 적법한 인스턴스에 대해 86 | 인스턴스 내의 임의의 튜플 t1과 t2의 모든 쌍이 t1[K] = t2[K]를 만족하면 언제나 t1[R] = t2[R]이기 때문에(즉, t1 = t2), K는 수퍼 키다. 87 | 88 |
89 | 90 | 우리는 두 가지 방법으로 함수 종속을 사용한다. 91 | 92 | 1. 릴레이션의 인스턴스가 주어진 함수 종속의 집합 F를 만족하는지 `검사`하기 위해 사용한다. 93 | 2. 적법한 릴레이션의 집합에 대한 제약 조건을 명시하기 위해 사용한다. 94 | - 우리는 주어진 함수 종속의 집합을 만족하는 릴레이션 인스턴스에만 관심을 기울인다. 95 | - 함수 종속 집합 F를 만족하는 스키마 r(R)의 릴레이션만으로 제한한다면, 96 | F는 r(R)를 `보존`(성립, 유지, 만족)한다고 말한다. 97 | 98 |
99 | 100 | ### e.g., 101 | 102 |

릴레이션 r 103 | 104 |
105 | 106 | 1. A → C가 만족된다. 107 | - A의 값이 a1인 두 개의 튜플은 동일한 C의 값, c1을 가진다. 108 | - A의 값이 a2인 두 개의 튜플은 동일한 C의 값, c2를 가진다. 109 | 110 | 111 | 2. 함수 종속 C → A는 성립되지 않는다. 112 | - 튜플 t1(a2, b3, c2, d3)과 t2(a3, b3, c2, d4) 113 | - t1[C] = t2[C]이지만 t1[A] ≠ t2[A]이기 때문이다. 114 | 115 |
116 | 117 | ### trivial 118 | 119 | > **α → β** 형태의 함수 종속은 **β ⊆ α**이면 `자명하다(trivial)`고 한다. 120 | 121 | e.g., 122 | 123 | A → A : A라는 속성을 지니는 모든 릴레이션이 만족한다. 124 | 125 | 즉, 임의의 튜플 t1과 t2로 구성한 모든 쌍에서 ’t1[A] = t2[A]이라면, t1[A] = t2[A]임을 만족해야 한다’는 것이며 이는 당연히 성립하는 수식이다. 126 | 127 |
128 | 129 | --- 130 | 131 |
132 | 133 | > 어떤 특정 릴레이션의 스키마가 만족하지 않는 함수 종속을 특정 시점의 릴레이션의 인스턴스가 보존할 수도 있다. 134 | 135 | e.g., 136 | 137 | classroom 릴레이션에서 `room_number → capacity`가 만족한다. 138 | 139 | - 하지만 실세계에서는 다른 건물에 있는 두 강의실이 동일한 강의실 번호를 가지지만 수용인원은 다를 수 있다. 140 | - 따라서 언젠가 room_number → capacity가 만족되지 않는 인스턴스가 나타날 수 있기 때문에 141 | room_number → capacity는 classroom 릴레이션 스키마가 `보존`하는 함수 종속 집합에 포함되지 않는다. 142 | - 그러나 `building, room_number → capacity`는 classroom 스키마에서 성립함을 예상할 수 있다. 143 | 144 |
145 | 146 | ### 함수 종속의 추론 147 | 148 | > 주어진 함수 종속의 집합 F가 릴레이션 r(R)에 대해 성립한다고 하면, 149 | > 다른 어떤 함수 종속 또한 그 릴레이션에 대해 성립한다는 것을 **추론**해 낼 수 있다. 150 | 151 | e.g., 152 | 153 | 주어진 스키마 r(A, B, C)에서 만약 함수 종속 A → B, B → C가 r에 대해 성립한다면 함수 종속 A → C 또한 r에 대해 성립함을 추론할 수 있다. 154 | 155 | A의 어떤 값에 대응하는 B의 값은 오직 하나이고, B의 그 값에 대해서도 C에 대응하는 값은 오직 하나이기 때문이다. 156 | 157 |
158 | 159 | ### 폐포(closure) 160 | 161 | 함수 종속 집합 F의 `폐포(closure)`는 **주어진 집합 F로부터 추론할 수 있는 모든 함수 종속의 집합**을 의미한다. 162 | 163 | 이는 `F+`라고 표현하며, F+는 F의 모든 함수 종속을 기본적으로 포함한다. 164 | -------------------------------------------------------------------------------- /Part_02/Chapter_07/7.3 정규형/README.md: -------------------------------------------------------------------------------- 1 | # 7.3 정규형 2 | 3 |
4 | 5 | 관계형 데이터베이스를 설계하는 데 사용할 수 있는 다양한 정규형이 존재한다. 6 | 7 | - `제1정규형` : 분해가 아닌 속성의 도메인과 관련된다. (7.8절) 8 | - `제2정규형` : 역사적으로만 중요성을 지니고 실제로는 제3정규형 또는 BCNF 중 하나가 항상 더 좋은 선택이다. (책에서는 생략되었음) 9 | - `BCNF` 10 | - `제3정규형` 11 | 12 |
13 |
14 |
15 | 16 | # 7.3.1 보이스-코드 정규형 17 | 18 | `보이스-코드 정규형(Boyce-Codd Normal Form, BCNF)`은 **함수 종속을 기반으로 발견할 수 있는 모든 중복을 제거**하지만, 다른 유형의 중복이 남을 수 있다. 19 | 20 |
21 | 22 | ## 7.3.1.1 정의 23 | 24 | R는 스키마, F는 함수 종속의 집합이라고 하자. 25 | 26 |
27 | 28 | 만약 **α ⊆ R이고 β ⊆ R인 α → β 형태의 F+의 모든 함수 종속**이 다음 중 적어도 하나라도 만족한다면 29 | 함수 종속의 집합 F와 관련하여 릴레이션 스키마 R는 BCNF에 있다. 30 | 31 | - α → β가 자명한(trivial) 함수 종속이다. (즉, β ⊆ α) 32 | - α가 스키마 R의 수퍼 키다. 33 | 34 |
35 | 36 | 설계를 구성하고 있는 모든 릴레이션이 BCNF에 속하면 그 데이터베이스 설계는 BCNF에 속한다. 37 | 38 |
39 | 40 | e.g., instructor 스키마는 BCNF에 속한다. 41 | 42 | `ID → name, dept_name, salary` (자명하지 않은 모든 함수 종속은 화살표 왼쪽에 ID를 포함하여 성립함) 43 | 44 | - ID는 instructor에 대한 수퍼 키다. (사실 이 경우는 주 키) 45 | - 즉, 화살표 왼쪽에 ID를 포함하지 않고 `name, dept_name, salary`의 조합만으로 구성된 자명하지 않은 함수 종속이 존재하지 않는다. 46 | - 따라서 instructor는 BCNF에 속한다. 47 | 48 |
49 | 50 | ### BCNF 형태가 아닌 스키마를 분해하는 규칙 51 | 52 | R가 BCNF가 아닌 스키마이며 자명하지 않은 함수 종속 α → β가 최소 한 개 존재하고, α는 R에 대한 수퍼 키가 아니라고 하자. 53 | 54 |
55 | 56 | 설계에서 R를 다음과 같은 두 개의 스키마로 대체할 수 있다. 57 | 58 | - (α ⋃ β) 59 | - (R - (β - α)) 60 | 61 |
62 | 63 | BCNF가 아닌 스키마를 분해할 때 그 결과로 나오는 스키마들 중 하나 혹은 그 이상은 BCNF가 아닐 수도 있다. 64 | 65 | 이럴 경우, 계속해서 분해를 수행하여 궁극적인 결과가 BCNF 스키마의 집합이 되도록 한다. 66 | 67 |
68 | 69 | --- 70 | 71 |
72 | 73 | e.g., 74 | 75 | ```sql 76 | in_dep (ID, name, salary, dept_name, building, budget) 77 | ``` 78 | 79 |
80 | 81 | 위 스키마의 경우, α와 β는 다음과 같다. 82 | 83 | α = dept_name 84 | 85 | β = { building, budget } 86 | 87 |
88 | 89 | in_dep는 다음과 같이 대체할 수 있다. 90 | 91 | - (α ⋃ β) = (dept_name, building, budget) 92 | - (R - (β - α)) = (ID, name, dept_name, salary) 93 | 94 |
95 |
96 | 97 | ## 7.3.1.2 BCNF와 종속성 보존 98 | 99 | 데이터베이스 일관성 제약 조건을 표현하기 위한 방법으로는 주 키 제약 조건, 함수 종속, check 제약 조건, 주장, 트리거 등이 있다. 100 | 101 | 데이터베이스가 갱신될 때마다 이러한 제약 조건을 검사하는 것은 큰 비용이 소모될 수 있기에, 102 | 제약 조건을 효과적으로 검사할 수 있는 방법으로 데이터베이스를 설계하는 것이 유용하다. 103 | 104 | > 여기서는 **BCNF로 분해하는 작업이 어떤 함수 종속을 효과적으로 검사하는 것을 방해할 수도 있다**는 것을 살펴본다. 105 | 106 |
107 | 108 | ``` 109 | BCNF can decompose “too much” 110 | ``` 111 | 112 |
113 | 114 | 예를 들어, 대학교 조직을 운용하는 방식에 변화를 준다고 가정해보자. 115 | 116 | - 원래 설계에서는 한 명의 학생이 반드시 단 한 명의 지도교수를 둘 수 있었다. (이는 student로부터 advisor로 다대일인 advisor 관계 집합에 기인함) 117 | - 이제 교수는 단일 부서에만 연관될 수 있고, 118 | **한 학생은 두 명 이상의 지도교수를 둘 수 있지만 주어진 학과에서는 최대 한 명만 가능하도록** 할 것이다. (복수 전공 제도를 도입) 119 | 120 |
121 | 122 | 이런 변화를 E-R 설계로 구현하는 한 가지 방법은 123 | `advisor 관계 집합`을 세 개의 개체 집합 instructor, student, department를 포함하는 `삼진 관계 집합 dept_advisor`로 대체하는 것이다. 124 | 125 |
126 | 127 |

dept_advisor 128 | 129 |
130 |
131 | 132 | dept_advisor 관계 집합을 다음 스키마로 변환할 수 있다. 133 | 134 | ```sql 135 | dept_advisor (s_ID, i_ID, dept_name) 136 | ``` 137 | 138 |
139 | 140 | E-R 다이어그램에는 구체적으로 명시되어 있진 않지만, 141 | ’**교수는 단 하나의 학과에서만 지도교수로 활동할 수 있다**’라는 추가적인 제약 조건이 있다고 가정해보자. 142 | 143 | 그러면 다음의 함수 종속은 dept_advisor에서 유지된다. 144 | 145 | ```sql 146 | i_ID → dept_name 147 | // '교수는 단 하나의 학과에서만 지도교수로 활동할 수 있다'는 요구 사항에서 나옴 148 | 149 | s_ID, dept_name → i_ID 150 | // '학생은 주어진 학과에 대해서 많아야 한 명의 지도교수를 둘 수 있다'는 요구 사항에서 나옴 151 | ``` 152 | 153 | **이 설계에서 교수가 dept_advisor 관계에 참여할 때마다 학과명을 반복해야 한다.** 154 | 155 |
156 | 157 | 따라서 `BCNF 분해 규칙`을 dept_advisor에 적용하면 다음을 얻을 수 있다. 158 | 159 | - (s_ID, i_ID) 160 | - (i_ID, dept_name) 161 | 162 |
163 | 164 | 두 스키마 모두 BCNF를 만족한다. 165 | 166 | > 하지만 함수 종속 `s_ID, dept_name → i_ID`에 나타나는 세 가지 속성을 포함하는 스키마는 존재하지 않는다. 167 | 168 | - 분해한 개별 릴레이션에 적용할 수 있는 유일한 종속성은 `i_ID → dept_name`이다. 169 | - `s_ID, dept_name → i_ID`는 분해된 릴레이션의 조인을 계산해야 검사할 수 있다. 170 | 171 |
172 | 173 | --- 174 | 175 |
176 | 177 | 위 설계는 조인 없이 이 함수 종속의 적용을 허용하지 않기 때문에 이 설계는 `종속성을 보존(dependency preserving)하지 않는다`고 말한다. 178 | 179 |
180 | 181 | > 종속성 보존을 보통 바람직한 것으로 간주하기 때문에, BCNF보다는 약하지만 종속성을 보존하는 다른 형태의 정규형을 고려할 필요도 있다. 182 | 183 | → `제3정규형` 184 | 185 |
186 |
187 |
188 | 189 | # 7.3.2 제3정규형 190 | 191 | BCNF은 모든 비자명한(nontrivial) 종속은 α → β의 형태여야 하고, 이때 α가 수퍼 키임을 요구한다. 192 | 193 | > `제3정규형(3NF)`은 **비자명한 함수 종속에 대해 그 좌측 항이 수퍼 키가 아닌 것도 허용**함으로써 제약 조건을 조금 완화했다. 194 | 195 |
196 | 197 | 릴레이션 스키마 R는 관련된 함수 종속들의 집합 F에 대해서 제3정규형(3NF)이라 하는데, 198 | 이때 α ⊆ R, β ⊆ R이며 α → β 형태를 갖는 F+의 모든 함수 종속이 다음 중 적어도 하나를 만족해야 한다. 199 | 200 | - α → β는 자명한 함수 종속이다. 201 | - α는 R의 수퍼 키다. 202 | - **β - α에 속한 각 속성 A는 R의 후보 키에 포함된다.** 203 | - 후보 키는 최소의 수퍼 키이다. 204 | - 단일 후보 키가 β - α의 모든 속성을 포함해야 한다는 것을 의미하는 것은 아니며, **β - α에 속하는 각 속성 A가 서로 다른 후보 키에 포함될 수 있다.** 205 | 206 |
207 | 208 | 세 번째 조건은 직관적이지도 않고, 이것이 왜 유용한지도 명확하지 않는데 209 | 이는 어떤 의미에서 **모든 스키마를 3NF로 종속성 보존 분해할 수 있도록 보장하기 위해 BCNF의 조건을 최소한으로 완화했음**을 나타낸다. 210 | 211 | 세 번째 조건의 목적은 3NF로의 분해에 대해 설명할 때 더 명확해질 것이다. (7.5.2절) 212 | 213 |
214 | 215 | --- 216 | 217 |
218 | 219 | > BCNF를 만족하는 스키마는 그것의 함수 종속 각각이 위의 두 가지 조건 중 하나를 만족하기 때문에 3NF를 만족한다. 220 | 221 | - 따라서 BCNF는 3NF보다 더 제한적이며 까다로운 조건을 가진 정규형이다. 222 | - 3NF의 정의는 BCNF가 허용하지 않는 어떤 함수 종속을 허용한다. 223 | 224 |
225 | 226 | 다음의 함수 종속을 가지는 dept_advisor 스키마를 다시 살펴보자. 227 | 228 | ```sql 229 | i_ID → dept_name 230 | // '교수는 단 하나의 학과에서만 지도교수로 활동할 수 있다'는 요구 사항에서 나옴 231 | 232 | s_ID, dept_name → i_ID 233 | // '학생은 주어진 학과에 대해서 많아야 한 명의 지도교수를 둘 수 있다'는 요구 사항에서 나옴 234 | ``` 235 | 236 |
237 | 238 | 앞서 `i_ID → dept_name`으로 인해 dept_advisor 스키마가 BCNF에 속하지 않는다고 하였다. 239 | 240 | - α = i_ID 241 | - β = dept_name 242 | - β - α = dept_name 243 | 244 | 함수 종속 `s_ID, dept_name → i_ID`는 dept_advisor에서 성립하고, 속성 dept_name은 후보 키에 포함되므로 dept_advisor는 3NF에 속한다. 245 | 246 | > 즉, 세 번째 조건은 redundancy를 허락하는 조건이다. 247 | 248 |
249 |
250 |
251 | 252 | # 7.3.3 BCNF와 3NF의 비교 253 | 254 | 관계형 데이터베이스 스키마에 대한 두 개의 정규형 3NF와 BCNF 중에서 255 | **무손실 또는 종속성 보존을 희생하지 않고 항상 3NF 설계를 얻을 수 있다**는 점에서 3NF가 좀 더 유용하다고 말할 수 있다. 256 | 257 | 그럼에도 불구하고, 3NF는 데이터 항목 간의 생길 수 있는 몇몇 의미적인 연관성을 표현하기 위해 **null 값**을 사용해야 할 수도 있으며, 258 | **정보 반복 문제**도 가지고 있다. 259 | 260 |
261 | 262 | 함수 종속을 사용하는 데이터베이스 설계의 목표는 다음과 같다. 263 | 264 | 1. BCNF 265 | 2. 무손실 266 | 3. 종속성 보존 267 | 268 |
269 | 270 | 세 가지를 모두 항상 만족할 수 있는 것은 아니기 때문에 BCNF 또는 종속성 보존을 위한 3NF를 선택해야 한다. 271 | -------------------------------------------------------------------------------- /Part_02/Chapter_07/7.8 원자적 도메인과 제1정규형/README.md: -------------------------------------------------------------------------------- 1 | # 7.8 원자적 도메인과 제1정규형 2 | 3 |
4 | 5 | E-R 모델은 개체 집합과 관계 집합이 `여러 단계의 하부 구조로 표현되는 속성`을 가지는 것을 허용한다. 6 | 7 | 특히 `다중값 속성`이나 `복합 속성`을 가지는 것을 허용한다. (아래 사진 참고) 8 | 9 | - 다중값 속성 : phone_number 10 | - 복합 속성 : address (구성요소 속성 street, city, state를 가짐) 11 | 12 |

다중값 속성, 복합 속성 13 | 14 |
15 |
16 |
17 | 18 | ## 제1정규형 19 | 20 | 관계형 모델에서 속성이 하부 구조를 가질 수 없다는 개념을 형식화했다. 21 | 22 |
23 | 24 | > **도메인의 원소가 나눌 수 없는 단위로 되어 있을 때** 그 도메인은 `원자적(atomic)`이라고 한다. 25 | 26 | > 릴레이션 스키마 R의 **모든 속성의 도메인이 원자적일 때** R이 `제 1정규형(first normal from, INF)`에 속한다고 한다. 27 | 28 |
29 | 30 | 중요한 쟁점은 도메인 자체가 무엇인가가 아니라 **도메인 원소를 데이터베이스에서 어떻게 사용하는가** 하는 점이다. 31 | 32 |
33 | 34 | e.g., 정수 35 | 36 | - 정수는 원자적으로 볼 수 있지만, 정수의 모든 집합의 집합은 원자적인 도메인이 아니다. 37 | - 만약 정수를 숫자의 정렬된 리스트라고 간주한다면, 모든 정수의 도메인은 원자적이 아닐 것이다. 38 | 39 |
40 | 41 | e.g., 직원 식별 번호 42 | 43 | ”CS0001”, “EE1127”처럼 처음 두 글자는 부서를 나타내며, 나머지 네 숫자는 그 부서 내에서 직원의 고유한 번호를 나타내는 형태로 44 | 직원 식별 번호를 부여하는 조직이 있다고 가정해보자. 45 | 46 | - 이 직원 식별 번호는 더 작은 단위로 나눌 수 있으므로 원자성을 갖지 않는다. 47 | - 따라서 만일 위와 같이 직원 식별 번호를 구성하는 속성을 지닌 릴레이션 스키마가 있다면 그 스키마는 제1정규형이 아니다. 48 | - 위 식별 번호를 사용하게 되면 발생하는 문제점 49 | - 식별 번호의 구조를 분해하는 코드를 작성해서 직원의 부서를 찾을 수 있는데 이 방식은 부가적인 프로그래밍이 필요하게 되며, 50 | 정보는 데이터베이스가 아닌 응용 프로그램에서 인코딩된다. 51 | - 때로는 식별 번호를 해석하는 코드가 잘못된 결과를 낼 수 있다. 52 | - 이런 식별 번호를 주 키로 사용한다면 직원이 부서를 옮길 경우 직원 식별 번호가 나타나는 모든 곳에서 수정이 이루어져야 한다. 53 | 54 |
55 | 56 | e.g., 과목 식별자 57 | 58 | “CS-101”를 사용하는 경우 “CS”가 컴퓨터 과학학과를 의미하므로, 이 식별자의 도메인은 원자적이 아닌 것처럼 보인다. 59 | 60 | - 이 도메인은 시스템을 사용하는 인간의 관점으로 볼 때 원자적이지 않다. 61 | - 그러나 식별자를 분할하여 식별자의 일부를 학과의 약어로 해석하는 시도를 하지 않는 한, 데이터베이스 응용 프로그램은 이 도메인을 원자적으로 취급한다. 62 | 63 | course 스키마는 학과 이름을 분리된 속성으로 저장하고 있어 데이터베이스 응용 프로그램은 과목 식별자의 특정 문자를 해석하는 대신 64 | 이 속성을 사용하여 과목의 학과 이름을 찾을 수 있기 때문에, 앞의 대학교 스키마는 제1정규형으로 간주할 수 있다. 65 | -------------------------------------------------------------------------------- /Part_05/Chapter_12/12.1 물리적 저장 장치 매체 개요/README.md: -------------------------------------------------------------------------------- 1 | # 12.1 물리적 저장 장치 매체 개요 2 | 3 | 저장 장치 매체는 `데이터에 접근하는 속도`, 해당 매체를 구매하기 위해 드는 `데이터 단위당 비용`, 그리고 `매체의 신뢰성`에 따라 분류할 수 있다. 4 | 5 | - 캐시, Cache 6 | - 메인 메모리, Main memory 7 | - 플래시 메모리, Flash memory 8 | - 자기 디스크 저장 장치, Magnetic-disk storage 9 | - 광학 저장 장치, Optical storage 10 | - 테이프 저장 장치, Tape storage 11 | 12 |
13 |
14 | 15 | ## 캐시, Cache 16 | 17 | - 저장 장치 중에서 가장 빠르고 비싸다. 18 | - 캐시 메모리는 크기가 상대적으로 작다. 19 | - 컴퓨터 시스템 하드웨어가 캐시의 사용을 관리한다. 20 | - 데이터베이스 시스템에서 캐시 저장 장치를 어떻게 관리하는지에 대해서는 신경을 쓸 필요는 없으나, 21 | 데이터베이스 시스템의 질의 처리 데이터 구조와 알고리즘을 설계하는 데 캐시 효과를 고려하는 것은 의미가 있다. 22 | 23 |
24 |
25 | 26 | ## 메인 메모리, Main memory 27 | 28 | - 연산에 사용할 데이터를 저장하기 위한 저장 장치이다. 29 | - 일반적으로, 매우 큰 데이터베이스에 대해서 그 전체를 저장하기에 메인 메모리는 너무 작거나 비싸지만, 30 | 많은 기업용 데이터베이스의 경우 메인 메모리에 모두 적재가 가능하다. 31 | - `휘발성(volatile)` : 메인 메모리의 내용은 정전이나 시스템 충돌이 발생하면 잃어버리게 된다. 32 | 33 |
34 |
35 | 36 | ## 플래시 메모리, Flash memory 37 | 38 | - `비휘발성(non-volatile)` : 메인 메모리와 달리 정전이 발생해도 데이터가 남아있다. 39 | - 메인 메모리에 비교해 바이트당 비용이 더 낮지만, 자기 디스크보다 바이트당 비용은 더 비싸다. 40 | 41 |
42 | 43 | ### SSD 44 | 45 | `솔리드 스테이트 드라이브(solid-state drive, SSD)`는 내부적으로 플래시 메모리를 사용하여 데이터를 저장하지만, 46 | 자기 디스크와 유사한 인터페이스를 제공하여 **데이터를 블록 단위로 저장하거나 검색할 수 있다.** 47 | 48 | → `블록 지향 인터페이스(block-oriented interface)` 49 | 50 |
51 |
52 | 53 | ## 자기 디스크 저장 장치, Magnetic-disk storage 54 | 55 | - 온라인으로 장기간 데이터를 저장하기 위한 주된 매체이다. 56 | - `하드 디스크 드라이브(hard disk drive, HDD)`라고도 한다. 57 | - `비휘발성(non-volatile)`이다. 58 | 59 |
60 | 61 | > 자기 디스크에 저장된 데이터에 접근하려면 시스템은 먼저 데이터에 접근할 수 있는 디스크에서 메인 메모리로 데이터를 이동시켜야 한다. 62 | > 그 다음, 시스템이 지정한 작업을 수행한 후 수정된 데이터를 디스크에 기록해야 한다. 63 | 64 |
65 |
66 | 67 | ## 광학 저장 장치, Optical storage 68 | 69 | - `DVD(Digital Video Disk)`는 레이저 광원을 사용하여 데이터를 쓰고 다시 읽는 광학 저장 매체다. 70 | - 이는 특정 데이터에 접근하는 데 필요한 시간이 자기 디스크에 걸리는 시간에 비교해 상당히 길 수 있으므로, 71 | 활성 중인 데이터베이스 데이터를 저장하는 데 적합하지 않다. 72 | - 일부 DVD 버전은 생산된 공장에서만 기록되는 읽기 전용(read-only)이며, 73 | 다른 버전은 단 한 번 기록(write-once)을 지원하기 때문에 한 번만 기록할 수 있고 덮어쓸 수 없다. 일부 다른 버전에서는 여러 번 재기록할 수 있다. 74 | 75 | > 단 한 번 기록되어 여러 번 읽기 가능한 디스크를 WORM(write-once, read-many) 디스크라 한다. 76 | 77 |
78 |
79 | 80 | ## 테이프 저장 장치, Tape storage 81 | 82 | - 주로 데이터 백업과 보관용으로 테이프 저장 장치를 사용한다. 83 | - 자기 테이프는 디스크보다 저렴하며 수년 동안 데이터를 안전하게 저장할 수 있다. 84 | - `순차 접근 저장 장치(sequential-access storgae)` → 테이프 시작부터 순차적으로 접근해야 하므로 데이터 접근이 훨씬 더 느리다. 85 | 86 | > 반대로, 자기 디스크와 SSD 저장 장치는 **데이터가 어디에 위치하든지 데이터를 읽을 수 있으므로** 직접 접근 저장 장치(direct-access storage)라고 불린다. 87 | 88 |
89 |
90 | 91 | ## 저장 장치 계층 92 | 93 | 다양한 저장 매체는 `속도`와 `비용`에 따라서 계층 구조로 나타낼 수 있다. 94 | 95 | 이 둘 사이에는 합리적인 상반관계(trade-off)가 존재한다. 96 | 97 | - 계층의 높은 단계로 갈수록 비싸지만 빠르다. 98 | - 계층의 낮은 단계로 갈수록 비트당 비용은 감소하고, 접근 시간은 증가한다. 99 | 100 |
101 | 102 |

storage hierarchy 103 | 104 |
105 |
106 | 107 | 다양한 저장 매체의 속도와 비용에 덧붙여서, 저장 장치의 휘발성에 대한 이슈가 있다. 108 | 109 | 메인 메모리를 기준으로 위쪽의 저장 장치는 휘발성 저장 장치이고, 플래시 메모리부터 아래쪽은 비휘발성 저장 장치이다. 110 | 111 | > 안전한 보관을 위해 비휘발성 저장 장치에 데이터를 기록해야 한다. 112 | 113 |
114 | 115 | ### 1차 저장 장치, primary storage 116 | 117 | - 캐시 118 | - 메인 메모리 119 | 120 |
121 | 122 | ### 2차 저장 장치, secondary storage 123 | 124 | `온라인 저장 장치(online storage)`라고도 한다. 125 | 126 | - 플래시 메모리 127 | - 자기 디스크 128 | 129 |
130 | 131 | ### 3차 저장 장치, tertiary storage 132 | 133 | `오프라인 저장 장치(offline storage)`라고도 한다. 134 | 135 | - 자기 테이프 136 | - 광디스크 주크박스 137 | -------------------------------------------------------------------------------- /Part_05/Chapter_12/12.2 저장 장치 인터페이스/README.md: -------------------------------------------------------------------------------- 1 | # 12.2 저장 장치 인터페이스 2 | 3 |
4 | 5 | ### SATA, SCSI(SAS) 6 | 7 | - 디스크는 일반적으로 `직렬 ATA(SATA)` 인터페이스 또는 `직렬 부착 SCSI(Serial Attached SCSI, SAS)` 인터페이스를 지원한다. 8 | - SATA 3 : 6 gigabits/sec 9 | - SAS Version 3 : 12 gigabits/sec 10 | - SAS 인터페이스는 일반적으로 서버에서만 사용된다. 11 | 12 |
13 | 14 | ### NVMe 15 | 16 | - `비휘발성 메모리 익스프레스(Non-volatile Memory Express, NVMe)` 인터페이스는 SSD를 더 잘 지원하기 위해 개발한 논리 인터페이스 표준이다. 17 | - 일반적으로 `PCIe` 인터페이스와 함께 사용된다. 18 | - PCIe 인터페이스 : 컴퓨터 시스템 내부에서 고속 데이터 전송을 제공한다. (lower latency & higher transfer rates) 19 | - 24 gigabits/sec 20 | 21 |
22 | 23 | ### SAN 24 | 25 | > 일반적으로 케이블을 통해 컴퓨터 시스템의 디스크 인터페이스에 디스크를 직접 연결하지만, 26 | > 고속 네트워크를 통해 **원격**에 위치한 컴퓨터에 연결할 수도 있다. 27 | 28 | - `SAN(storage area network)` 구조에서는 많은 수의 디스크가 **고속 네트워크를 통해** 여러 서버 컴퓨터에 연결된다. 29 | - 일반적으로 `독립적인 디스크의 중복적인 배열(redundant arrays of independent disks, RAID)`이라고 불리는 **저장 장치 조직 기법**을 사용해 30 | 디스크를 지역적으로 조작한다. 31 | - SAN에 사용되는 상호 연결 기술들 32 | - `iSCSI` : SCSI 명령을 IP 네트워크를 통해 전송할 수 있다. 33 | - `FiberChannel`, `FC` : 버전에 따라 초당 1.6~12기가바이트의 전송 속도를 지원한다. 34 | - `InfiniBand` : 매우 낮은 대기 시간의 고대역폭 네트워크 통신을 제공한다. 35 | 36 |
37 | 38 | ### NAS 39 | 40 | - SAN의 대안이다. 41 | - `NAS(network attached storage)`는 큰 디스크처럼 보이는 네트워크 저장 장치 대신, 42 | NFS 또는 CIFS와 같은 **네트워크 파일 시스템 규약**을 사용하여 파일 시스템 인터페이스를 제공한다. 43 | 44 |
45 | 46 | ### Cloud storage 47 | 48 | - `클라우드 저장 장치(cloud storage)` : 클라우드에 데이터를 저장하고 API를 통해 접근한다. (21.7절에서 다룸) 49 | - 데이터가 데이터베이스와 같은 위치에 있지 않은 경우, 수십에서 수백 밀리초의 매우 긴 지연 시간을 가지므로, 50 | 데이터베이스의 기본 저장 장치로는 그리 이상적이지 못하다. 51 | - 응용 프로그램의 경우 객체를 저장하기 위해 종종 클라우드 저장 장치를 사용한다. 52 | -------------------------------------------------------------------------------- /Part_05/Chapter_12/12.4 플래시 메모리/README.md: -------------------------------------------------------------------------------- 1 | # 12.4 플래시 메모리 2 | 3 | 플래시 메모리에는 `NOR 플래시`와 `NAND 플래시`의 두 종류가 존재한다. 4 | 5 |
6 | 7 | ### NAND 플래시 8 | 9 | 데이터 저장 장치에 주로 사용되는 변종으로, 반도체의 셀이 직렬으로 배열되어 있다. 10 | 11 |
12 | 13 | NAND 플래시로부터 읽기는 일반적으로 4킬로바이트 단위의 데이터의 전체 `페이지(page)`를 필요로 하는데, 14 | **이 전체 페이지를 NAND 플래시에서 메인 메모리로 읽어들여야 한다.** 15 | 16 |
17 | 18 | 플래시 메모리로 한 페이지를 쓰는 데 보통 100마이크로초가 걸린다. 19 | 20 | 하지만 플래시 메모리의 페이지가 한 번 쓰이면 해당 페이지에 직접 덮어쓰기(overwrite)을 할 수 없고, 21 | 대신에 **페이지를 지우고(erase) 이어서 다시 쓰기를 해야 한다.** 22 | 23 | - `지움 블록(erase block)`이라고 불리는 페이지 그룹에 대해 지움 연산을 수행하며, 대략 2~5 밀리초 정도의 시간이 든다. 24 | - 지움 블록의 크기는 일반적으로 256킬로바이트에서 1메가바이트에 이르며, 한 개의 지움 블록은 대략 128~256개의 페이지로 되어 있다. 25 | - 보통 100,000~1,000,000회 정도로 플래시 페이지를 지울 수 있는 횟수가 제한되어 있다. 26 | 27 | → 이 기준에 도달하게 되면 저장 비트 내에 오류가 발생할 가능성이 있다. 28 | 29 |
30 | 31 | --- 32 | 33 |
34 | 35 | 플래시 메모리 시스템은 논리적 페이지 주소를 물리적(실제) 페이지 주소에 매핑(mapping)함으로써 36 | 느린 지움 속도와 갱신 횟수 제한으로 인해 받는 영향을 최소화한다. 37 | 38 | 논리적 페이지를 수정하면 이미 지운 물리적 페이지에 다시 대응해야 하고, 나중에 기존 위치에 있는 데이터를 지워야 한다. 39 | 40 |
41 | 42 | > 각 물리적 페이지는 자신의 논리적 주소를 저장한 메모리의 작은 부분을 차지한다. 43 | 44 | 만약 논리적 주소를 다른 물리적 주소로 다시 대응하면, 원래의 물리적 주소는 삭제된 것으로 간주한다. 45 | 46 | 신속한 접근을 위해, 논리적 페이지의 `물리적 페이지 대응 정보(logical-to-physical mapping, L2P)`는 47 | 메모리 내 `변환 테이블(translation table)`로 복제된다. 48 | 49 |
50 | 51 | --- 52 | 53 |
54 | 55 | 플래시 메모리는 다수의 삭제된 페이지를 포함하는 블록을 주기적으로 지운다. 56 | 57 | - 그 블록 내에 있는 지우지 않은 페이지를 다른 블록에 복사한다. 이때 변환 테이블은 그러한 안 지운 페이지에 대한 정보를 갱신한다. 58 | - 각 물리적 페이지는 주어진 갱신 횟수 범위 안에서만 갱신될 수 있다. 59 | - 여러 번 지워졌던 물리적 페이지에는 거의 갱신 되지 않은 데이터라는 의미로 “`cold data`”가 할당된다. 60 | - 많이 지워지지 않았던 페이지는 자주 갱신되는 데이터라는 의미로 “`hot data`”가 저장된다. 61 | 62 | > 물리적 블록에 걸쳐서 골고루 지움 연산을 불포시키는 원리를 `평등화 작업(wear leveling)`이라고 부른다. 63 | 64 |
65 | 66 | --- 67 | 68 |
69 | 70 | `플래시 변환 계층(flash translation layer)`이라고 부르는 소프트웨어 계층이 위의 모든 동작을 수행한다. 71 | -------------------------------------------------------------------------------- /Part_05/Chapter_12/12.6 디스크 블록 접근/README.md: -------------------------------------------------------------------------------- 1 | # 12.6 디스크 블록 접근 2 | 3 |
4 | 5 | 데이터베이스 시스템은 대부분의 디스크 I/O를 담당하는 질의 처리 서브시스템과 함께 디스크 I/O에 대한 요청을 생성한다. 6 | 7 | 각 요청은 디스크의 `디스크 식별자`와 `논리 블록 번호`로 구성된다. 8 | 9 |
10 | 11 | --- 12 | 13 |
14 | 15 | 디스크 블록에 대한 일련의 요청은 `순차적 접근 유형` 또는 `임의 접근 유형`으로 분류한다. 16 | 17 | - `순차적 접근 유형`에서 연속적인 요청(successive request)은 같은 트랙 혹은 인접한 트랙에 있는 연속적인 블록을 대상으로 한다. 18 | - `임의 접근 유형`에서 연속적인 데이터의 요청은 디스크상의 임의 위치한 블록을 대상으로 한다. 19 | 이러한 각 요청은 탐색이 필요하므로 접근 시간이 길어지고 초당 임의 I/O 연산 수가 줄어들게 된다. 20 | 21 |
22 |
23 | 24 | ## 블록에 대한 접근 속도를 향상하기 위한 기법들 25 | 26 | **접근 횟수를 최소화함으로써**, 특히 임의 접근 횟수를 최소화함으로써 블록에 대한 접근 속도를 향상하기 위한 많은 기법을 개발해왔다. 27 | 28 | 자기 디스크에 저장된 데이터에 대한 임의 접근 횟수를 줄이는 것은 성능에 매우 중요하다. 29 | 30 |
31 | 32 | ### 버퍼링, Buffering 33 | 34 | 다음에 있을 요청을 충족하기 위해 **디스크로부터 읽는 블록을 메모리 버퍼 내에 임시로 저장**하는 기법이다. 35 | 36 |
37 | 38 | ### 미리 읽기, Read-ahead 39 | 40 | 디스크 블록에 접근할 때, 블록에 대한 요청이 없더라도 **동일 트랙 내의 연속적인 블록을 일단 메모리 내의 버퍼로 읽어들이는** 기법이다. 41 | 42 | - `순차적 접근`의 경우, 이러한 미리 읽기는 많은 블록이 요청되더라도 이미 메모리 내에 있게 되기 때문에 43 | 블록 읽기당 디스크 탐색과 회전 지연에 낭비되는 시간을 최소화할 수 있다. 44 | - `임의 블록 접근`의 경우 미리 읽기는 크게 유용하지 않다. 45 | 46 |
47 | 48 | ### 스케줄링, Scheduling 49 | 50 | 실린더에 있는 몇 개의 블록을 디스크에서 메인 메모리로 전송할 필요가 있다면 헤드 아래로 지나갈 순서대로 블록을 요청함으로써 접근 시간을 줄일 수 있다. 51 | 52 |
53 | 54 | `디스크 암 스케줄링(disk-arm-scheduling) 알고리즘`은 **처리할 수 있는 접근 수를 최대한 증가시키는 방식으로** 트랙 접근 순서를 정하려고 한다. 55 | 56 | → 일반적으로 사용되는 알고리즘 : `승강기 알고리즘(elevator algorithm)` 57 | 58 |
59 | 60 | `디스크 컨트롤러`는 디스크 블록의 구성, 디스크 판의 회전 위치, 그리고 디스크 암의 위치에 대해 상세히 알고 있다. 61 | 62 | 따라서 보통 디스크 컨트롤러가 성능을 향상하기 위해 읽기 요구의 순서를 재구성하는 일을 수행한다. 63 | 64 | 이러한 재정렬을 활성화하려면 `디스크 컨트롤러 인터페이스`에서 대기열에 여러 요청을 추가할 수 있어야 한다. 65 | 66 |
67 | 68 | ### 파일 구성, File organization 69 | 70 | 블록 접근 시간을 줄이기 위해 데이터에 접근하고자 하는 방식에 가장 가까이 부합하는 방식으로 디스크의 블록을 조직할 수 있다. 71 | 72 |
73 | 74 | 최신 디스크는 운영체제에서 정확한 블록 위치를 숨기지만 **서로 인접한 블록에 연속 번호를 부여하는** `논리적 블록 번호`를 사용한다. 75 | 76 | 연속되는 번호를 매긴 디스크 블록에 파일의 `연속 블록(consecutive block)`을 할당함으로써 운영체제는 파일을 순차적으로 저장할 수 있다. 77 | 78 |
79 | 80 | 하나의 긴 연속 블록의 순차로 대용량 파일을 저장하면 디스크 블록 할당에 문제가 발생하는데, 81 | 이를 해결하기 위해 운영체제는 한 번에 몇 개의 연속 블록, 즉 `확장영역(extent)`을 파일에 할당한다. 82 | 83 | 파일에 할당된 다른 확장영역은 디스크에서 서로 인접하지 않을 수 있으며, 84 | 블록이 무작위로 할당된 경우 파일에 대한 순차 접근은 블록당 하나의 탐색 대신에 **확장영역당 하나의 탐색**이 필요하다. 85 | 86 | → 충분히 큰 확장영역을 사용하면 데이터 전송 비용과 관련된 탐색 비용을 최소화할 수 있다. 87 | 88 |
89 | 90 | 시간이 지남에 따라 여러 개의 착은 추가(append)가 있는 순차 파일은 `단편화(fragmented)`될 수 있다. 91 | 92 | 단편화를 줄이기 위해 시스템은 디스크에 있는 데이터의 백업본을 만들어서 전체 디스크를 다시 저장할 수 있다. 93 | 94 | 일부 운영체제는 단편화를 줄이기 위해 디스크를 스캔하면서 블록을 이동시키는 유틸리티를 제공한다. 95 | 96 |
97 | 98 | --- 99 | 100 |
101 | 102 | 위와 같은 저수준의 최적화(low-level optimizations) 외에도, 103 | 질의 처리 알고리즘을 더 현명하게 설계해서 더 높은 수준에서의 임의 접근을 최소화할 수 있는 최적화를 수행할 수 있다. 104 | -------------------------------------------------------------------------------- /Part_05/Chapter_13/13.1 데이터베이스 저장 장치 구조/README.md: -------------------------------------------------------------------------------- 1 | # 13.1 데이터베이스 저장 장치 구조 2 | 3 |
4 | 5 | 영구적인 데이터는 일반적으로 자기 디스크 또는 SSD인 비휘발성 저장 장치에 저장된다. 6 | 7 | 자기 디스크와 SSD는 `블록(block)` 구조를 이용하는 저장 장치이다. 즉, **데이터를 블록 단위로 읽거나 쓴다.** 8 | 9 | 이에 반해 데이터베이스는 일반적으로 블록보다 훨씬 작은 크기인 `레코드(record)`를 처리한다. 10 | 11 |
12 |
13 | 14 | 대부분 데이터베이스는 레코드를 저장하기 위한 중간 계층으로 운영체제 파일을 사용하여 하부 블록의 세부 정보를 추상화한다. 15 | 16 | 그러나 데이터베이스는 블록 구조를 계속 사용해야 하는데, 이는 효율적인 접근을 보장하고 오류 발생 시 데이터의 복구가 가능하도록 하기 위해서이다. 17 | 18 | > 13.2절 : 블록 구성에 따라 어떻게 개별 레코드를 파일에 저장하는가? 19 | 20 |
21 |
22 | 23 | 레코드 집합이 있다면, 파일 구성에서 이러한 레코드를 어떻게 조직할지를 결정할 수 있다. 24 | 25 | > 13.3절 : 파일에 레코드를 구성하는 방법? 26 | 27 |
28 |
29 | 30 | > 13.4절 : 데이터 사전에서 데이터베이스가 저장 장치 구조뿐만 아니라 관계형 스키마에 대한 메타 데이터를 어떻게 구성하는가? 31 | 32 |
33 |
34 | 35 | CPU가 데이터에 접근하려면 해당 데이터는 메인 메모리에 있어야 하지만, 영속 데이터는 자기 디스크 또는 SSD와 같은 비휘발성 저장 장치에 있어야 한다. 36 | 37 | 따라서 보통 메인 메모리보다 큰 데이터베이스의 경우, **데이터를 비휘발성 저장 장치에서 가져와서 갱신한 뒤에는 다시 저장 장치에 저장해야 한다.** 38 | 39 | > 13.5절 : 데이터베이스가 비휘발성 저장 장치에서 가져온 블록을 `데이터베이스 버퍼(buffer)`라고 하는 메모리 영역을 이용하여 저장하는 방법? 40 | 41 |
42 |
43 | 44 | 특정 행의 모든 속성을 함께 저장하는 것이 아니라, 45 | **특정 열의 모든 값을 함께 저장**하는 것에 기반을 둔 데이터 저장 방법은 분석 질의 처리에서 매우 잘 동작하는 것으로 밝혀졌다. 46 | 47 | > 13.6절 : 열 지향 저장소(column-oriented storage) 48 | -------------------------------------------------------------------------------- /Part_05/Chapter_13/13.2 파일 구성/README.md: -------------------------------------------------------------------------------- 1 | # 13.2 파일 구성 2 | 3 |
4 | 5 | ## Database > File > Record > Field 6 | 7 | - The `database` is stored as a collection of `files`. 8 | - Each `file` is a sequence of `records`. 9 | - A `record` is a sequence of `fields`. 10 | 11 |
12 | 13 | 하나의 데이터베이스는 내부적으로 기반 운영체제가 관리하는 많은 다른 파일에 대응하며, 이 파일은 디스크 안에 영구적으로 저장된다. 14 | 15 | > `파일(file)`은 일련의 레코드로서, 논리적으로 구성된다. 16 | 17 |
18 | 19 | > `블록(block)`이라고 불리는 **고정 길이(fixed-length) 저장 단위**로 각 파일을 논리적으로 분할한다. 20 | 21 | 이는 저장 장소 할당과 데이터 전송의 단위이다. 22 | 23 | 대부분의 데이터베이스는 기본으로 4~8킬로바이트의 블록 크기를 사용한다. 24 | 25 |
26 | 27 | > 한 개의 블록은 여러 `레코드(record)`을 포함한다. 28 | 29 | 정확히 어떤 레코드 집합이 같은 블록에 있어야 하는지에 대한 결정은 물리적 데이터 구성의 형태가 한다. 30 | 31 |
32 | 33 | > 레코드는 여러 `필드(field)`를 포함한다. 34 | 35 |

record 36 | 37 |
38 |
39 | 40 | --- 41 | 42 |
43 | 44 | **블록보다 더 큰 레코드는 없다**고 가정한다. 45 | 46 | - 이 가정은 대부분의 데이터 처리 응용 프로그램을 고려할 때 현실적이다. 47 | - 이미지와 같이 블록보다 훨씬 큰 대용량의 데이터 항목은 별도로 저장한 다음, 레코드 안에 해당 데이터 항목에 대한 포인터를 저장함으로써 다룬다. 48 | 49 |
50 | 51 | **단일 블록은 각 레코드를 완전히 포함해야 한다.** 52 | 53 | - 이는 어떤 레코드도 한 블록에 부분적으로 포함되거나 또 다른 레코드에 부분적으로 포함되지 않는다는 것을 의미한다. 54 | 55 |
56 | 57 | --- 58 | 59 |
60 | 61 | 관계형 데이터베이스에서 서로 다른 릴레이션의 튜플은 일반적으로 다른 크기를 가진다. 62 | 63 |
64 | 65 | 데이터베이스에 파일을 매핑하기 위한 두 가지 방법 66 | 67 | 1. 여러 파일을 사용하면서 주어진 파일 내에 `고정 길이` 레코드만 저장한다. 68 | 2. 파일을 구조적으로 저장하여 `가변 길이`로 레코드를 저장한다. 69 | 70 | 고정 길이 레코드로 구성된 파일은 가변 길이 레코드 파일보다 구현하기 더 쉽지만, 가변 길이의 경우에 더 많은 다양한 기법들을 적용할 수 있게 된다. 71 | 72 |
73 |
74 |
75 | 76 | # 13.2.1 고정 길이 레코드 77 | 78 | 대학교 데이터베이스의 instructor 레코드 파일의 각 레코드를 의사 코드로 다음과 같이 정의할 수 있다. 79 | 80 | ```sql 81 | type instructor = record 82 | ID varchar(5); 83 | name varchar(20); 84 | dept_name varchar(20); 85 | salary numeric(8, 2); 86 | end 87 | ``` 88 | 89 |
90 | 91 | 각 문자는 1바이트를, numeric(8, 2)형은 8바이트를 차지한다고 가정한다면, instructor 레코드의 길이는 53바이트다. 92 | 93 | 이러한 고정 길이 파일을 구성하는 간단한 방법은 첫 번째 레코드를 위해 첫 번째 53바이트를 사용하고, 94 | 두 번째 레코드를 위해 그다음 53바이트를 사용하는 등등이다. 95 | 96 |

고정 길이 레코드 97 | 98 |
99 |
100 | 101 | --- 102 | 103 |
104 | 105 | > Store record `i` starting from byte `n * (i-1)`, where `n` is the size of each record. 106 | 107 | 아래 예시는 레코드의 길이가 100바이트라고 가정했을 경우에 대한 것이다. 108 | 109 | 110 |

record access 111 | 112 |
113 |
114 |
115 | 116 | ## 문제점 117 | 118 | 이 방법은 두 가지 문제점을 지닌다. 119 | 120 |
121 | 122 | > 1️⃣ 만약 블록 크기가 53의 배수가 되지 않는다면 몇몇 레코드는 블록 경계를 넘게 된다 123 | 124 | 즉, 레코드 일부분은 어떤 블록에 저장되고 나머지 부분은 다른 블록에 저장될 것이므로 해당 레코드를 읽거나 쓰기 위해서는 두 블록에 모두 접근해야 한다. 125 | 126 | 이를 피하려면 한 블록에 완전히 채울 수 있는 만큼의 블록만 레코드를 할당해야 한다. (남은 바이트는 사용하지 않은 채 남김) 127 | 128 |
129 | 130 | > 2️⃣ 레코드를 삭제하기가 어렵다 131 | 132 | 삭제할 레코드가 차지하는 공간은 그 파일의 다른 레코드로 채우거나, 그 공간을 무시할 수 있도록 레코드를 삭제했다는 표시를 해야 한다. 133 | 134 |
135 |
136 | 137 | ## 레코드의 삭제 138 | 139 | 가능한 방법은 총 3가지가 존재한다. 140 | 141 |
142 | 143 | > 1️⃣ 한 레코드를 삭제할 때 이 레코드 뒤에 있는 모든 레코드를 바로 **전 레코드가 차지한 공간으로 이동시킨다.** 144 | 145 | 아래 그림은 레코드 3이 삭제되고 마지막 레코드가 이동한 상태를 나타낸다. 146 | 147 |

deletion 1 148 | 149 |
150 |
151 | 152 | 이 방법에서는 많은 수의 레코드가 이동해야 할 수 있기 때문에, 153 | 아래 그림처럼 **삭제한 레코드가 있었던 공간에 파일의 마지막 레코드를 단순히 이동**하는 게 더 쉬울 수 있다. 154 | 155 |

deletion 2 156 | 157 |
158 |
159 | 160 | 하지만 이처럼 삭제한 레코드가 있었던 빈 곳, 즉 `자유 공간`을 채우기 위해 레코드를 이동하게 되면 부차적인 블록 접근이 필요하기에 바람직하지 않다. 161 | 162 |
163 | 164 | > 2️⃣ 삭제한 레코드가 있었던 공간을 비워 둔 채, 재사용하기 전 다음에 삽입할 레코드를 기다리게 한다. 165 | > → new 레코드를 해당 빈 자리에 추가한다. 166 | 167 | 하지만 이러한 이용 가능 공간을 찾기가 어렵기 때문에, 삭제한 레코드를 표시하는 것만으로는 충분하지 않을 것다. 168 | 169 | 따라서 추가적인 구조를 생각해 볼 필요가 있다. 170 | 171 |
172 | 173 | > 3️⃣ 자유 리스트(free list)를 사용한다. 174 | 175 | 파일의 앞부분에 일부 바이트를 할당해 `파일 헤더(file header)`를 만들어서, 해당 파일에 대한 다양한 정보를 저장한다. 176 | 177 | 여기에 삭제된 첫 번째 레코드의 주소를 저장하고, 이 레코드를 사용해서 이용 가능한 두 번째(즉 다음) 레코드의 주소를 저장하고, … 178 | 이런 식으로 계속해 나가면 된다. 179 | 180 |
181 | 182 | 이렇게 저장한 레코드 주소는 레코드의 위치를 가리키므로 해당 주소를 `포인터(pointer)`로 생각할 수 있으며, 183 | 이 삭제한 레코드는 `연결 리스트(linked list)`를 형성한다. 184 | 185 | 이는 종종 `자유 리스트(free list)`로 언급하기도 한다. 186 | 187 |

deletion 3 188 | 189 |
190 |
191 | 192 | - 새로운 레코드를 삽입할 대 헤더가 가리키는 레코드를 사용한다. 193 | - 그다음 헤더의 포인터를 다음 이용 가능한 레코드를 가리키도록 바꾼다. 194 | - 이용 가능 공간이 없다면 이 파일 끝에 새로운 레코드르 추가한다. 195 | 196 |
197 | 198 | --- 199 | 200 |
201 | 202 | 고정 길이 레코드에서는 삭제한 레코드가 이용할 수 있는 공간은 정확하게 새로운 레코드를 삽입하는 데 필요한 공간이 된다. 203 | 204 | 따라서 고정된 길이의 레코드를 저장한 파일의 삽입과 삭제는 구현이 간단하다. 205 | 206 |
207 | 208 | 그러나 가변 길이 레코드를 파일에 저장한다면 이런 일치가 더는 유효하지 않게 된다. 209 | 210 |
211 |
212 |
213 | 214 | # 13.2.2 가변 길이 레코드 215 | 216 | 데이터베이스 시스템에서 `가변 길이 레코드(variable-length record)`가 필요한 몇 가지 상황이 있다. 217 | 218 | - 파일 내에 여러 레코드 유형의 존재 219 | - 가변 길이 필드의 존재 (e.g., varchar) 220 | - 배열 혹은 다중 집합(multiset)과 같은 반복적인 필드를 포함하는 레코드 유형의 존재 221 | 222 |
223 | 224 | --- 225 | 226 |
227 | 228 | 가변 길이 레코드를 구현하기 위한 다양한 기법이 존재하며, 이들은 아래의 두 가지 서로 다른 문제를 해결해야 한다. 229 | 230 | 1. 속성이 가변 길이인 경우에도 **개별 속성을 쉽게 추출할 수 있는** 방식으로 하나의 레코드를 표현하는 방법 231 | 2. **블록 내의 레코드를 쉽게 추출할 수 있도록** 블록 내에 가변 길이 레코드를 저장하는 방법 232 | 233 |
234 |
235 | 236 | ## 가변 길이 레코드의 표현 237 | 238 | 가변 길이의 속성을 지닌 레코드의 표현은 일반적으로 두 부분으로 구성된다. 239 | 240 |
241 | 242 | > 1️⃣ 구조가 같은 릴레이션의 모든 레코드에 대해 같은 **고정 길이 정보**를 갖는 처음 부분 243 | 244 | → 고정 길이 속성에 해당 값을 저장하는 데 필요한 많은 수의 바이트마늠을 해당 고정 길이 속성에 할당한다. 245 | 246 |
247 | 248 | > 2️⃣ **가변 길이 속성의 내용**으로 구성된 그다음 부분 249 | 250 | → 레코드의 처음 부분에서 `[offset, length]`의 쌍으로 표현된다. 251 | 252 | - `offset` : 레코드 내의 속성이 시작되는 부분을 위한 데이터 253 | - `length` : 가변 길이 속성의 바이트의 길이 (size of data) 254 | 255 |
256 | 257 | --- 258 | 259 |
260 | 261 | 이러한 레코드 표현의 예시는 아래와 같다. 262 | 263 | e.g., instructor 레코드 264 | 265 |
266 | 267 | ID, name, dept_name 268 | 269 | - 가변 길이의 문자열 → 각 문자열은 자신이 가지는 수만큼의 바이트를 지닌다. 270 | - offset과 length 값을 속성당 2바이트씩, 총 4바이트를 저장한다고 가정한다. 271 | 272 |
273 | 274 | salary 275 | 276 | - 고정 길이 숫자 277 | - 8바이트로 해당 속성을 저장한다고 가정한다. 278 | 279 |
280 | 281 |

가변 길이 레코드 282 | 283 |
284 |
285 | 286 | ### 널 비트맵, null bitmap 287 | 288 | 위 그림에서 어떤 레코드의 속성이 null 값을 가지는지를 나타내는 `널 비트맵(null bitmap)`의 사용도 볼 수 있다. 289 | 290 | 특정한 레코드에서 만약 salary의 값이 null이면 **비트맵의 네 번째 비트는 1로 설정되고**, 12~19바이트로 저장될 salary의 값은 무시될 것이다. 291 | 292 |
293 | 294 | 일부 표현에서 레코드의 시작 부분에 널 비트맵을 저장하고, null인 속성을 위해 값이나 offset, length와 같은 데이터를 전혀 저장하지 않는다. 295 | 296 | 이런 표현에서는 레코드의 속성을 추출하기 위한 여분의 작업 비용에서 저장 장치의 공간을 절약하게 되므로, 297 | 대부분의 필드가 null 값을 갖는 레코드를 사용하는 여러 응용 프로그램에 특히 유용하다. 298 | 299 |
300 |
301 | 302 | ## 슬롯 페이지 구조, slotted-page structure 303 | 304 | `슬롯 페이지 구조(slotted-page structure)`는 블록 내의 레코드를 구성하는 데 흔히 사용된다. (여기서 “페이지”는 “블록”과 같은 의미로 사용한다.) 305 | 306 |
307 | 308 |

slotted-page structure 309 | 310 |
311 |
312 | 313 | 각 블록의 시작에는 다음의 정보를 저장하는 헤더가 있다. 314 | 315 | - 헤더가 있는 레코드 엔트리의 수 316 | - 블록에서 빈 곳의 끝 317 | - 각 레코드의 위치와 크기를 포함하고 있는 엔트리 배열 318 | 319 |
320 | 321 | ### 레코드의 삽입 322 | 323 | > 실제 레코드는 블록의 끝에서부터 **인접하게(contiguously)** 할당되며, 324 | > 블록에서 빈 곳은 헤더 배열에 있는 마지막 엔트리와 첫 번째 레코드 사이에서 연속적이다. 325 | 326 | 어떤 한 레코드를 삽입하면 **빈 곳 끝에 이 레코드를 위한 공간을 할당**하고, 이 레코드의 크기와 위치를 포함하는 엔트리를 헤더에 추가한다. 327 | 328 |
329 | 330 | ### 레코드의 삭제 331 | 332 | 1. 레코드를 삭제하면 해당 레코드가 차지하고 있던 공간을 비우고, 관련 엔트리를 **삭제한 상태**(예를 들어, 크기는 -1로 표시)로 명시한다. 333 | 2. 삭제한 레코드 앞쪽에 있는 레코드를 이동한다. 334 | - 이를 통해 삭제한 레코드가 차지하고 있었던 공간이 빈 곳이 되어, 모든 빈 곳은 다시 헤더 배열의 마지막 엔트리와 첫 번째 레코드 사이에 있게 된다. 335 | 336 |
337 | 338 | --- 339 | 340 |
341 | 342 | > 헤더에 있는 빈 공간의 끝을 가리키는 포인터를 상황에 맞게 갱신해야 한다. 343 | 344 |
345 | 346 | > 블록의 크기가 제한되어 있으므로 레코드를 이동하는 비용은 크게 들지 않는다. 347 | 348 | 블록의 크기는 보통 4~8킬로바이트다. 349 | 350 | 351 |
352 | 353 | > 레코드를 직접 가리키는 포인터는 없도록 해야 하며, 354 | > 포인터는 레코드의 실제 위치를 포함하고 있는 헤더 안에 있는 엔트리를 가리키도록 해야 한다. 355 | 356 | 이러한 수준의 우회(indirection)는 레코드에 대한 간접 포인터를 지원하면서, 블록의 공간을 단편화하는 것을 막기 위해 레코드를 이동할 수 있도록 해준다. 357 | 358 |
359 |
360 |
361 | 362 | # 13.2.3 대형 객체 저장 방법 363 | 364 | 데이터베이스는 디스크 블록보다 훨씬 큰 데이터를 종종 저장한다. 365 | 366 |
367 | 368 | 대부분의 관계형 데이터베이스는 내부적으로 한 레코드의 크기가 한 블록의 크기를 넘지 않도록 제한한다. 369 | 370 | 해당 `대형 객체(large object)`는 레코드의 다른 소형 속성과는 별도로 저장하며, **대형 객체에 대한 논리 포인터를 해당 객체를 포함하는 레코드에 저장한다.** 371 | 372 |
373 | 374 | 대형 객체를 저장하는 방법에는 두 가지가 존재한다. 375 | 376 | 1. 데이터베이스가 관리하는 파일 시스템 영역의 파일로 저장한다. 377 | 2. 데이터베이스가 저장하고 관리하는 파일 구성으로 저장한다. 378 | - 데이터베이스 내 대형 객체를 `B+-tree` 파일 구성을 사용해서 선택적으로 표현할 수 있다. (14.4.1절) 379 | - B+-tree 파일 구성은 그 객체 내의 임의 위치에 대한 효율적인 접근을 가능하게 한다. 380 | 381 |
382 |
383 | 384 | ## 성능 이슈 385 | 386 | 데이터베이스에 매우 큰 객체를 저장하는 데서 오는 몇 가지 성능에 대한 이슈들은 다음과 같이 존재한다. 387 | 388 | 1. 대형 객체를 데이터베이스 인터페이스를 통해서 접근하는 것이 효율적인가? 389 | 2. 데이터베이스 백업의 크기 증가 390 | - 많은 기업이 주기적으로 `데이터베이스 덤프(dump)`, 즉 데이터베이스의 백업 복사본을 만드는데 391 | 데이터베이스에 대형 객체를 저장하면 데이터베이스 덤프의 크기가 매우 증가할 것이다. 392 | 393 |
394 | 395 | ### 해결법 396 | 397 | > 많은 응용 프로그램은 크기가 매우 큰 객체를 **데이터베이스 외부의 파일 시스템에 저장한다.** 398 | 399 | 이럴 때 응용 프로그램은 파일 이름(일반적으로 파일 시스템에서 경로)을 데이터베이스 내 레코드의 속성으로 저장할 수 있다. 400 | 401 |
402 | 403 | 하지만 이렇게 하면 문제들이 또다시 발생하게 된다. 404 | 405 | - 데이터베이스의 파일 이름이 존재하지 않는 파일을 가리키게 되며, 파일이 삭제되었기 때문에 외래 키 제약 조건을 위반하는 형태가 된다. 406 | - 데이터베이스 권한 제어는 파일 시스템에 저장된 데이터에는 적용되지 않는다. 407 | 408 |
409 | 410 | > 따라서 일부 데이터베이스는 **데이터베이스와의 파일 시스템 통합**을 제공한다. 411 | 412 | - 제약 조건을 충족하는지를 확인하고 데이터베이스 접근 권한을 적용하도록 한다. 413 | - 즉, 파일 시스템 인터페이스와 데이터베이스 SQL 인터페이스 모두에서 파일에 접근할 수 있는 것이다. 414 | 415 | e.g., Oracle : SecureFiles 및 Database File System 특성을 이용해 이러한 통합을 지원한다. 416 | -------------------------------------------------------------------------------- /Part_05/Chapter_13/13.3 파일에 레코드를 구성하는 방법/README.md: -------------------------------------------------------------------------------- 1 | # 13.3 파일에 레코드를 구성하는 방법 2 | 3 |
4 | 5 | > `릴레이션(relation)` = `레코드(record)`들의 집합 6 | 7 |
8 | 9 | 파일 안에 레코드를 구성하는 몇 가지 가능한 방법은 다음과 같다. 10 | 11 | - 힙 파일 구성, Heap file organization 12 | - 순차 파일 구성, Sequential file organization 13 | - 다중 테이블 군집 파일 구성, Multitable clustering file organization 14 | - B+-트리 파일 구성, B+-tree file organization 15 | - 해싱 파일 구성, Hashing file organization 16 | 17 |
18 |
19 |
20 | 21 | # 13.3.1 힙 파일 구성 22 | 23 | 레코드는 릴레이션에 해당하는 파일의 어디에나 저장될 수 있다. 24 | 25 | > 파일 안에 레코드를 위한 공간만 있다면 임의의 레코드는 어디든지 놓일 수 있으며, 레코드의 순서는 없다. 26 | 27 |
28 |
29 | 30 | ## 레코드의 삽입 31 | 32 |

힙 파일 구성 33 | 34 |
35 |
36 | 37 | 레코드를 파일에 삽입할 때, 항상 파일의 끝부분에 추가하도록 할 수 있다. 38 | 39 | 그러나 **레코드를 삭제하면 만들어진 빈 곳**을 사용하여 새 레코드를 저장하는 것이 더 좋다. 40 | 41 |
42 | 43 | ### 여유 공간 맵, free-space map 44 | 45 | 대부분 데이터베이스는 `여유 공간 맵(free-space map)`이라고 하는 공간 효율적 데이터 구조를 사용하여 레코드를 저장할 여유 공간이 있는 블록을 추적한다. 46 | 47 | - 여유 공간 맵은 릴레이션의 각 블록에 대해 한 개의 엔트리를 포함하는 배열로 흔히 나타낸다. 48 | - 각 엔트리는 비율 f를 표현하는데, 이는 **최소 비율 f만큼이 해당 블록 공간에 비어 있어야 한다**는 것을 뜻한다. 49 | 50 |
51 | 52 | > 배열은 파일에 저장되고, 파일의 블록은 필요할 때 메모리로 가져온다. 53 | 54 | 레코드를 삽입, 삭제 또는 그 크기를 변경할 때마다 엔트리 값에 영향을 줄 만큼 점유 비율이 변경되면 여유 공간 맵에서 엔트리를 갱신한다. 55 | 56 |
57 | 58 | e.g., 16개의 블록이 있는 파일에 대한 여유 공간 맵 59 | 60 | - 점유 비율을 저장하기 위해 3비트를 사용한다고 가정하자. 61 | - 위치 i의 값을 8(= 2^3)로 나누어 블록 i의 여유 공간 비율을 구해야 한다. 62 | - e.g., 7 = 해당 블록에서 최소 7/8의 공간이 비어 있다. 63 | - 한 페이지가 4KB라고 가정한다면, unit size for the free spaces : 512바이트(= 4KB / 8) 64 | 65 |
66 | 67 |

여유 공간 맵 68 | 69 |
70 |
71 | 72 | 1. 데이터베이스는 주어진 크기의 새 레코드를 저장할 블록을 찾기 위해, 여유 공간 맵을 스캔하여 해당 레코드를 저장할 충분한 여유 공간이 있는 블록을 찾는다. 73 | 2. 만약 적당한 블록이 없다면 릴레이션에 새로운 블록을 할당한다. 74 | 75 |
76 | 77 | ### 2계층 여유 공간 맵 78 | 79 | 여유 공간이 충분한 블록을 찾는 작업의 속도를 높이기 위해 **2계층의 여유 공간 맵**을 만들 수 있다. 80 | 81 | 2단계 여유 공간 맵은 기존의 여유 공간 맵의 n개 엔트리 중 최댓값만을 저장하는 것으로 구현할 수 있다. 82 | 83 | 아래 배열은 위의 예시에 대한 `2단계 여유 공간 맵`을 나타낸 것이다. 84 | 85 |

2단계 여유 공간 맵 86 | 87 |
88 |
89 | 90 | 2단계 여유 공간 맵에서 충분한 여유 공간을 가진 적절한 엔트리가 발견되면, 91 | 기본 여유 공간 맵에서 해당하는 엔트리들을 검사하며 여유 공간이 충분한 블록을 찾으면 된다. 92 | 93 |
94 | 95 | 매우 큰 릴레이션을 다루기 위해 같은 아이디어를 사용하여 2계층 이상의 여유 공간 맵을 만들 수 있다. 96 | 97 |
98 |
99 | 100 | ### 여유 공간 맵의 갱신 101 | 102 | 맵의 엔트리를 갱신할 때마다 여유 공간 맵을 디스크에 쓰는 것은 비용이 많이 들 수 있다. 103 | 104 | 따라서 **여유 공간 맵을 주기적으로 쓰게 되는데**, 이로 인해 디스크의 여유 공간 맵이 최신이 아닐수도 있다. 105 | 106 | 즉, 여유 공간 맵은 블록에 여유 공간이 없을 때도 여유 공간이 있다고 할 수 있으며, 107 | 이 오류는 블록을 가져올 때 감지가 된다. 이는 여유 공간 맵에서 추가로 검색하여 해결할 수 있다. 108 | 109 | 반면에 여유 공간 맵은 블록에 여유 공간이 없다고 할 수도 있는데, 110 | 이를 해결하기 위해 릴레이션을 주기적으로 스캔하고 여유 공간 맵을 다시 계산하여 디스크에 기록한다. 111 | 112 |
113 |
114 |
115 | 116 | # 13.3.2 순차 파일 구성 117 | 118 | > 레코드의 효율적인 처리를 위해 일부 `검색 키(search key)`**를 기반으로 정렬한 순서로** `순차 파일(sequential file)`을 설계한다. 119 | 120 |
121 | 122 | ### 검색 키 123 | 124 | - `검색 키(search key)` 는 특정 속성이나 속성들의 집합으로, 정렬의 기준이 된다. 125 | - 반드시 주 키이거나 수퍼 키일 필요는 없다. 126 | 127 |
128 | 129 | > 각 레코드는 다음 레코드를 검색 키의 순서로 **포인터를 통해 연결한다.** 130 | 131 |

순차 파일 구성 132 | 133 |
134 |
135 |
136 | 137 | ## 레코드의 삭제와 삽입 138 | 139 | 레코드를 삽입하고 삭제한 대로 물리적 순서를 유지하기는 어렵다. 140 | 141 | 한 번의 삽입이나 삭제 때문에 많은 레코드를 이동하는 것은 비용이 많이 들기 때문이다. 142 | 143 |
144 | 145 | ### 레코드의 삭제 146 | 147 | 레코드의 삭제는 `포인터 체인`을 이용하여 관리할 수 있다. 148 | 149 | (아래 사진에서 붉은색 부분 참고) 150 | 151 |
152 | 153 | ### 레코드의 삽입 154 | 155 | 1. 검색 키 순서로 볼 때 삽입할 레코드 바로 앞에 위치하는 레코드를 파일에서 찾는다. 156 | 2. (1) 찾은 레코드와 같은 블록 내에 빈 레코드(즉 삭제한 후 빈 공간)가 있다면 거기에 새로운 레코드를 삽입한다. 157 | (2) 그렇지 않다면 `오버플로 블록(overflow block)`에 새로운 레코드를 삽입한다. 158 | → 어느 경우든, 레코드를 검색 키 순서로 연결하기 위해 포인터를 조정한다. 159 | 160 | (아래 사진에서 푸른색 부분 참고) 161 | 162 |

순차 파일 구성 - 삭제와 삽입 163 | 164 |
165 |
166 |
167 | 168 | ## 파일의 재구성 169 | 170 | 상대적으로 오버플로 블록에 저장할 필요가 있는 레코드가 거의 없다면 위의 방법은 잘 동작한다. 171 | 172 | 하지만 검색 키 순서와 물리적 순서 사이의 일치를 시간이 지남에 따라 완전히 잃어버릴 수가 있어, 이 경우 순차적인 처리가 훨씬 비효율적으로 될 수 있다. 173 | 174 | 이 시점에서는 다시 물리적으로 순차적인 순서가 되도록 파일을 `재구성(reorganized)`해야 한다. 175 | 176 | - 재구성 작업은 비용이 많이 든다. 177 | - 이 작업은 시스템 작업량이 낮을 때 해야 한다. 178 | - 재구성이 필요한 빈도는 새로운 레코드의 삽입 빈도에 따라 다르다. 179 | 180 |
181 | 182 | 14.4.1절에서 설명하는 `B+-트리 파일 구성`은 삽입, 삭제 및 갱신이 많이 일어날 때도 비용이 많이 드는 재구성 없이 효율적인 정렬 접근이 가능하다. 183 | -------------------------------------------------------------------------------- /Part_05/Chapter_14/14.1 기본 개념/README.md: -------------------------------------------------------------------------------- 1 | # 14.1 기본 개념 2 | 3 |
4 | 5 | 데이터베이스 시스템의 `인덱스(index)`는 도서관에서 사용되는 책의 인덱스와 똑같은 역할을 한다. 6 | 7 | e.g., 주어진 ID를 가진 student 레코드를 검색하기 위해 인덱스를 이용한다. 8 | 즉, 대응되는 레코드가 어느 디스크 블록에 있는지 찾은 후에 student 레코드를 얻기 위해 해당 블록을 가져온다. 9 | 10 |
11 | 12 | > 인덱스는 **효율적인 질의 처리**를 위한 중요 요소이다. 13 | > 만약 인덱스가 없다면 모든 질의는 사용하는 모든 릴레이션의 전체 내용을 읽어야 한다. 14 | 15 |
16 |
17 | 18 | ## 인덱스의 종류 19 | 20 | ### 순서 인덱스, Ordered index 21 | 22 | 값에 대해 **정렬**된 순서로 되어 있다. 23 | 24 |
25 | 26 | ### 해시 인덱스, Hash index 27 | 28 | 버켓(bucket)의 범위 안에서 값이 일정하게 **분배**되어 있다. 29 | 30 | 값이 할당되는 버켓은 `해시 함수`에 의해 결정된다. 31 | 32 |
33 |
34 | 35 | ## 인덱스 기술의 평가 요소 36 | 37 | ### 접근 유형, Access type 38 | 39 | - 효율적으로 지원되는 접근 유형 40 | - 특정한 속성의 값을 가진 레코드나 특정한 범위에 들어가는 속성의 값을 가지는 레코드를 찾는 것을 포함한다. 41 | 42 |
43 | 44 | ### 접근 시간, Access time 45 | 46 | - 특정한 데이터 항목이나 항목의 집합을 찾는 데 걸리는 시간 47 | 48 |
49 | 50 | ### 삽입 시간, Insertion time 51 | 52 | - 새로운 데이터 항목을 삽입하는 데 걸리는 시간 53 | - 삽입 위치를 찾는 데 걸리는 시간 + 인덱스 구조를 갱신하는 데 걸리는 시간 54 | 55 |
56 | 57 | ### 삭제 시간, Deletion time 58 | 59 | - 데이터 항목을 삭제하는 데 걸리는 시간 60 | - 삭제될 항목을 찾는 데 걸리는 시간 + 인덱스 구조를 갱신하는 데 걸리는 시간 61 | 62 |
63 | 64 | ### 공간 부담, Space overhead 65 | 66 | - 인덱스 구조가 사용하는 부가적인 공간 67 | 68 |
69 |
70 | 71 | ## 검색 키, search key 72 | 73 | > 한 파일에서 레코드를 찾는 데 사용되는 속성이나 속성들의 집합 74 | 75 | 한 파일에 대해 여러 개의 인덱스가 있다면, 검색 키도 여러 개 있다고 생각할 수 있다. 76 | -------------------------------------------------------------------------------- /Part_05/Chapter_14/14.2 순서 인덱스/README.md: -------------------------------------------------------------------------------- 1 | # 14.2 순서 인덱스 2 | 3 |
4 | 5 | 인덱스 구조는 파일 안에 있는 레코드에 대한 `임의 접근(random access)`**을 빨리 하기 위해서** 사용할 수 있다. 6 | 7 |
8 | 9 | ### 순서 인덱스, ordered index 10 | 11 | > entries are stored on the search key value 12 | 13 | **검색 키의 값을 정렬된 순서로 저장**하고, 검색 키와 검색 키를 포함하는 레코드를 연계시킨다. 14 | 15 |
16 | 17 | ### 클러스터링 인덱스, clustering index, clustered index 18 | 19 | > orders of keys in index = sequential order of the file 20 | 21 | 레코드를 포함하는 파일이 연속적인 순서로 저장되어 있다면, 22 | 클러스터링 인덱스는 **그 파일을 연속적인 순서로 정의한 속성을 검색 키로 사용**하는 인덱스를 말한다. 23 | 24 | - 클러스터링 인덱스는 `기본 인덱스(primary index)`라고도 부른다. 25 | - 클러스터링 인덱스의 검색 키는 주 키인 경우가 많지만 반드시 그럴 필요는 없다. 26 | 27 |
28 | 29 | ### 비클러스터링 인덱스, nonclustering index, nonclustered index 30 | 31 | - **파일의 연속적인 순서와 다른 순서**로 구성되는 검색 키의 인덱스를 말한다. 32 | - `보조 인덱스(secondary index)`라고도 부른다. 33 | 34 |
35 | 36 | ### 인덱스 순차 파일, indexed-sequential file 37 | 38 | > sequential file ordered on a search key, with a clustered index on the search key 39 | 40 | 해당 장의 1절부터 3절까지에서는 **모든 파일은 어떤 검색 키에 의한 연속적인 순서로 정렬되어 있다**고 가정한다. 41 | 42 | 이렇게 검색 키에 대해 기본 인덱스를 가지는 파일을 `인덱스 순차 파일`이라 부른다. 43 | 44 |
45 |
46 | 47 | ## 인덱스 레코드의 구성 48 | 49 | - `인덱스 레코드(index record)`, 즉 `인덱스 엔트리(index entry)`는 50 | (1) **검색 키 값**과 (2) 이를 검색 키 값으로 가지는 한 개 이상의 레코드에 대한 **포인터**로 구성되어 있다. 51 | - 포인터 : 디스크 블록의 식별자 + 블록 안에서 레코드를 구별하기 위한 오프셋(offset) 52 | 53 |
54 | 55 |

인덱스 레코드의 구성 56 | 57 |
58 |
59 |
60 | 61 | ## 14.2.1 밀집과 희소 인덱스 62 | 63 | 순서 인덱스는 두 가지 유형이 있다. 64 | 65 | - 밀집 인덱스, Dense index 66 | - 희소 인덱스, Sparse index 67 | 68 |
69 | 70 | ### 밀집 인덱스, Dense index 71 | 72 | > 인덱스 엔트리는 파일에 있는 **모든 검색 키 값에 대해** 나타난다. 73 | 74 |
75 | 76 | - `밀집 클러스터링 인덱스` 77 | \: 인덱스 레코드는 검색 키 값과 **그 검색 키 값의 첫 번째 데이터 레코드에 대한 포인터**를 포함한다. 78 | (똑같은 검색 키 값을 가진 나머지 레코드는 첫 번째 레코드 이후부터 연속적으로 저장되기 때문) 79 |
80 | 81 | - `밀집 비클러스터링 인덱스` 82 | \: 똑같은 검색 키를 가진 **모든** 레코드에 대한 포인터 목록을 저장해야 한다. 83 | 84 |
85 | 86 | 검색 키가 ID인 밀집 클러스터링 인덱스 87 | 88 |

밀집 인덱스 - ID 89 | 90 |
91 |
92 | 93 | 검색 키가 dept_name인 밀집 클러스터링 인덱스 94 | 95 |

밀집 인덱스 - dept_name 96 | 97 |
98 |
99 | 100 | ### 희소 인덱스, Sparse index 101 | 102 | > 인덱스 엔트리는 검색 키 값에 대해 **단지 몇 개만** 나타난다. 103 | 104 | - 희소 인덱스는 오직 릴레이션이 검색 키로 정렬되어 저장될 때 (= 인덱스가 `클러스터링 인덱스`인 경우) 사용될 수 있다. 105 | - 검색 키 값과 **그 검색 키 값의 첫 번째 데이터 레코드에 대한 포인터**를 포함한다. 106 | - 레코드를 위치시키기 위해서는 107 | 1. **찾고자 하는 검색 키보다 작거나 동일한 것 중 가장 큰** 검색 키를 가지는 인덱스 엔트리를 찾는다. 108 | 2. 그 검색 키 엔트리에 의해 가리켜지는 레코드를 시작으로, 그 파일에서 원하는 레코드를 찾을 때까지 포인터를 따라간다. 109 | 110 |
111 | 112 |

희소 인덱스 113 | 114 |
115 |
116 | 117 | --- 118 | 119 |
120 | 121 | - 일반적으로 레코드의 위치를 정하기 위해서는 희소 인덱스보다 `밀집 인덱스`를 사용하면 더 **빠르다**. 122 | - 그러나 `희소 인덱스`는 밀집 인덱스보다 **더 적은 공간을 요구해서** 삽입과 삭제에 대한 유지 부담이 더 적다. 123 | 124 | 이처럼 시스템 설계자는 접근 시간과 공간 부담 사이의 상반관계를 고려해야 한다. 125 | 126 |
127 | 128 | 좋은 절충안은 **블록당 하나의 인덱스 엔트리를 가지는** `희소 인덱스`를 가지는 것이다. 129 | 130 | **데이터베이스 요구를 처리하는 데 드는 비용 중 지배적인 것은 디스크에서 메인 메모리로 블록을 가져오는 데 걸리는 시간**이기 때문에, 131 | 일단 블록을 가져왔으면 전체 블록을 훑어보는 데 걸리는 시간은 대수롭지 않기 132 | 때문이다. 133 | 134 |
135 |
136 | 137 | ## 14.2.2 다계층 인덱스 138 | 139 | 인덱스가 메인 메모리에 유지될 만큼 충분히 크기가 작다면 엔트리를 찾는 데 걸리는 검색 시간은 짧다. 140 | 141 | 하지만 전체 인덱스가 메모리에 유지될 수 없을 만큼 크다면 **필요할 때마다 인덱스 블록을 디스크로부터 가져와야 하고**, 142 | 그다음에 인덱스에서 엔트리를 찾기 위해 여러 개의 디스크 블록을 읽어야 한다. 143 | 144 | → 크기가 큰 인덱스에 대한 검색은 비용이 많이 발생한다. 145 | 146 |
147 | 148 | 이 문제를 해결하기 위해서는 인덱스를 다른 순차 파일처럼 취급하여 149 | `내부 인덱스`라고 불리는 **원래의 기본 인덱스에 대한** `희소 외부 인덱스`를 구성할 수 있다. 150 | 151 | 인덱스 엔트리는 외부 인덱스를 희소하게 분포시키며, 항상 정렬된 순서로 존재한다. 152 | 153 | > 두 개 혹은 그 이상의 단계를 가지는 인덱스를 `다계층 인덱스(multilevel index)`라 한다. 154 | 155 |
156 | 157 | #### `two-level sparce index`에서 레코드의 위치를 찾기 위한 과정 158 | 159 | > outer index : a sparse index of the basic index 160 | > inner index : the basic index file→ points the read data 161 | 162 | 1. 외부 인덱스상에서 이진 검색을 이용하여 원하는 레코드보다 작거나 같은 검색 키 값 중에서 가장 큰 값을 가지는 레코드를 찾는다. 163 | **이 레코드 포인터는 내부 인덱스 블록을 가리킨다.** 164 | 2. 해당 포인터가 가리키는 블록을 스캔하여 원하는 레코드보다 작거나 같은 검색 키 값 중에서 가장 큰 값을 가지는 레코드를 찾는다. 165 | 이 레코드에 있는 포인터는 **찾고자 하는 레코드를 포함하는 파일의 블록을 가리킨다.** 166 | 167 |
168 | 169 |

보조 인덱스 170 | 171 |
172 |
173 |
174 | 175 | ## 14.2.3 인덱스 갱신 176 | 177 | 모든 인덱스는 어떤 레코드가 파일에 **삽입**되거나 파일로부터 **삭제**될 때마다 갱신되어야 한다. 178 | 179 | 파일 안에 레코드가 **갱신**된 경우에는 갱신에 영향을 받은 검색 키를 소유한 어떤 인덱스도 갱신되어야 한다. 180 | 181 | - 하지만 레코드의 갱신은 이전 레코드가 삭제되어 뒤이어 새로운 레코드의 값이 삽입되는 것으로 모델링되며, 인덱스도 삭제된 후 새로운 인덱스가 삽입되는 결과를 보인다. 182 | - 따라서 인덱스에 대한 삽입과 삭제에 대해서만 고려하며, 명시적으로 갱신을 고려하지 않아도 된다. 183 | 184 |
185 | 186 | ### 14.2.3.1 삽입, insertion 187 | 188 | 1. 시스템은 삽입되는 레코드의 검색 키 값을 사용해서 **찾기를 수행한다.** 189 | 2. 그 다음 해야할 일은 인덱스의 종류에 따라서 다르다. 190 | 191 |
192 | 193 | #### 밀집 인덱스 194 | 195 | 1. **검색 키 값이 인덱스에 없다면,** 시스템은 적당한 위치에 검색 키 값을 가지는 인덱스 엔트리를 삽입한다. 196 | 2. 그렇지 않다면, 197 | 1. 만약 인덱스 엔트리가 **똑같은 검색 키 값을 가지는 모든 레코드를 가리키는 포인터를 저장하고 있다면,** 198 | 시스템은 인덱스 엔트리에 새로운 레코드에 대한 포인터를 추가한다. 199 | 2. 그렇지 않다면 인덱스 엔트리는 검색 키 값을 가지는 첫 번째 레코드에 대한 포인터만 저장하고 있다는 것이다. 200 | → 시스템은 똑같은 검색 키 값을 가지는 다른 레코드 뒤에 삽입된 레코드를 놓는다. 201 | 202 |
203 | 204 | #### 희소 인덱스 205 | 206 | - 시스템이 **새로운 블록을 생성한다면**, 새로운 블록에 나타나는 첫 번째 검색 키 값을 인덱스에 삽입한다. 207 | - 반면, 새로운 레코드가 **그 블록 안에 있는 가장 작은 검색 키 값이라면** 시스템은 그 블록을 가리키고 있는 인덱스 엔트리를 갱신한다. 208 | - **그렇지 않으면 시스템은 인덱스를 바꾸지 않는다.** 209 | 210 |
211 | 212 | ### 14.2.3.2 삭제, deletion 213 | 214 | 1. 시스템은 먼저 삭제될 레코드를 **찾는다.** 215 | 2. 그 다음 해야할 일은 인덱스의 종류에 따라서 다르다. 216 | 217 |
218 | 219 | #### 밀집 인덱스 220 | 221 | 1. **삭제될 레코드가 특정한 검색 키 값을 가지는 유일한 레코드라면,** 시스템은 인덱스로부터 이와 대응되는 인덱스 엔트리를 삭제한다. 222 | 2. 그렇지 않다면, 223 | 1. 만약 인덱스 엔트리가 **똑같은 검색 키 값을 가지는 모든 레코드를 가리키는 포인터를 저장하고 있다면,** 224 | 시스템은 삭제된 레코드에 대한 포인터를 삭제한다. 225 | 2. 그렇지 않다면 인덱스 엔트리는 검색 키 값을 가지는 첫 번째 레코드에 대한 포인터만 저장하고 있다는 것이다. 226 | → **삭제된 레코드가 검색 키 값을 가지는 첫 번째 레코드였다면,** 시스템은 인덱스 엔트리가 다음 레코드를 가리키도록 저장한다. 227 | 228 |
229 | 230 | #### 희소 인덱스 231 | 232 | 1. 만약 인덱스가 **삭제된 레코드의 검색 키 값을 가지는 인덱스 엔트리를 포함하고 있지 않다면** 인덱스에 대해 해야 할 일은 없다. 233 | 2. 그렇지 않다면, 234 | 1. (1) 만약 **삭제된 레코드가 그 검색 키를 가지는 유일한 레코드였다면,** 시스템은 대응되는 인덱스 레코드로 교체한다. 235 | (2) **다음 검색 키 값이 이미 인덱스 엔트리에 있다면,** 이 엔트리는 교체되는 대신 삭제된다. 236 | 2. 그렇지 않다면 검색 키 값을 위한 인덱스 엔트리는 삭제된 레코드를 가리키고 있다는 것이다. 237 | → 시스템은 인덱스 레코드가 똑같은 검색 키 값을 가지는 다음 레코드를 가리키도록 갱신한다. 238 | 239 |
240 | 241 | --- 242 | 243 |
244 | 245 | 다계층 인데스를 위한 삽입과 삭제는 위의 구조를 간단히 확장하기만 하면 된다. 246 | 247 |
248 |
249 | 250 | ## 14.2.4 보조 인덱스 251 | 252 | > 보조 인덱스는 모든 검색 키 값과 모든 레코드에 대한 포인터를 가지는 인덱스 엔트리로 된 **밀집 인덱스**여야 한다. 253 | 254 | - 즉, 보조 인덱스는 **모든 레코드에 대한 포인터를 포함해야 한다.** 255 | - 레코드는 **보조 인덱스의 검색 키에 의해서가 아닌, 기본 인덱스의 검색 키에 의해 순서대로 되어 있기 때문에**, 256 | 똑같은 검색 키의 값을 가지는 나머지 레코드는 파일의 아무 곳에나 흩어져 있을 수 있다. 257 | 258 |
259 | 260 | ### 비고유 검색 키, nonunique search key 261 | 262 | 릴레이션에 동일한 검색 키 값을 가지는 레코드가 두 개 이상 존재한다면, 263 | 즉 **두 개 이상의 레코드가 인덱싱 속성에 대해 동일한 값을 가질 수 있다면,** 이러한 검색 키를 `비고유 검색 키`라고 한다. 264 | 265 | > 비고유 검색 키에 대해서 보조 인덱스를 구현하려면, 266 | > 보조 인덱스에 있는 각각의 포인터는 **그 파일에 대한 포인터를 담고 있는 버켓을 가리켜야 한다.** 267 | 268 |
269 | 270 | 단점 271 | 272 | - 임의 I/O 작업이 필요한 간접 참조로 인해 인덱스 접근 시 시간이 더 오래 걸린다. 273 | - 키에 중복이 거의 없거나 전혀 없는 경우, 전체 블록이 해당 버켓에 할당되면 많은 공간 낭비가 발생한다. 274 | 275 |
276 | 277 | 클러스터링 인덱스 순서에서 연속적으로 스캔하는 것은 능률적이다. 278 | (파일에 있는 레코드가 인덱스의 순서와 똑같은 순서로 물리적으로 저장되어 있기 때문) 279 | 280 | 그러나 파일을 보조 키 순서대로 스캔을 시도한다면, 각 레코드를 읽는 것은 디스크로부터 새로운 블록 읽기를 요구하는 것과 같기 때문에 매우 느리다. 281 | 282 |
283 | 284 | 보조 인덱스는 기본 인덱스의 검색 키가 아닌 다른 키를 사용하는 질의문의 성능을 향상시키지만, 데이터베이스 변경에 상당한 부담을 강요한다. 285 | 286 | 따라서 보조 인덱스는 검색만을 위한 질의와 287 | 데이터 변경의 상대적인 빈도에 대한 평가에 기초해서 결정되어야 한다. 288 | 289 |
290 |
291 | 292 | ## 14.2.5 다중 키상의 인덱스 293 | 294 | > **두 개 이상의 속성으로 구성된 검색 키**를 `복합 검색 키(composite search key)`라고 한다. 295 | 296 | - 검색 키가 하나의 속성이 아니라, 속성의 목록으로 되어 있다. 297 | - 검색 키는 **값의 튜플**인 (a1, … , an) 형식으로 표현될 수 있으며, 이때 인덱스의 속성은 A1, … , An이다. 298 | - 검색 키 값의 순서는 `사전적 순서(lexicographic ordering)`이다. 299 | -------------------------------------------------------------------------------- /Part_05/Chapter_14/14.3 B+-트리 인덱스 파일/README.md: -------------------------------------------------------------------------------- 1 | # 14.3 B+-트리 인덱스 파일 2 | 3 |
4 | 5 | ### 인덱스 순차 파일의 단점 6 | 7 | - 파일이 커질수록, 인덱스를 찾아서 그 데이터를 연속으로 스캔하는 성능이 감소한다. 8 | - 성능 감소는 파일을 재구성함으로써 제거될 수 있지만, 파일 재구성에 드는 비용은 크다. 9 | 10 |
11 | 12 | ## B+-tree index 13 | 14 | > `균형 트리(balanced tree)` 형태이다. 15 | > 즉, 트리의 `루트(root)`에서 `단말 노드(leaf node)`까지 **모든 경로의 길이가 같다.** 16 | 17 | > B+-tree의 “B” : balanced 18 | > → 이 속성으로 인해 검색, 삽입, 삭제의 성능을 좋게 한다. 19 | 20 |
21 | 22 | - root 노드를 제외한 비단말 노드는 **⎡n/2⎤~ n** 사이의 자식(children)을 가지고 있다. 23 | 즉, 50% 이상이 차있어야 하는 것이다. (n은 특정한 트리에 대해 고정된 값) 24 | - leaf 노드는 **⎡(n-1)/2⎤~ n-1** 사이의 개수만큼 value를 가진다. 25 | - special cases 26 | - root 노드는 2 ~ n개 사이의 자식을 갖는다. 27 | - root 노드가 leaf 노드라면(= 트리에 root 노드만이 존재한다면) 0 ~ (n-1) 사이의 개수만큼 value를 가진다. 28 | 29 |
30 | 31 |

B+-tree index 32 | 33 |
34 |
35 | 36 | 이 구조는 삽입과 삭제 시 성능 부담과 공간 부담을 준다. 37 | 38 | 하지만 이 성능 부담은 파일의 변경이 많은 경우에 파일 재구성 비용을 피할 수 있기에 수용될 수 있다. 39 | 40 |
41 |
42 | 43 | ## 14.3.1 B+-트리의 구조 44 | 45 | - B+-트리 인덱스는 다계층 인덱스이다. 46 | - 중복 검색 키 값이 없다고 가정하자. 즉, 각각의 `검색 키(search key)`는 고유하다. 47 | 48 |
49 | 50 | - n-1개의 검색 키 값 K 51 | - n개의 포인터 P 52 | 53 |

node 54 | 55 |
56 | 57 |

pointers 58 | 59 |
60 |
61 | 62 | > 노드 안의 검색 키 값은 **정렬된 순서**로 유지된다. 63 | > → K1 < K2 < K3 < … < Kn-1 64 | 65 |
66 | 67 | ### 단말 노드(leaf node) 68 | 69 | - 포인터 Pi는 검색 키 값 Ki를 가지는 파일 레코드를 가리킨다. 70 | - 적어도 ⎡(n-1)/2⎤개의 value를 포함해야 한다. 71 | 72 | > leaf 노드를 **검색 키 순서로 서로 연결하기 위해서** 포인터 Pn을 사용한다. 73 | > → 파일의 연속적인 처리에 대한 성능 ↑ 74 | 75 |
76 | 77 | e.g., n = 4 78 | 79 |

leaf nodes 80 | 81 |
82 |
83 | 84 | ### 비단말 노드(non-leaf node) 85 | 86 | - `내부 노드(internal node)`라고도 부른다. 87 | - leaf 노드 상에서 `다계층 (희소) 인덱스(multi-level sparse index)`를 형성한다. 88 | - 모든 포인터가 **트리 노드에 대한 포인터**인 것을 제외하고는 leaf 노드의 구조와 동일하다. 89 | - ⎡n/2⎤ ~ n개 사이의 개수만큼 포인터를 가질 수 있다. (한 노드의 포인터 수 : 그 노드의 `팬아웃(fanout)`) 90 | 91 |
92 | 93 |

non-leaf nodes 94 | 95 |
96 |
97 | 98 | --- 99 | 100 |
101 | 102 | m(≤ n)개의 포인터를 포함하는 노드 103 | 104 | - i = 2, 3, … , m-1일 때, 105 | 포인터 Pi는 **Ki 보다는 작고, Ki-1보다는 크거나 같은** 검색 키 값을 포함하는 서브 트리(subtree)를 가리킨다. 106 | - 포인터 Pm은 Km-1보다 크거나 같은 키 값을 포함하는 서브 트리를 가리킨다. 107 | - 포인터 P1은 K1보다 작은 검색 키 값을 포함하는 서브 트리를 가리킨다. 108 | 109 | → 아래 예시를 같이 보면 쉽게 이해할 수 있을 것! 110 | 111 |
112 | 113 | e.g., B+-tree for instructor file (n = 6) 114 | 115 |

b+-tree for instructor file 116 | 117 |
118 |
119 |
120 | 121 | ## 14.3.2 B+-트리에서 질의 122 | 123 | - `Point queries` : find(v) 124 | - `Range queries` : findRange(lb, ub) 125 | 126 |
127 | 128 |

find 129 | 130 |
131 |
132 | 133 | ### 질의 비용 134 | 135 | - root에서 일부 leaf 노드까지 트리의 경로를 탐색해야 한다. 136 | - 파일에 레코드 N개가 있다면, 그 경로는 ⎡log⎡n/2⎤(N)⎤보다 더 길지 않다. 137 | - 따라서 읽어야 하는 디스크 블록의 개수가 상당히 절감된다. 138 | 139 | > B+-트리는 각 노드가 크고(일반적으로 디스크 블록 크기), 각 노드는 많은 수의 포인터를 가질 수 있다. 140 | > → 굵고 짧은 형태 (↔︎ 이진트리 : 가늘고 긴 형태) 141 | 142 |
143 | 144 | - leaf 노드로 이동한 후, 고유한 검색 키의 단일값에 대한 질의의 경우 일치하는 레코드를 가져오기 위해 하나 이상의 임의 I/O가 필요하다. 145 | - 범위 질의(range query)는 leaf 노드까지 순회한 후, **주어진 범위 내에 있는 모든 포인터를 검사**하는 추가 비용이 발생한다. 146 | 147 |
148 |
149 | 150 | ## 14.3.3 B+-트리 갱신 151 | 152 | ### 14.3.3.1 삽입 153 | 154 |

insert 155 | 156 |
157 |
158 | 159 | “Lamport” 삽입 결과 160 | 161 |

insert result 162 | 163 |
164 |
165 | -------------------------------------------------------------------------------- /Part_07/Chapter_17/17.1 트랜잭션 개념/README.md: -------------------------------------------------------------------------------- 1 | # 17.1 트랜잭션 개념 2 | 3 |
4 | 5 | ### 트랜잭션, transaction 6 | 7 | > 다양한 데이터 항목에 접근하고 갱신하는 프로그램 수행의 **단위** 8 | 9 | - 한 트랜잭션은 `begin transaction`과 `end transaction` 사이에서 실행되는 연산으로 구성되어 있다. 10 | - 보통 한 트랜잭션은 고급 데이터 조작 언어(주로 SQL)나 JDBC나 ODBC를 사용해 11 | 데이터베이스에 접근하는 프로그래밍 언어로 작성된 사용자 프로그램으로 수행된다. 12 | 13 |
14 |
15 | 16 | ## ACID property 17 | 18 | ### 원자성, atomicity 19 | 20 | > 트랜잭션의 모든 연산이 정상적으로 수행 완료되거나, 어떠한 연산도 수행되지 않은 원래 상태가 되도록 해야 한다. 21 | 22 | > Either all operations of the transaction are properly reflected in the database or none are. 23 | 24 | - `all-or-none` : 전부 아니면 전무 25 | - 트랜잭션은 나눌 수 없기 때문에, 전부 실행되거나 전부 실행되지 않아야 한다. 26 | 27 |
28 | 29 | ### 일관성, consistency 30 | 31 | > 고립 상태(= 동시에 수행되는 트랜잭션이 없는 상태)에서 32 | > 트랜잭션 수행이 데이터베이스의 일관성을 보존해야 한다. 33 | 34 | > Atomic execution of a transaction in isolation preserves the consistency of the database. 35 | 36 | - 만약 한 트랜잭션이 일관된 상태의 데이터베이스에서 원자적이고 고립된 상태로 실행되었다면 37 | 데이터베이스는 **트랜잭션이 종료된 후에도 일관된 상태여야 한다.** 38 | - 데이터 무결성 제약 조건(주 키 제약 조건, 참조 키 제약 조건 등) 뿐만 아니라, SQL을 사용해 기술할 수 없는 응용 프로그램 자체의 일관성 조건을 보장해야 한다. → 이런 제약 조건을 지키는 것은 트랜잭션을 39 | 만드는 프로그래머의 책임이다. 40 | 41 |
42 | 43 | ### 고립성, isolation 44 | 45 | > 여러 트랜잭션이 동시에 수행되더라도, 각 트랜잭션은 시스템에서 다른 트랜잭션이 동시에 수행되고 있는지를 알지 못하는 것과 같아야 한다. 46 | 47 | > Although multiple transactions may execute concurrently, each transaction must be unaware of other concurrently 48 | > executing transactions. Intermediate transaction results must be hidden from other concurrently executed transactions. 49 | 50 | - 모든 트랜잭션 Ti와 Tj의 쌍에 대해 / 데이터베이스 시스템은 Ti에게 Ti가 시작되기 전에 Tj가 수행을 끝마쳤거나, 51 | 아니면 Ti가 수행을 끝마친 후에 Tj가 수행을 시작하는 것과 같이 되도록 보장해야 한다. 52 | - 데이터베이스 시스템은 **동시에 수행되는 다른 데이터베이스 명령어의 영향을 받지 않고** 트랜잭션이 올바르게 수행할 수 있도록 특별한 조치를 해야 한다. 53 | - 고립성을 유지하는 것은 데이터베이스 시스템의 성능에 부정적인 영향을 미치기 때문에 몇몇 응용 프로그램은 고립성을 지키지 않기도 한다. 54 | 55 |
56 | 57 | ### 지속성, durability 58 | 59 | > 트랜잭션이 성공적으로 수행 완료되고 나면, 트랜잭션에 의해 변경된 데이터베이스 내용은 시스템에 오류가 발생한다고 하더라도 **영구적으로 반영되어야 한다.** 60 | 61 | > After a transaction completes successfully, the changes it has made to the database persistent, even if there are 62 | > system failures. 63 | -------------------------------------------------------------------------------- /Part_07/Chapter_17/17.2 간단한 트랜잭션 모델/README.md: -------------------------------------------------------------------------------- 1 | # 17.2 간단한 트랜잭션 모델 2 | 3 |
4 | 5 | 트랜잭션은 두 가지 연산을 이용하여 데이터에 접근한다. 6 | 7 | > `read(X)` 8 | > (1) 데이터 항목 X를 데이터베이스로부터 읽어서 9 | > (2) read 연산을 수행하는 트랜잭션의 메인 메모리 버퍼에 있는 X라는 변수에 저장한다. 10 | 11 | > `write(X)` 12 | > write 연산을 수행하는 트랜잭션의 메인 메모리 버퍼에 있는 변수 X의 값을 데이터베이스의 데이터 항목 X에 저장한다. 13 | 14 |
15 | 16 | 데이터 항목에 대한 변경이 메인 메모리에만 반영되었는지, 아니면 디스크에도 기록되었는지 판단하는 것이 중요하다. 17 | 18 | 실제 데이터베이스 시스템에서 write 연산에 의한 중간 갱신 결과를 즉시 디스크에 저장하지 않고, 19 | 다른 곳에 임시로 저장했다가 나중에 디스크에 저장할 수도 있기 때문이다. 20 | 21 | (이 절에서는 write 연산이 데이터베이스를 즉시 갱신한다고 가정한다.) 22 | 23 |
24 |
25 | 26 | ## e.g., Transaction to transfer $50 from account A to account B 27 | 28 | 트랜잭션은 다음과 같이 작성된다. 29 | 30 | ``` 31 | read(A) 32 | A := A - 50 33 | write(A) 34 | read(B) 35 | B := B + 50 36 | write(B) 37 | ``` 38 | 39 |
40 | 41 | ### 일관성 42 | 43 | - 일관성 요구 조건 : 계좌 A와 B의 잔액 합이 트랜잭션 수행이 끝난 후에도 변하지 않아야 한다. 44 | - 각각의 트랜잭션에 대한 일관성을 보장하는 것은 트랜잭션을 작성하는 응용 프로그래머의 책임이다. 45 | 46 |
47 | 48 | ### 원자성 49 | 50 |

transaction 51 | 52 |
53 |
54 | 55 | > `비일관성 상태, inconsistent state` 56 | > 데이터베이스 시스템에 실패가 발생하여 더 이상 실세계의 실제 상태를 반영하지 못하게 된 상태 57 | 58 | → **트랜잭션이 시작되지 않았다거나, 아니면 완료되었다는 것을 보장할 수만 있다면** 59 | 비일관성 상태는 트랜잭션을 실행하는 동안을 제외하고는 나타나지 않는다. 60 | 61 |
62 | 63 | #### 원자성을 보장하기 위한 기본 방법 64 | 65 | 1. 데이터베이스 시스템은 트랜잭션이 write 연산을 하는 데이터의 예전 값을 게속 추적하고, 이 정보는 `로그(log)`라고 불리는 파일에 기록된다. 66 | 2. 트랜잭션이 정상적으로 종료하지 못하면 데이터베이스 시스템은 **로그를 사용해 데이터의 이전 값으로 복구한다.** 67 | 이로써 마치 트랜잭션이 전혀 실행되지 않았던 것처럼 보이게 한다. 68 | 69 |
70 | 71 | ### 지속성 72 | 73 | - 지속성 요구 조건 : 트랜잭션이 성공적으로 종료된 이후에는 시스템 오류가 발생하더라도 74 | 그 트랜잭션이 처리한 모든 갱신 결과가 데이터베이스에 지속되어야 한다. 75 | - 다음 둘 중 한가지를 지키면 지속성을 보장할 수 있다. 76 | 1. 트랜잭션이 수행한 갱신을 트랜잭션이 완료되기 전에 디스크에 기록한다. 77 | 2. 데이터베이스 시스템이 시스템 오류 후에 재시작되었을 때, 78 | 실패한 트랜잭션이 갱신한 데이터를 다시 복구할 수 있을 만큼 충분한 정보를 디스크에 기록한다. 79 | 80 |
81 | 82 | > `복구 시스템(recovery system)`이 원자성과 지속성을 보장하는 역할을 한다. (19장에서 설명) 83 | 84 |
85 | 86 | ### 고립성 87 | 88 | - 고립성 요구 조건 : 트랜잭션의 동시 실행 결과가 트랜잭션을 한 번에 하나씩 순차적으로 실행해서 얻은 결과와 같다는 것을 보장해야 한다. 89 | - 여러 트랜잭션이 동시에 수행되면 **그 트랜잭션을 구성하는 연산이 예기치 않은 순서로 배치되고**, 90 | 이에 따라 비일관성 상태가 발생할 수 있다. 91 | - 동시에 실행하는 트랜잭션으로 인한 문제를 피하기 위한 한 방법은 순차적으로 트랜잭션을 실행하는 것이나, 이는 상당한 성능 저하를 일으킨다. 92 | 93 |
94 | 95 | > 고립성은 `동시성 제어 시스템(concurrency-control system)`이라는 데이터베이스 시스템의 구성요소가 책임지고 있다. 96 | -------------------------------------------------------------------------------- /Part_07/Chapter_17/17.4 트랜잭션 원자성과 지속성/README.md: -------------------------------------------------------------------------------- 1 | # 17.4 트랜잭션 원자성과 지속성 2 | 3 |
4 | 5 | ## Transaction State 6 | 7 | ### 동작, Active 8 | 9 | 초기 상태로, 트랜잭션이 실행 중인 상태 10 | 11 |
12 | 13 | ### 부분 커밋, Partially committed 14 | 15 | 마지막 명령문이 실행된 후의 상태 16 | 17 |
18 | 19 | ### 실패, Failed 20 | 21 | 정상적인 실행이 더 진행될 수 없을 때 가지는 상태 22 | 23 |
24 | 25 | ### 중단, Aborted 26 | 27 | 트랜잭션이 `롤백(rollback)`되고, 데이터베이스가 트랜잭션의 시작 전 상태로 환원되고 난 후의 상태 28 | 29 |
30 | 31 | > 중단된 트랜잭션에 의해 수행된 갱신 내용이 무효가 될 때 **트랜잭션이 롤백(rollback)되었다**고 한다. 32 | > 이 부분은 트랜잭션의 중단을 관리하는 복구 기법이 책임지며, 트랜잭션의 중단과 롤백은 주로 `로그(log)`를 유지하는 방법을 통해 이루어진다. 33 | 34 | - 로그 : 갱신을 수행한 트랜잭션의 식별자, 수정하는 데이터 항목의 식별자, 데이터 항목의 이전 값과 새로운 값(수정 값)을 기록한다. 35 | - **로그를 기록한 후에야 비로소 데이터베이스에 수정 내용이 반영된다.** 36 | 37 |
38 | 39 | ### 커밋, Committed 40 | 41 | 트랜잭션이 성공적으로 완료된 후의 상태 42 | 43 |
44 | 45 | > 성공적으로 실행을 완료한 트랜잭션은 **커밋(commit)되었다**고 한다. 46 | 47 | 갱신을 수행한 트랜잭션이 커밋되었다면 데이터베이스는 그 트랜잭션에 의해 새로운 일관된 상태로 변경된 것이다. 48 | 49 |
50 |
51 | 52 | ## 트랜잭션의 상태 다이어그램 53 | 54 |

트랜잭션의 상태 다이어그램 55 | 56 | > 트랜잭션이 커밋(committed)되었거나 중단(aborted)되었다면 그 트랜잭션은 `종료(terminated)`되었다고 할 수 있다. 57 | 58 |
59 | 60 | 1. 트랜잭션은 `동작(active) 상태`에서 시작한다. 61 | 2. 트랜잭션이 마지막 명령문을 실행하고 나면 `부분 커밋(partially committed) 상태`로 들어가게 된다. 62 | - 트랜잭션은 자신의 모든 실행을 완료했지만, 여전히 중단될 가능성을 가진다. 63 | - 실행 결과가 아직 메인 메모리에 존재하는 상황이기 때문에, 64 | 데이터베이스 시스템은 만약 실패가 발생했더라도 시스템이 재시작되었을 때 갱신 내용이 다시 수행될 수 있도록 충분한 정보를 디스크에 저장한다. 65 | 3. **복구에 필요한 정보가 모두 저장되었을 때** 트랜잭션은 `커밋(committed) 상태`로 들어가게 된다. 66 | 67 |
68 | 69 | --- 70 | 71 |
72 | 73 | 만약 트랜잭션이 더는 정상적인 실행을 진행할 수 없다고 판단된다면 트랜잭션은 `실패(failed) 상태`로 들어가게 된다. 74 | 75 | 이러한 트랜잭션은 반드시 롤백되어야 하며, 그 다음 트랜잭션은 `중단(aborted) 상태`로 들어간다. 76 | 77 |
78 | 79 | 이 시점에서 시스템은 두 가지 선택 사항을 가진다. 80 | 81 | 1. **하드웨어 오류** 또는 트랜잭션 자체의 논리적 오류에 의하지 않은 **소프트웨어 오류**로 인해 중단되었을 경우 82 | - 트랜잭션을 재시작할 수 있다. 83 | - `재시작(restart)`된 트랜잭션은 새로운 트랜잭션으로 간주한다. 84 | 2. 응용 프로그램을 직접 수정해야 하는 논리적 오류가 있거나 입력이 잘못된 경우, 또는 필요한 데이터가 데이터베이스에 없는 경우 85 | - 트랜잭션을 `강제 종료(kill)`시킬 수 있다. 86 | -------------------------------------------------------------------------------- /Part_07/Chapter_17/17.5 트랜잭션 고립성/README.md: -------------------------------------------------------------------------------- 1 | # 17.5 트랜잭션 고립성 2 | 3 |
4 | 5 | ## 트랜잭션 동시성 허용의 이점 6 | 7 | 트랜잭션 처리 시스템은 보통 **여러 트랜잭션이 동시에 수행되는 것**을 허용하나, 이는 데이터의 일관성과 관련된 여러 가지 복잡한 문제를 발생시킨다. 8 | 9 | 동시에 여러 트랜잭션의 동시성과 일관성을 모두 보장하기 위해서는 추가적인 노력이 필요하다. 10 | 11 | 트랜잭션이 한 번에 하나씩 `순차적으로(serially)` 실행되도록 하면 문제는 간단해지지만, 동시성을 허용함으로써 다음 두 가지 이점을 얻을 수 있다. 12 | 13 |
14 | 15 | ### 처리율과 자원 이용률 향상 16 | 17 | CPU와 디스크는 서로 병렬적으로 동작할 수 있기 때문에, I/O 작업은 CPI 처리가 필요한 작업과 병렬적으로 처리될 수 있다. 18 | 19 | 이러한 CPU와 I/O 시스템의 병렬성은 여러 트랜잭션을 동시에 실행할 수 있도록 해주어, 20 | 결국 시스템의 `처리율(throughput)`, 즉 **주어진 시간에 처리되는 트랜잭션의 수**를 높인다. 21 | 22 | 마찬가지로 프로세서와 디스크가 작업을 처리하지 않고 정지해 있는 휴식 시간을 줄일 수 있어, 시스템의 `이용률(utilization)` 또한 증가한다. 23 | 24 |
25 | 26 | ### 대기 시간 감소 27 | 28 | 트랜잭션의 실행 시간은 각각 다른데, 만약 트랜잭션이 순차적으로 실행된다면 29 | **짧은 트랜잭션이 긴 트랜잭션이 끝날 때까지 오랜 시간을 기다리고 있어야 하는** 상황이 발생할 수 있다. 30 | 31 | 이는 트랜잭션 수행의 지연을 초래하게 된다. 32 | 33 | 따라서 동시 수행은 트랜잭션의 예기치 않은 지연을 줄일 수 있으며, 34 | `평균 응답 시간(average response time)`, 즉 **트랜잭션이 요청된 후에 완료될 때까지 걸리는 평균 시간**도 줄일 수 있다. 35 | 36 |
37 | 38 | > 데이터베이스에서 동시 수행을 적용하게 된 동기 39 | > == 운영체제에서 `다중 프로그래밍(multi-programming)`을 사용하게 된 동기 40 | 41 |
42 |
43 | 44 | ## 동시성 제어 기법, Concurrency control schemes 45 | 46 | > mechanisms to achieve **isolation** 47 | 48 | > 여러 트랜잭션이 동시에 수행될 때 `고립성`이 보장되지 않으면, 49 | > 개별 트랜잭션이 정상적으로 처리되고 있더라도 데이터베이스 `일관성`은 깨질 수 있다. 50 | 51 | - 데이터베이스 시스템은 데이터베이스의 일관성을 유지하기 위해 트랜잭션 간의 상호작용을 반드시 제어해야 한다. 52 | - 이는 동시성 제어 기법이라고 하는 다양한 기법으로 처리할 수 있다. (18장에서 설명) 53 | 54 |
55 |
56 | 57 | ## 스케줄, schedule 58 | 59 | > specify **the order** in which instructions of concurrent transactions are executed 60 | > 스케줄은 실행 중인 트랜잭션들이 **어떤 순서에 따라** 실행되는지를 보여준다. 61 | 62 | 일련의 트랜잭션 스케줄은 반드시 그 트랜잭션의 모든 명령어를 포함하고 있어야 하며, 63 | 명령어는 개별 트랜잭션의 명령어 순서를 따라야 한다. 64 | 65 |
66 | 67 | - A transaction that **succesfully complete**s its execution will have a `commit instruction` as the last statement 68 | - A transaction that **fails to complete** its execution will have an `abort instruction` as the last statement 69 | 70 |
71 | 72 | ### e.g., 은행 시스템 예시 73 | 74 | `트랜잭션 T1` : 계좌 A에서 계좌 B로 $50을 이체한다. 75 | 76 | ``` 77 | T1 : read(A); 78 | A := A - 50; 79 | write(A); 80 | read(B); 81 | B := B + 50; 82 | write(B). 83 | ``` 84 | 85 |
86 | 87 | `트랜잭션 T2` : 계좌 A의 잔액의 10%를 계좌 B로 이체한다. 88 | 89 | ``` 90 | T2 : read(A); 91 | temp := A * 0.1; 92 | A := A - temp; 93 | write(A); 94 | read(B); 95 | B := B + temp; 96 | write(B). 97 | ``` 98 | 99 |
100 | 101 | #### Serial Schedule 1 102 | 103 | > a serial schedule in which T1 is followed by T2 104 | 105 |

Serial Schedule 1 106 | 107 |
108 |
109 | 110 | #### Serial Schedule 2 111 | 112 | > a serial schedule in which T2 is followed by T1 113 | 114 |

Serial Schedule 2 115 | 116 |
117 |
118 | 119 | #### Serializable Schedule 3 120 | 121 | > the following schedule **is not a serial schedule**, but it is `equivalent` to Schedule 1 122 | 123 |

Serializable Schedule 3 124 | 125 |
126 |
127 | 128 | #### Schedule 4 129 | 130 | > the following schedule does not preserve the value of (A+B) 131 | 132 |

Schedule 4 133 | 134 | → `비일관성(inconsistent) 상태` 135 | 136 |
137 |
138 |
139 | 140 | ## 직렬성, Serializability 141 | 142 | 동시 수행한 스케줄의 결과가 **트랜잭션을 하나씩 순차적으로 수행하는 스케줄의 실행 결과와 동일**하게 함으로써 데이터베이스의 일관성을 보장할 수 있다. 143 | 144 | 이런 스케줄을 `직렬 가능(serializable) 스케줄`이라고 한다. 145 | 146 |
147 | 148 | > **serial execution** of a set of transactions preserves database consistency 149 | > → a schedule is `serializable` if it is equivalent to a serial schedule 150 | 151 | *→ 6절에서 이어서 설명* 152 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Database-System-Concepts 2 | 3 | [데이터베이스 시스템(7판)](http://www.yes24.com/Product/Goods/103156919)을 읽고, 그 내용과 개념을 정리한 레포지토리입니다. 4 | 5 | 잘못된 내용은 이슈와 PR로 알려주세요 😉 6 | 7 |
8 | 9 | ## 📌 데이터베이스 시스템 10 | 11 | 1. [서론](/Chapter_01) 12 | 13 | ### Part 1. 관계형 언어 14 | 15 | 2. [관계형 모델 소개](/Part_01/Chapter_02) 16 | 3. [SQL 소개](/Part_01/Chapter_03) 17 | 4. 중급 SQL 18 | 5. 고급 SQL 19 | 20 | ### Part 2. 데이터베이스 설계 21 | 22 | 6. [E-R 모델을 사용한 데이터베이스 설계](/Part_02/Chapter_06) 23 | 7. [관계형 데이터베이스 설계](/Part_02/Chapter_07) 24 | 25 | ### Part 3. 응용 프로그램의 설계 및 개발 26 | 27 | 8. 복합 데이터 타입 28 | 9. 응용 프로그램의 개발 29 | 30 | ### Part 4. 빅데이터 분석 31 | 32 | 10. 빅데이터 33 | 11. 데이터 분석 34 | 35 | ### Part 5. 저장 장치 관리 및 인덱싱 36 | 37 | 12. [물리적 저장 장치 시스템](/Part_05/Chapter_12) 38 | 13. [데이터 저장 장치 구조](/Part_05/Chapter_13) 39 | 14. [인덱싱](/Part_05/Chapter_14) 40 | 41 | ### Part 6. 질의 처리와 최적화 42 | 43 | 15. 질의 처리 44 | 16. 질의 최적화 45 | 46 | ### Part 7. 트랜잭션 관리 47 | 48 | 17. [트랜잭션](/Part_07/Chapter_17) 49 | 18. 동시성 제어 50 | 19. 복구 시스템 51 | 52 | ### Part 8. 병렬 및 분산 데이터베이스 53 | 54 | 20. 데이터베이스 시스템 구조 55 | 21. 병렬 및 분산 데이터 저장소 56 | 22. 병렬 및 분산 질의 처리 57 | 23. 병렬 및 분산 트랜잭션 처리 58 | 59 | ### Part 9. 고급 주제 60 | 61 | 24. 고급 인덱싱 기술 62 | 25. 고급 응용 프로그램 개발 63 | 26. 블록체인 데이터베이스 64 | --------------------------------------------------------------------------------