Join (SQL)
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
Join은 관계형 데이터베이스에서 여러 테이블의 데이터를 결합하는 데 사용되는 SQL 연산이다. 정규화된 데이터베이스에서 정보 중복을 줄이기 위해 여러 테이블로 분리된 관련 데이터를 효과적으로 검색하고 통합하는 데 필수적이다. Join은 교차 조인, 내부 조인(동일 조인, 자연 조인 포함), 외부 조인(왼쪽, 오른쪽, 완전 외부 조인) 등 다양한 유형이 있으며, 각 유형은 데이터 결합 방식과 결과 집합에 미치는 영향이 다르다. 데이터베이스 시스템은 쿼리 옵티마이저를 통해 조인의 효율적인 실행을 위해 조인 순서 및 방법을 결정하며, 중첩 루프, 정렬-병합, 해시 조인과 같은 다양한 조인 알고리즘을 활용한다. 조인 인덱스는 쿼리 성능을 향상시키는 데 사용되며, 데이터 분석, 보고서 생성, 데이터 통합 등 다양한 분야에서 활용된다.
더 읽어볼만한 페이지
- SQL 키워드 - TRUNCATE (SQL)
TRUNCATE는 SQL에서 테이블 내의 모든 데이터를 빠르게 삭제하는 명령어로, 외래 키 제약 조건 무시, 테이블 잠금 방식, 트랜잭션 처리 방식 등 DELETE 명령어와 차이를 보이며, WHERE 절을 사용할 수 없어 테이블의 모든 행을 삭제하고, 일부 데이터베이스 시스템에서는 롤백이 불가능할 수 있다. - SQL 키워드 - Null (SQL)
Null은 SQL에서 데이터베이스 테이블 열의 값 부재를 나타내는 특별한 표식으로, 0이나 빈 문자열과 구별되며 삼진 논리와 관련된 특별한 처리 방식으로 인해 데이터베이스 설계 및 쿼리 작성 시 주의가 필요하고 SQL 표준 구현에 대한 논쟁이 존재한다.
| Join (SQL) | |
|---|---|
| 조인 (SQL) | |
![]() | |
| 종류 | SQL |
| 설명 | 여러 테이블의 행을 연결하는 방법 |
| 조인 연산 | |
| 내부 조인 (Inner Join) | 양쪽 테이블 모두에서 일치하는 행만 반환 |
| 왼쪽 조인 (Left Join) | 왼쪽 테이블의 모든 행과 오른쪽 테이블에서 일치하는 행을 반환 (오른쪽 테이블에 일치하는 행이 없으면 NULL 값으로 채움) |
| 오른쪽 조인 (Right Join) | 오른쪽 테이블의 모든 행과 왼쪽 테이블에서 일치하는 행을 반환 (왼쪽 테이블에 일치하는 행이 없으면 NULL 값으로 채움) |
| 완전 외부 조인 (Full Outer Join) | 양쪽 테이블의 모든 행을 반환 (일치하는 행이 없으면 NULL 값으로 채움) |
| 교차 조인 (Cross Join) | 양쪽 테이블의 모든 가능한 조합을 반환 (데카르트 곱) |
| 추가 정보 | |
| 비고 | 조인 연산은 데이터베이스 쿼리에서 매우 중요한 역할을 수행함 적절한 조인 연산 선택은 쿼리 성능에 큰 영향을 미침 |
2. 예제 테이블
위 테이블에서 `Department` 테이블의 `DepartmentID`는 기본 키이고, `Employee` 테이블의 `DepartmentID`는 외래 키이다.
`Employee` 테이블의 "John"은 부서가 할당되지 않았고, `Department` 테이블의 "마케팅" 부서에는 직원이 없다.
2. 1. 테이블 구조
'''주의''': 위의 `Employee` 테이블에서 "윌리엄스"라는 직원은 아직 어떤 부서에도 할당되지 않았다. 또한 어떠한 직원도 "마케팅" 부서에 할당되지 않았음을 유의해라.
2. 2. 샘플 데이터
'''주의''': 위의 Employee 테이블에서, "John"이라는 직원은 아직 어떤 부서에도 할당되지 않았다. 또한 어떠한 직원도 "마케팅" 부서에 할당되지 않았음을 유의해라.
조인 유형을 설명하기 위해 이 문서의 나머지 부분에서는 다음 표를 사용한다.
| 성(姓) | 부서ID |
|---|---|
| 라퍼티 | 31 |
| 존스 | 33 |
| 하이젠베르크 | 33 |
| 로빈슨 | 34 |
| 스미스 | 34 |
| 윌리엄스 |
| 부서ID | 부서명 |
|---|---|
| 31 | 판매 |
| 33 | 엔지니어링 |
| 34 | 사무 |
| 35 | 마케팅 |
2. 3. 테이블 생성 SQL
sqlCREATE TABLE department
(
DepartmentID INT,
DepartmentName VARCHAR(20)
);
CREATE TABLE employee
(
LastName VARCHAR(20),
DepartmentID INT
);
INSERT INTO department(DepartmentID, DepartmentName) VALUES(31, '영업부');
INSERT INTO department(DepartmentID, DepartmentName) VALUES(33, '기술부');
INSERT INTO department(DepartmentID, DepartmentName) VALUES(34, '사무부');
INSERT INTO department(DepartmentID, DepartmentName) VALUES(35, '마케팅');
INSERT INTO employee(LastName, DepartmentID) VALUES('Rafferty', 31);
INSERT INTO employee(LastName, DepartmentID) VALUES('Jones', 33);
INSERT INTO employee(LastName, DepartmentID) VALUES('Steinberg', 33);
INSERT INTO employee(LastName, DepartmentID) VALUES('Robinson', 34);
INSERT INTO employee(LastName, DepartmentID) VALUES('Smith', 34);
INSERT INTO employee(LastName, DepartmentID) VALUES('John', NULL);
3. 조인의 종류
조인은 SQL에서 둘 이상의 테이블을 결합하여 데이터를 검색하는 데 사용되는 방법이다. 조인은 크게 내부 조인, 외부 조인, 교차 조인, 자가 조인 등으로 나눌 수 있다.
- 내부 조인 (Inner Join): 두 테이블에서 지정된 조건이 참인 행만 반환한다.
- 외부 조인 (Outer Join): 한쪽 테이블의 모든 행과 다른 쪽 테이블에서 조건이 참인 행을 반환한다. 조건이 참이 아닌 경우, 다른 쪽 테이블의 열은 NULL 값으로 채워진다. 외부 조인은 왼쪽, 오른쪽, 완전 외부 조인으로 나뉜다.
- 교차 조인 (Cross Join): 두 테이블의 모든 가능한 행 조합을 반환한다.
- 자가 조인 (Self-Join): 테이블 자기 자신을 조인한다.
각 조인 유형에 대한 자세한 내용은 하위 섹션을 참조하면 된다.
3. 1. 교차 조인 (Cross Join)
`CROSS JOIN` 절은 조인되는 두 테이블의 곱집합을 반환한다. 즉, 두 번째 테이블의 각 행과 첫 번째 테이블의 각 행이 한 번씩 결합된 열을 생성한다. 예를 들어 m행을 가진 테이블과 n행을 가진 테이블을 교차 조인하면 m*n 개의 행이 생성된다.[17]교차 조인의 명시적 예는 다음과 같다.
```sql
SELECT *
FROM employee CROSS JOIN department;
```
다음은 크로스 조인을 암묵적으로 사용한 예이다.
```sql
SELECT *
FROM employee, department;
```
위의 두 쿼리는 동일한 결과를 반환한다.
| Employee.LastName | Employee.DepartmentID | Department.DepartmentName | Department.DepartmentID |
|---|---|---|---|
| Rafferty | 31 | 영업부 | 31 |
| Jones | 33 | 영업부 | 31 |
| Steinberg | 33 | 영업부 | 31 |
| Smith | 34 | 영업부 | 31 |
| Robinson | 34 | 영업부 | 31 |
| John | 영업부 | 31 | |
| Rafferty | 31 | 기술부 | 33 |
| Jones | 33 | 기술부 | 33 |
| Steinberg | 33 | 기술부 | 33 |
| Smith | 34 | 기술부 | 33 |
| Robinson | 34 | 기술부 | 33 |
| John | 기술부 | 33 | |
| Rafferty | 31 | 사무부 | 34 |
| Jones | 33 | 사무부 | 34 |
| Steinberg | 33 | 사무부 | 34 |
| Smith | 34 | 사무부 | 34 |
| Robinson | 34 | 사무부 | 34 |
| John | 사무부 | 34 | |
| Rafferty | 31 | 마케팅 | 35 |
| Jones | 33 | 마케팅 | 35 |
| Steinberg | 33 | 마케팅 | 35 |
| Smith | 34 | 마케팅 | 35 |
| Robinson | 34 | 마케팅 | 35 |
| John | 마케팅 | 35 |
크로스 조인은 결합된 테이블에서 레코드를 걸러내기 위해 어떠한 서술어도 적용하지 않는다. 프로그래머는 크로스 조인된 결과를 WHERE 구문을 사용하여 추가로 필터링할 수 있다.
SQL:2011 표준에서, 크로스 조인은 F401, 확장 조인 테이블(Extended joined table)의 선택사항이다.[1]
3. 2. 내부 조인 (Inner Join)
내부 조인(inner join)은 SQL에서 두 개 이상의 테이블을 결합하는 가장 일반적인 방법 중 하나로, 특정 조건에 맞는 행들만 결과에 포함시킨다.SQL은 내부 조인을 표현하는 두 가지 방법, 즉 '명시적 조인 표현'과 '암시적 조인 표현'을 제공한다.
- 명시적 조인 표현: `JOIN` 키워드를 사용하여 결합할 테이블을 지정하고, `ON` 키워드를 사용하여 결합 조건을 명시한다.
- 암시적 조인 표현: `SELECT` 문의 `FROM` 절에 결합할 테이블들을 나열하고, `WHERE` 절에 결합 조건을 작성한다. (더 이상 최상의 방법으로 간주되지 않지만 데이터베이스 시스템은 여전히 이를 지원한다.)
예를 들어, `employee` 테이블과 `department` 테이블을 `DepartmentID` 컬럼을 기준으로 내부 조인하는 경우, 명시적 표현과 암시적 표현은 각각 다음과 같다.
```sql
- - 명시적 조인 표현
SELECT *
FROM employee INNER JOIN department
ON employee.DepartmentID = department.DepartmentID;
- - 암시적 조인 표현
SELECT *
FROM employee, department
WHERE employee.DepartmentID = department.DepartmentID;
```
두 쿼리 모두 `employee` 테이블의 `DepartmentID`와 `department` 테이블의 `DepartmentID`가 일치하는 행들만 결합하여 결과를 반환한다. 결과는 다음과 같다.
| Employee.LastName | Employee.DepartmentID | Department.DepartmentName |
|---|---|---|
| Robinson | 34 | 사무부 |
| Jones | 33 | 기술부 |
| Smith | 34 | 사무부 |
| Steinberg | 33 | 기술부 |
| Rafferty | 31 | 영업부 |
위 결과에서 John이라는 직원과 마케팅 부서는 나타나지 않는데, 이는 다른 테이블에 일치하는 레코드가 없기 때문이다.
내부 조인은 동일 조인, 자연 조인 등으로 더 세분화될 수 있다. 단, NULL 값이 포함된 열을 기준으로 조인할 때는 주의해야 한다. NULL은 어떤 값과도 일치하지 않기 때문이다.
3. 2. 1. 동일 조인 (Equi-Join)
'''동일 조인'''(Equi-Join)은 조인 조건에 등호(=)만을 사용하는 특별한 유형의 조인이다. 다른 비교 연산자(< 와 같은)를 사용하면 동일 조인으로 인정되지 않는다.[18]예를 들어, 아래 쿼리는 동일 조인을 사용한다.
```sql
SELECT *
FROM employee JOIN department
ON employee.DepartmentID = department.DepartmentID;
```
위 쿼리는 다음과 같이 작성할 수도 있다.
```sql
SELECT *
FROM employee, department
WHERE employee.DepartmentID = department.DepartmentID;
```
만약 동일 조인 내의 컬럼들이 같은 이름을 가지고 있다면, SQL-92는 `USING`을 사용하여 동일 조인을 표현하는 더 간결한 방법을 제공한다.[18]
```sql
SELECT *
FROM employee INNER JOIN department USING (DepartmentID);
```
`USING` 구문은 단순한 설탕구문 그 이상이다. `USING` 목록에 언급된 컬럼은 각 테이블에 한 번씩 나타나는 것이 아니라, 한 번만 나타나기 때문이다. 위의 예시에서는 `DepartmentID` 컬럼이 하나만 나타나고, `employee.DepartmentID` 또는 `department.DepartmentID`는 나타나지 않는다.
`USING` 구문은 MS SQL Server와 Sybase에서는 지원되지 않는다.
3. 2. 2. 자연 조인 (Natural Join)
자연 조인(natural join)은 조인된 테이블에서 동일한 컬럼명을 가진 두 테이블의 모든 컬럼들을 비교하여 암묵적으로 일어나는 동일 조인의 한 유형이다. 결과적으로 생성된 조인된 테이블에는 동일한 이름을 가진 컬럼의 각 쌍에 대해 단 하나의 컬럼만 포함된다. 만약 동일한 이름을 가진 컬럼이 없다면 교차 조인이 발생한다.대부분의 전문가들은 자연 조인이 위험하다고 여기며, 사용을 권장하지 않는다.[19] 그 이유는 다른 테이블에 다른 컬럼으로 동일한 이름을 가진 새로운 컬럼을 무심코 추가할 경우, 기존 자연 조인이 새로운 컬럼을 사용하여 비교를 수행하게 되어 이전과 다른 결과를 낼 수 있기 때문이다. 즉, 테이블의 데이터가 변경되지 않고 추가만 되어도 기존 쿼리의 결과가 달라질 수 있다.
내부 조인 예제 쿼리는 자연 조인을 사용하여 다음과 같이 표현할 수 있다.
```sql
SELECT *
FROM employee NATURAL JOIN department;
```
명시적 `USING` 절과 마찬가지로, 조인된 테이블에는 한정자 없이 DepartmentID 컬럼이 하나만 나타난다.
| DepartmentID | Employee.LastName | Department.DepartmentName |
|---|---|---|
| 34 | Smith | 사무 |
| 33 | Jones | 엔지니어링 |
| 34 | Robinson | 사무 |
| 33 | Heisenberg | 엔지니어링 |
| 31 | Rafferty | 영업 |
PostgreSQL, MySQL 및 Oracle은 자연 조인을 지원하지만, Microsoft T-SQL 및 IBM DB2는 지원하지 않는다. 조인에 사용된 컬럼은 암시적이므로 조인 코드는 어떤 열이 예상되는지 표시하지 않으며, 열 이름이 변경되면 결과가 변경될 수 있다. SQL:2011 표준에서 자연 조인은 선택 사항인 F401 "확장된 조인된 테이블" 패키지의 일부이다.[7]
많은 데이터베이스 환경에서 열 이름은 쿼리 개발자가 아닌 외부 공급업체가 제어한다. 따라서 자연 조인은 공급업체가 명령한 버전 업그레이드 중에 열 이름이 변경될 수 있다는 가정하에 안정성과 일관성을 유지해야 한다.
3. 3. 외부 조인 (Outer Join)
외부 조인(Outer Join)은 두 테이블을 조인할 때, 한쪽 테이블에는 해당 데이터가 존재하지만 다른 쪽 테이블에는 데이터가 존재하지 않는 경우에도 모든 행을 결과에 포함시키는 방법이다. 외부 조인은 왼쪽 외부 조인, 오른쪽 외부 조인, 완전 외부 조인으로 나뉜다.- 왼쪽 외부 조인 (Left Outer Join): 왼쪽 테이블의 모든 행을 포함하고, 오른쪽 테이블에서는 조건에 맞는 행만 결합한다. 오른쪽 테이블에 일치하는 행이 없으면, 오른쪽 테이블의 열들은 NULL 값으로 채워진다.
- 오른쪽 외부 조인 (Right Outer Join): 오른쪽 테이블의 모든 행을 포함하고, 왼쪽 테이블에서는 조건에 맞는 행만 결합한다. 왼쪽 테이블에 일치하는 행이 없으면, 왼쪽 테이블의 열들은 NULL 값으로 채워진다.
- 완전 외부 조인 (Full Outer Join): 양쪽 테이블의 모든 행을 포함한다. 어느 한 쪽에 일치하는 행이 없으면 해당 열들은 NULL 값으로 채워진다.
외부 조인은 내부 조인과 달리, 조인 조건에 맞지 않는 행도 결과에 포함시키기 때문에, 데이터가 누락되지 않도록 하는 데 유용하다.
외부 조인의 효과는 `UNION ALL`을 사용하여 얻을 수도 있는데, 예를 들어 아래와 같은 왼쪽 외부 조인 쿼리가 있을때:
```sql
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName
FROM employee
LEFT OUTER JOIN department ON employee.DepartmentID = department.DepartmentID;
```
다음과 같이 바꿔 쓸 수 있다.:
```sql
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName
FROM employee
INNER JOIN department ON employee.DepartmentID = department.DepartmentID
UNION ALL
SELECT employee.LastName, employee.DepartmentID, cast(NULL as varchar(20))
FROM employee
WHERE NOT EXISTS (
SELECT * FROM department
WHERE employee.DepartmentID = department.DepartmentID)
```
일부 데이터베이스 시스템은 완전 외부 조인 기능을 직접 지원하지 않지만, 내부 조인과 `UNION ALL`을 조합하여 유사하게 구현할 수 있다.
3. 3. 1. 왼쪽 외부 조인 (Left Outer Join)
왼쪽 외부 조인(또는 간단히 왼쪽 조인)은 테이블 A와 B에 대해 "왼쪽" 테이블(A)의 모든 행을 항상 포함하며, 조인 조건이 "오른쪽" 테이블(B)에서 일치하는 행을 찾지 못하는 경우에도 마찬가지이다. 즉, `ON` 절이 B에서 0개의 행과 일치하는 경우(A의 특정 행에 대해) 조인은 여전히 결과를 반환하지만(해당 행에 대해) B의 각 열에 NULL 값이 포함된다. 왼쪽 외부 조인은 내부 조인의 모든 값과 오른쪽 테이블과 일치하지 않는 왼쪽 테이블의 모든 값을 반환하며, 연결 열에 NULL(비어 있음) 값이 있는 행도 포함한다.[9]예를 들어, 이를 통해 직원의 부서를 찾을 수 있지만 부서가 할당되지 않은 직원도 표시할 수 있다. (내부 조인 예와 달리, 할당되지 않은 직원은 결과에서 제외됨).
왼쪽 외부 조인의 예('''`OUTER`''' 키워드는 선택 사항)에서 추가 결과 행(내부 조인과 비교)은 다음과 같다.
| Employee.LastName | Employee.DepartmentID | Department.DepartmentName | Department.DepartmentID |
|---|---|---|---|
| Jones | 33 | Engineering | 33 |
| Rafferty | 31 | Sales | 31 |
| Robinson | 34 | Clerical | 34 |
| Smith | 34 | Clerical | 34 |
| Williams | |||
| Heisenberg | 33 | Engineering | 33 |
오라클은 더 이상 사용되지 않는[9] 다음 구문을 지원한다.
```sql
SELECT *
FROM employee, department
WHERE employee.DepartmentID = department.DepartmentID(+)
```
사이베이스(Sybase)는 다음 구문을 지원한다. (마이크로소프트 SQL 서버(Microsoft SQL Server)는 2000 버전부터 이 구문을 지원하지 않는다.)
```tsql
SELECT *
FROM employee, department
WHERE employee.DepartmentID *= department.DepartmentID
```
IBM Informix는 다음 구문을 지원한다.
```sql
SELECT *
FROM employee, OUTER department
WHERE employee.DepartmentID = department.DepartmentID
3. 3. 2. 오른쪽 외부 조인 (Right Outer Join)
오른쪽 외부 조인(Right Outer Join)은 왼쪽 외부 조인과 매우 유사하며, 테이블 처리 순서만 반대이다. 오른쪽 테이블(B)의 모든 행이 결과에 나타나며, 왼쪽 테이블(A)에서 일치하는 행이 없으면 A의 열에는 NULL 값이 표시된다.오른쪽 외부 조인은 오른쪽 테이블의 모든 값과 왼쪽 테이블에서 일치하는 값을 반환한다. 일치하는 조인 조건이 없는 경우 NULL 값을 반환한다. 예를 들어, 이를 통해 각 직원과 해당 부서를 찾을 수 있지만, 직원이 없는 부서도 표시할 수 있다.
다음은 오른쪽 외부 조인의 예시이다. ('''`OUTER`''' 키워드는 선택 사항이다.) 추가 결과 행은 *기울임꼴*로 표시된다.
```sql
SELECT *
FROM employee RIGHT OUTER JOIN department
ON employee.DepartmentID = department.DepartmentID;
```
| Employee.LastName | Employee.DepartmentID | Department.DepartmentName | Department.DepartmentID |
|---|---|---|---|
| Smith | 34 | 사무부 | 34 |
| Jones | 33 | 기술부 | 33 |
| Robinson | 34 | 사무부 | 34 |
| Heisenberg | 33 | 기술부 | 33 |
| Rafferty | 31 | 영업부 | 31 |
| 마케팅 | 35 |
오른쪽 외부 조인과 왼쪽 외부 조인은 기능적으로 동일하다. 서로 제공하지 않는 기능은 없으므로 테이블 순서가 바뀌면 상호 대체 가능하다.
3. 3. 3. 완전 외부 조인 (Full Outer Join)
'''완전 외부 조인'''은 왼쪽 외부 조인과 오른쪽 외부 조인의 결과를 합친 것이다. 완전 외부 조인된 테이블에는 양쪽 테이블의 모든 레코드가 포함되며, 한쪽 테이블에 일치하는 레코드가 없는 경우 해당 레코드는 빈 값으로 채워진다.예를 들어, 완전 외부 조인을 사용하면 부서에 속한 직원과 직원이 있는 부서를 모두 볼 수 있다. 또한, 부서에 속하지 않은 직원과 직원이 없는 부서도 확인할 수 있다.
다음은 완전 외부 조인의 예시이다 ('''`OUTER`''' 키워드는 선택 사항이다):
```sql
SELECT *
FROM employee FULL OUTER JOIN department
ON employee.DepartmentID = department.DepartmentID;
```
| Employee.LastName | Employee.DepartmentID | Department.DepartmentName | Department.DepartmentID |
|---|---|---|---|
| Smith | 34 | 사무부 | 34 |
| Jones | 33 | 기술부 | 33 |
| Robinson | 34 | 사무부 | 34 |
| John | |||
| Steinberg | 33 | 기술부 | 33 |
| Rafferty | 31 | 영업부 | 31 |
| 마케팅 | 35 |
일부 데이터베이스 시스템은 완전 외부 조인 기능을 직접 지원하지 않는다. 하지만, 내부 조인과 `UNION ALL`을 사용하여 왼쪽 및 오른쪽 테이블에서 각각 "단일 테이블 행"을 선택하는 방식으로 유사하게 구현할 수 있다.
```sql
SELECT employee.LastName, employee.DepartmentID,
department.DepartmentName, department.DepartmentID
FROM employee
INNER JOIN department ON employee.DepartmentID = department.DepartmentID
UNION ALL
SELECT employee.LastName, employee.DepartmentID,
cast(NULL as varchar(20)), cast(NULL as integer)
FROM employee
WHERE NOT EXISTS (
SELECT * FROM department
WHERE employee.DepartmentID = department.DepartmentID)
UNION ALL
SELECT cast(NULL as varchar(20)), cast(NULL as integer),
department.DepartmentName, department.DepartmentID
FROM department
WHERE NOT EXISTS (
SELECT * FROM employee
WHERE employee.DepartmentID = department.DepartmentID)
```
또 다른 방법으로는 왼쪽 외부 조인과 오른쪽 외부 조인을 `UNION ALL`하고 내부 조인을 빼는 방식으로 구현할 수 있다.
3. 4. 자가 조인 (Self-Join)
'''자가 조인'''(self-join)은 한 테이블에서 자기 자신에 조인을 시키는 것이다.[21]같은 나라에 있는 두 명의 직원을 찾는 질의가 필요하다고 가정해 보자. 만약 직원 정보가 두 개의 개별 테이블에 있다면, 일반적인 조인 연산을 사용하여 동일한 국적을 가진 직원을 찾을 수 있다. 그러나 모든 직원 정보가 하나의 테이블에 포함되어 있는 경우에는 자가 조인을 사용해야 한다.[22]
예를 들어, 다음과 같은 `Employee` 테이블이 있다고 가정하자:
| EmployeeID | LastName | Country | DepartmentID |
|---|---|---|---|
| 123 | Rafferty | 호주 | 31 |
| 124 | Jones | 호주 | 33 |
| 145 | Steinberg | 호주 | 33 |
| 201 | Robinson | 미국 | 34 |
| 305 | Smith | 독일 | 34 |
| 306 | John |
이 테이블에서 같은 국가에 있는 직원 쌍을 찾기 위한 SQL 질의는 다음과 같다:
SELECT F.EmployeeID, F.LastName, S.EmployeeID, S.LastName, F.Country
FROM Employee F INNER JOIN Employee S ON F.Country = S.Country
WHERE F.EmployeeID < S.EmployeeID
ORDER BY F.EmployeeID, S.EmployeeID;
위 질의의 결과는 다음과 같다:
| EmployeeID | LastName | EmployeeID | LastName | Country |
|---|---|---|---|---|
| 123 | Rafferty | 124 | Jones | 호주 |
| 123 | Rafferty | 145 | Steinberg | 호주 |
| 124 | Jones | 145 | Steinberg | 호주 |
| 305 | Smith | 306 | John | 독일 |
위 예제에서 사용된 조건은 다음과 같은 의미를 갖는다:
- `F`와 `S`는 `Employee` 테이블에 대한 앨리어스이다.
- `F.Country = S.Country` 조건은 같은 국가에 있는 직원만 선택한다.
- `F.EmployeeID < S.EmployeeID` 조건은 중복된 쌍과 자기 자신과의 쌍을 제외한다.
이 조건이 없다면, 다음과 같이 중복된 결과가 나타날 수 있다:
| EmployeeID | LastName | EmployeeID | LastName | Country |
|---|---|---|---|---|
| 305 | Smith | 305 | Smith | 독일 |
| 305 | Smith | 306 | John | 독일 |
| 306 | John | 305 | Smith | 독일 |
| 306 | John | 306 | John | 독일 |
위 테이블에서 첫 번째와 마지막 행은 중복된 결과이므로, `F.EmployeeID < S.EmployeeID` 조건을 통해 이러한 중복을 제거할 수 있다.
4. 조인의 활용
(이전 단계에서 원본 소스가 제공되지 않아 빈 출력만 생성되었으므로, 수정할 내용이 없습니다. 따라서 빈 출력을 그대로 유지합니다.)
5. 조인의 구현
데이터베이스 시스템에서는 관계형 시스템이 조인을 자주 호출하지만, 효율적인 실행을 최적화하기는 어렵다. 내부 조인은 교환 법칙과 결합 법칙을 따르기 때문에, 사용자가 조인할 테이블 목록과 조건을 제공하면 데이터베이스 시스템이 가장 효율적인 실행 방법을 결정해야 한다.
쿼리 옵티마이저는 조인이 포함된 쿼리 실행 방법을 결정하며, 다음 두 가지를 고려한다.
# '''조인 순서''': 조인은 교환 법칙과 결합 법칙에 따라 작동하므로 순서는 결과에 영향을 주지 않지만, 조인 작업 비용에는 큰 영향을 미치므로 최적의 순서 선택이 중요하다.
# '''조인 방법''': 주어진 테이블과 조건에 대해 여러 알고리즘이 조인 결과를 생성할 수 있다. 입력 테이블 크기, 조건 일치 행 수, 쿼리에 필요한 작업 등에 따라 가장 효율적인 알고리즘이 달라진다.
많은 조인 알고리즘은 입력을 다르게 처리하며, "외부" 및 "내부" 또는 "왼쪽" 및 "오른쪽" 조인 피연산자로 구분한다. (예: 중첩 루프에서 외부 관계의 각 행에 대해 전체 내부 관계 스캔)
조인이 포함된 쿼리 계획은 다음과 같이 분류된다.
- '''왼쪽 깊이''': 각 조인의 내부 피연산자로 기본 테이블 사용
- '''오른쪽 깊이''': 각 조인의 외부 피연산자로 기본 테이블 사용
- '''부시''': 왼쪽 깊이도 오른쪽 깊이도 아니며, 두 입력 모두 조인 결과일 수 있음
이 명칭은 쿼리 계획을 트리 자료 구조로 그릴 때 (외부 조인 관계는 왼쪽, 내부 관계는 오른쪽에 표시하는 것이 관례) 모양에서 유래되었다.
5. 1. 조인 알고리즘
데이터베이스 시스템에서 조인(Join)은 관계형 데이터베이스에서 자주 사용되지만, 효율적인 실행을 최적화하기는 어렵다. 조인은 교환 법칙과 결합 법칙을 따르기 때문에, 데이터베이스 시스템은 사용자가 지정한 테이블과 조건에 맞춰 가장 효율적인 실행 방법을 결정해야 한다.쿼리 옵티마이저는 조인이 포함된 쿼리의 실행 방법을 결정하며, 다음 두 가지를 고려한다.
# '''조인 순서''': 조인은 교환 법칙과 결합 법칙을 따르므로 조인 순서는 결과에 영향을 주지 않지만, 조인 작업 비용에는 큰 영향을 줄 수 있다. 따라서 최적의 조인 순서를 선택하는 것이 중요하다.
# '''조인 방법''': 주어진 테이블과 조건에 대해 여러 알고리즘이 조인 결과를 생성할 수 있다. 입력 테이블의 크기, 조건에 일치하는 행 수, 쿼리에 필요한 작업 등에 따라 가장 효율적인 알고리즘이 달라진다.
조인 알고리즘은 입력을 다르게 처리한다. 조인의 입력을 "외부" 및 "내부" 또는 "왼쪽" 및 "오른쪽"이라고 부를 수 있다. 예를 들어, 중첩 루프의 경우 데이터베이스 시스템은 외부 관계의 각 행에 대해 전체 내부 관계를 스캔한다.
조인이 포함된 쿼리 계획은 다음과 같이 분류할 수 있다.
- '''왼쪽 깊이''': 각 조인의 내부 피연산자로 기본 테이블(다른 조인 대신)을 사용한다.
- '''오른쪽 깊이''': 각 조인의 외부 피연산자로 기본 테이블을 사용한다.
- '''부시''': 왼쪽 깊이도 오른쪽 깊이도 아니며, 조인에 대한 두 입력 모두 조인의 결과일 수 있다.
이러한 이름은 쿼리 계획을 트리 자료 구조로 그렸을 때의 모양에서 유래되었다. (외부 조인 관계는 왼쪽에, 내부 관계는 오른쪽에 표시하는 것이 관례이다.)
이진 조인 연산을 수행하기 위한 세 가지 기본적인 알고리즘은 중첩 루프 조인, 정렬-병합 조인, 해시 조인이다. 최악의 경우 최적 조인 알고리즘은 최악의 경우 두 개 이상의 관계 사이의 조인에 대해 이진 조인 알고리즘보다 점근적으로 빠르다.[13]
5. 2. 조인 인덱스
데이터베이스 인덱스의 일종인 조인 인덱스는 데이터 웨어하우스 환경에서 조인 쿼리 처리 성능을 향상시키는 데 사용된다. 2012년 기준으로, 오라클[14]과 테라데이타[15]에서 조인 인덱스를 구현하여 제공하고 있다.테라데이타는 데이터베이스 뷰와 유사한 구문을 사용하여 조인 인덱스를 정의한다. 하나 이상의 테이블에서 특정 열, 열에 대한 집계 함수, 또는 날짜 열의 구성 요소를 지정할 수 있다. 하나의 조인 인덱스는 최대 64개의 열 또는 열 표현식을 가질 수 있다. 선택적으로 복합 데이터의 기본 키를 정의하는 열을 지정할 수도 있다. 병렬 하드웨어 환경에서는 열 값을 기준으로 인덱스 내용을 여러 디스크에 분산시킨다. 사용자가 소스 테이블을 업데이트하면 조인 인덱스 내용도 자동으로 업데이트된다. 쿼리의 WHERE 절이 조인 인덱스에 정의된 열 또는 열 표현식의 일부 또는 전체(이른바 "커버링 쿼리")를 포함하는 경우, 쿼리 실행 시 원본 테이블과 인덱스를 참조하는 대신 조인 인덱스를 참조하여 쿼리 성능을 향상시킨다.
오라클의 조인 인덱스는 비트맵 인덱스를 사용하는 방식으로 구현된다. ''비트맵 조인 인덱스''는 낮은 카디널리티 열(오라클 문서에 따르면 300개 미만의 고유 값을 포함하는 열)에 사용되며, 여러 관련 테이블의 낮은 카디널리티 열을 결합한다. 예를 들어, 다양한 공급업체가 다양한 부품을 제공하는 재고 시스템을 생각해 보자. 스키마는 세 개의 테이블(Part, Supplier, Inventory)로 구성된다. Part와 Supplier는 "마스터 테이블"이고, Inventory는 Supplier와 Part를 연결하는 "세부 테이블"로 가장 많은 행을 포함한다. 모든 부품에는 Part Type이 있고, 모든 공급업체는 미국에 기반을 두어 State 열을 갖는다. 미국에는 60개 미만의 주와 영토가 있으며, 300개 미만의 Part Type이 있다. 이 경우, 세 테이블을 조인하고 Part_Type 및 Supplier_State 열을 지정하여 비트맵 조인 인덱스를 정의할 수 있다. Part_Type 및 Supplier_State 열은 각각 Supplier와 Part 테이블에 있지만, 조인 인덱스는 Inventory 테이블에 정의된다.
테라데이타와 마찬가지로 오라클 비트맵 조인 인덱스 역시 쿼리의 WHERE 절이 조인 인덱스에 포함된 열로 제한될 때만 쿼리 응답에 활용된다.
5. 3. 쿼리 최적화
데이터베이스 시스템은 관계형 시스템에서 조인을 자주 호출하지만, 효율적인 실행을 최적화하는 것은 어려운 과제이다. 조인은 교환 법칙과 결합 법칙을 따르기 때문에, 사용자는 조인할 테이블 목록과 조건만 제공하면 되고, 데이터베이스 시스템이 가장 효율적인 실행 방법을 결정해야 한다. 쿼리에 관련된 테이블 수가 늘어날수록 선택 사항은 더욱 복잡해진다. 각 테이블은 레코드 수, 평균 레코드 길이(NULL 필드 고려), 사용 가능한 인덱스 등 서로 다른 특성을 가지며, Where 절 필터는 쿼리 볼륨 및 비용에 큰 영향을 미칠 수 있다.쿼리 옵티마이저는 조인이 포함된 쿼리를 실행하는 방법을 결정한다. 쿼리 옵티마이저는 다음과 같은 두 가지 기본적인 자유를 가진다.
# '''조인 순서''': 조인은 교환 법칙과 결합 법칙에 따라 작동하므로 시스템이 테이블을 조인하는 순서는 쿼리의 최종 결과 집합을 변경하지 않는다. 그러나 조인 순서는 조인 작업의 비용에 큰 영향을 미칠 수 있으므로 최상의 조인 순서를 선택하는 것이 매우 중요하다.
# '''조인 방법''': 두 개의 테이블과 조인 조건이 주어지면 여러 알고리즘이 조인의 결과 집합을 생성할 수 있다. 어떤 알고리즘이 가장 효율적으로 실행되는지는 입력 테이블의 크기, 조인 조건과 일치하는 각 테이블의 행 수 및 쿼리의 나머지 부분에서 필요한 작업에 따라 달라진다.
많은 조인 알고리즘은 입력을 다르게 처리한다. 조인의 입력을 각각 "외부" 및 "내부" 조인 피연산자 또는 "왼쪽" 및 "오른쪽"이라고 할 수 있다. 예를 들어, 중첩 루프의 경우 데이터베이스 시스템은 외부 관계의 각 행에 대해 전체 내부 관계를 스캔한다.
조인이 포함된 쿼리 계획은 다음과 같이 분류할 수 있다.
- '''왼쪽 깊이''': 계획의 각 조인의 내부 피연산자로 기본 테이블(다른 조인 대신) 사용
- '''오른쪽 깊이''': 계획의 각 조인의 외부 피연산자로 기본 테이블 사용
- '''부시''': 왼쪽 깊이도 오른쪽 깊이도 아님. 조인에 대한 두 입력은 자체적으로 조인의 결과일 수 있음
이러한 이름은 외부 조인 관계가 왼쪽에 있고 내부 관계가 오른쪽에 있는(규약에 따라) 트리 자료 구조로 그려진 경우 쿼리 계획의 모양에서 유래되었다.
일부 데이터베이스 시스템에서는 사용자가 조인 연산에서 테이블을 특정 순서로 읽도록 강제할 수 있다. 이는 조인 옵티마이저가 테이블을 비효율적인 순서로 읽도록 선택할 때 사용된다. 예를 들어, MySQL에서 `STRAIGHT_JOIN` 명령은 쿼리에 나열된 정확한 순서대로 테이블을 읽는다.[16]
6. 한국의 IT 환경과 조인
(이전 출력이 없으므로, 수정할 내용이 없습니다. 원본 소스와 함께 이전 출력을 제공해주시면 수정 작업을 진행하겠습니다.)
참조
[1]
웹사이트
SQL CROSS JOIN
http://www.sqlguides[...]
[2]
문서
Avoid SQL Server functions in the WHERE clause for Performance
MSSQL Tips
2007-05-03
[3]
문서
Inside Oracle APEX Caution when using PL/SQL functions in a SQL statement
2006-11-30
[4]
문서
T-SQL Best Practices - Don't Use Scalar Value Functions in Column List or WHERE Clauses
2009-10-29
[5]
웹사이트
Simplifying Joins with the USING Keyword
http://www.java2s.co[...]
[6]
문서
In Unicode, the bowtie symbol is ⋈ (U+22C8).
[7]
웹사이트
Ask Tom "Oracle support of ANSI joins."
http://asktom.oracle[...]
[8]
서적
Database System Concepts
McGraw-Hill
[9]
웹사이트
Oracle Left Outer Join
http://www.dba-oracl[...]
[10]
간행물
2005
[11]
간행물
2005
[12]
간행물
1998
[13]
논문
Free Join: Unifying Worst-Case Optimal and Traditional Joins
2023-01-27
[14]
웹사이트
Database Concepts - 5 Indexes and Index-Organized Tables - Bitmap Join Indexes
https://docs.oracle.[...]
2024-06-23
[15]
웹사이트
SQL Data Definition Language Syntax and Examples - CREATE JOIN INDEX
https://docs.teradat[...]
2024-06-23
[16]
웹사이트
13.2.9.2 JOIN Syntax
https://dev.mysql.co[...]
Oracle Corporation
2015-12-03
[17]
웹사이트
SQL CROSS JOIN
http://www.sqlguides[...]
[18]
웹사이트
Simplifying Joins with the USING Keyword
http://www.java2s.co[...]
[19]
웹사이트
Ask Tom "Oracle support of ANSI joins."
http://asktom.oracle[...]
[20]
웹인용
Why SQL Server Doesn’t Support Natural Join Syntax
https://web.archive.[...]
2013-04-19
[21]
간행물
2005
[22]
간행물
2005
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com
