1. 커버링 인덱스란?

커버링 인덱스(Covering Index)는 인덱스 자체에 쿼리에서 필요한 모든 컬럼이 포함되어 있어 테이블 데이터를 조회하지 않고 인덱스만으로 결과를 반환할 수 있는 인덱스입니다.

커버링 인덱스의 특징

  • WHERE 조건SELECT 컬럼 모두를 인덱스에 포함시킵니다.
  • 테이블 접근이 제거되므로 랜덤 I/O 비용이 줄어들어 성능이 크게 향상됩니다.

일반 인덱스와의 차이

  • 일반 인덱스: WHERE 조건을 최적화하지만 SELECT 컬럼이 인덱스에 없으면 테이블 데이터를 추가로 조회해야 합니다.
  • 커버링 인덱스: 모든 조건과 결과 컬럼이 인덱스에 포함되므로 테이블 접근 없이 바로 결과를 반환합니다.

2. 커버링 인덱스를 적용한 성능 비교

테스트 환경

  • 데이터 개수: 10만 개
  • 조회 조건: WHERE grade = 'SILVER' AND gender = 'Male'
  • 쿼리: SELECT * FROM customer WHERE grade = 'SILVER' AND gender = 'Male' LIMIT 0, 20000;

3. 단계별 성능 비교

단계인덱스 유형스캔된 행 수실제 반환된 행 수비용 (cost) 실행 시간특징

1. 인덱스 적용 전 없음 (ALL) 99,256 12,562 10,238 65.5ms 테이블 전체 스캔
2. 단일 컬럼 인덱스 idx_grade 49,628 12,562 3,420 44.7ms gender 조건 추가 필터링 발생
3. 멀티컬럼 인덱스 idx_grade_gender 24,436 12,562 3,382 36.6ms grade와 gender 조건 인덱스 처리
4. 커버링 인덱스 idx_covering_all_columns 24,392 12,562 3,377 34.9ms 테이블 접근 없이 인덱스에서 결과 반환

4. 단계별 분석

1. 인덱스 적용 전 (테이블 전체 스캔)

  • 인덱스 없음: 테이블 전체를 스캔하며 조건에 맞는 데이터를 필터링합니다.
  • 스캔된 행 수: 99,256개
  • 비용: 10,238
  • 실행 시간: 65.5ms
  • 결론: 성능이 가장 나쁘며, 테이블 전체 스캔으로 인해 I/O 비용이 큽니다.

2. 단일 컬럼 인덱스 (idx_grade)

  • 인덱스 사용: grade 컬럼만 최적화됨. gender 조건은 추가 필터링이 발생합니다.
  • 스캔된 행 수: 49,628개
  • 비용: 3,420
  • 실행 시간: 44.7ms
  • 결론: 스캔된 행 수가 절반으로 줄었지만, gender 조건이 추가로 처리되므로 완벽한 최적화는 되지 않았습니다.

3. 멀티컬럼 인덱스 (idx_grade_gender)

  • 인덱스 사용: grade와 gender 조건을 동시에 최적화합니다.
  • 스캔된 행 수: 24,436개
  • 비용: 3,382
  • 실행 시간: 36.6ms
  • 결론: 두 조건을 인덱스에서 처리하면서 추가 필터링 비용이 제거되어 성능이 크게 개선되었습니다.

4. 커버링 인덱스 (idx_covering_all_columns)

  • 인덱스 사용: WHERE 조건 최적화 + 모든 컬럼이 인덱스에 포함되어 테이블 접근이 제거되었습니다.
  • 스캔된 행 수: 24,392개
  • 비용: 3,377
  • 실행 시간: 34.9ms
  • 특징:
    • Using index가 실행 계획에 나타남.
    • 인덱스만으로 모든 데이터를 반환 → 랜덤 I/O 최소화.
  • 결론: 가장 빠른 성능을 보여주며, 테이블 접근 비용이 완전히 제거되었습니다.


5. 결론 및 추천

성능 개선 순서

  1. 인덱스 적용 전 → 성능이 가장 낮음 (테이블 전체 스캔).
  2. 단일 컬럼 인덱스 → WHERE 조건 일부만 최적화되므로 추가 필터링 비용 발생.
  3. 멀티컬럼 인덱스 → 두 조건을 동시에 최적화.
  4. 커버링 인덱스 → WHERE + SELECT를 인덱스만으로 처리해 성능이 가장 좋음.

최적화 추천

모든 컬럼이 필요한 경우: 커버링 인덱스가 가장 효율적입니다.

 
CREATE INDEX idx_covering_all_columns ON customer (grade, gender, birth, created_date, is_deleted, visit_cnt, employee_id, id, address(50), email(50), memo(50), name(50), phone(20));

INSERT/UPDATE 성능 저하를 감안해야 하므로 읽기 중심 테이블에 적용하는 것이 좋습니다.

지난 글 인덱스 적용/후 성능 비교에서 단일 인덱스(idx_grade)를 적용해 쿼리의 성능을 일부 개선했지만, 기대했던 만큼 성능이 크게 향상되지 않았습니다.

단일 인덱스를 사용하면 한 가지 조건만 최적화되기 때문에 다른 조건(gender = 'Male')은 여전히 추가 필터링 단계를 거쳐야 했습니다. 결과적으로 스캔된 데이터는 절반으로 줄었지만, 실행 시간과 비용은 여전히 비효율적이었습니다.

이번에는 복합 인덱스를 적용해 두 조건(grade와 gender)을 동시에 처리하고, 어떤 성능 개선이 이루어지는지 확인해 보겠습니다.


1. 복합 인덱스 생성

기존 쿼리

SELECT * FROM customer WHERE grade = 'Silver' AND gender = 'Male';

복합 인덱스 생성:

복합 인덱스를 사용하면 두 조건을 동시에 인덱스 단계에서 처리할 수 있습니다.

CREATE INDEX idx_grade_gender ON customer (grade, gender);

2. 실행 계획 비교

단일 인덱스 사용 (기존)

Filter: (customer.gender = 'Male') 
  -> Index lookup on customer using idx_grade (grade='Silver')
  • 스캔된 행 수: 49,628개.
  • 실제 반환된 행 수: 12,562개.
  • 추가 필터링: gender 조건을 따로 처리해야 함.
  • 비용(cost): 약 3,420.

복합 인덱스 사용 (새로운 인덱스 적용 후)

Filter: (customer.gender = 'Male') 
  -> Index lookup on customer using idx_grade (grade='Silver')
  • 스캔된 행 수: 24,436개 → 절반으로 감소.
  • 실제 반환된 행 수: 12,562개.
  • 추가 필터링 없음: grade와 gender 조건이 인덱스에서 동시에 처리됨.
  • 비용(cost): 약 3,382 → 더 낮아짐.

3. 성능 비교

항목단일 인덱스 (idx_grade) 복합 인덱스 (idx_grade_gender)

인덱스 사용 idx_grade idx_grade_gender
추가 필터링 있음 (gender 필터링) 없음
스캔된 행 수 49,628개 24,436개
실제 반환된 행 수 12,562개 12,562개
비용(cost) 3,420 3,382
실행 시간 0.137 ~ 44.7ms 0.321 ~ 36.6ms

4. 개선된 점

  1. 추가 필터링 단계 제거:
    복합 인덱스(idx_grade_gender)를 사용하면서 grade와 gender 조건이 인덱스 단계에서 처리되었습니다.
    • Using where 대신 바로 결과 반환이 가능해졌습니다.
  2. 스캔된 행 수 감소:
    기존에 idx_grade로 약 49,628개의 행을 읽었지만, 복합 인덱스는 약 24,436개만 스캔하게 되었습니다.
  3. 실행 시간 단축:
    쿼리 실행 시간이 평균 0.034 ~ 0.039초로 대폭 단축되었습니다.
  4. 비용 감소:
    MySQL의 쿼리 비용(cost)도 기존보다 낮아졌습니다.

5. 결론

복합 인덱스(idx_grade_gender)를 생성하면서 WHERE 절의 두 조건을 동시에 최적화할 수 있었습니다.

  • 단일 인덱스에서는 추가 필터링이 발생했습니다.
  • 복합 인덱스는 인덱스 단계에서 모든 조건을 처리하므로 I/O 비용이 감소하고 실행 시간이 크게 단축되었습니다.

6. 다음 예고: 커버링 인덱스로 SELECT 최적화

복합 인덱스는 WHERE 조건 최적화에 강력하지만, SELECT *처럼 모든 컬럼을 조회하는 경우에는 랜덤 I/O 비용이 여전히 발생합니다.

다음 글에서는 커버링 인덱스를 활용해 테이블 조회를 완전히 없애고, SELECT 성능을 극대화하는 방법을 다루겠습니다.

데이터베이스에서 성능 최적화를 위해 인덱스를 적용하는 것은 일반적인 방법입니다. 하지만 때로는 인덱스를 추가했음에도 불구하고 속도가 기대만큼 개선되지 않는 상황을 경험하게 됩니다. 오늘은 이러한 상황을 실습과 함께 분석하고, 인덱스의 한계점과 해결 방안을 공유해보겠습니다.


1. 문제 상황

다음과 같은 쿼리를 실행한다고 가정해 봅시다.

SELECT * FROM customer WHERE grade = 'Silver' AND gender = 'Male';
  • customer 테이블의 데이터 수: 약 100,000개.
  • 조건: grade가 'Silver'이고, gender가 'Male'인 데이터를 조회.

2. 인덱스 적용 전 분석

실행 계획

'1', 'SIMPLE', 'customer', NULL, 'ALL', NULL, NULL, NULL, NULL, '99256', '1.00', 'Using where'

설명

  • 타입: ALL → 테이블 전체 스캔이 수행됨.
  • 스캔된 행 수: 약 99,256개.
  • 비용(cost): 10,238 – 전체 데이터를 읽기 때문에 비용이 높음.
  • 실제 실행 시간: 0.0738 ~ 65.5ms.
  • 필터링: gender와 grade 조건을 전체 테이블에서 필터링.

결론

인덱스가 없기 때문에 MySQL은 테이블 전체를 스캔해야 합니다. 조건에 맞는 데이터만 가져오는 데 불필요한 I/O 비용이 발생하고 속도가 느립니다.


3. 인덱스 적용 후 분석

grade 컬럼에 인덱스를 생성해 봅니다.

CREATE INDEX idx_grade ON customer (grade);

실행 계획

'1', 'SIMPLE', 'customer', NULL, 'ref', 'idx_grade,idx_gender', 'idx_grade', '1023', 'const', '49628', '50.00', 'Using where' -> Filter: (customer.gender = 'Male') (cost=3420 rows=24814) 
-> Index lookup on customer using idx_grade (grade='Silver') (cost=3420 rows=49628)

설명

  • 타입: ref → 인덱스(idx_grade)를 사용하여 일부 행만 조회.
  • 스캔된 행 수: 49,628개절반으로 감소.
  • 필터링된 행 수: gender = 'Male' 조건을 추가로 적용해 12,562개 행만 반환.
  • 비용(cost): 3,420 → 비용이 절반 이하로 감소.
  • 실제 실행 시간:
    • Index Lookup: 0.137 ~ 42ms.
    • 추가 필터링: 0.147 ~ 44.7ms.

결론

  • idx_grade 인덱스를 사용해 grade = 'Silver' 조건을 빠르게 처리했습니다.
  • 하지만 gender = 'Male' 조건이 인덱스에 포함되지 않아 추가 필터링 단계가 발생했습니다.
  • 실행 시간은 줄었지만, 여전히 최적화되지 않은 부분이 남아 있습니다.

4. 성능 비교

항목인덱스 적용 전인덱스 적용 후

타입 ALL (테이블 전체 스캔) ref (인덱스 사용)
스캔된 행 수 99,256 49,628
필터링된 행 수 12,562 12,562
비용 (cost) 10,238 3,420
실제 실행 시간 0.0738 ~ 65.5ms 0.137 ~ 44.7ms

개선된 점

  1. 스캔된 행 수가 절반으로 줄어들었습니다.
  2. 비용(cost)이 절반 이하로 감소했습니다.
  3. 실행 시간도 개선되었지만, 여전히 추가 필터링이 남아있습니다.

5. 결론

단일 인덱스(idx_grade)를 적용한 결과, 데이터 접근 비용은 감소했지만 속도 개선이 완벽하지 않았습니다. 이유는 gender 조건에 대한 추가 필터링 작업이 남아있기 때문입니다.

해결 방안: 복합 인덱스 또는 커버링 인덱스를 활용하면 두 조건을 동시에 처리할 수 있어 더 나은 성능을 기대할 수 있습니다.


6. 다음 블로그 예고

다음 글에서는 복합 인덱스커버링 인덱스를 비교해보겠습니다.


마무리

이번 글을 통해 인덱스 적용 전/후 성능 차이를 비교하고, 단일 인덱스의 한계점을 확인했습니다. 다음 단계에서는 인덱스 설계를 더 최적화해 MySQL 성능을 극대화하는 방법을 배워보겠습니다.
👉 인덱스 설계를 최적화해 MySQL 성능을 극대화하는 방법

MySQL Workbench를 사용하다 보면 쿼리 실행 결과로 나오는 Rows의 수가 제한되어 있어 불편함을 느낄 때가 있습니다. 기본적으로 MySQL Workbench는 쿼리 실행 시 최대 1,000개의 행(Row)만 보여줍니다. 하지만 설정을 통해 이 제한을 늘릴 수 있습니다. 아래 단계를 따라 한 번에 더 많은 데이터를 조회할 수 있도록 설정을 변경해 보세요.


1. 기본 Rows 제한 확인하기

MySQL Workbench에서 쿼리를 실행했을 때, 상단에 "Showing rows 0 - 999"와 같은 메시지가 표시됩니다. 이는 현재 설정된 최대 행 수가 1,000개로 제한되어 있다는 의미입니다.


2. Rows 제한 변경 방법

  1. Workbench 열기
    • MySQL Workbench를 실행합니다.
  2. Preferences 열기
    • Windows: Edit > Preferences
    • Mac: MySQL Workbench > Preferences
  3. SQL Editor 설정으로 이동
    • Preferences 창에서 왼쪽 메뉴에서 SQL Execution을 선택합니다.
  4. Limit Rows 옵션 수정
    • "Limit Rows" 섹션에서 Limit Rows Count 값이 기본적으로 1000으로 설정되어 있습니다.
    • 이 값을 원하는 숫자로 변경합니다. 예를 들어, 10,000으로 설정하면 한 번에 최대 10,000개의 행을 조회할 수 있습니다.
  5. 저장 및 적용
    • 설정을 저장한 뒤, MySQL Workbench를 재시작하면 변경된 설정이 적용됩니다.
     

맥에서는 위에서 바로 저렇게도 가능합니다.

3. 쿼리 실행에서 제한 없이 조회하기

설정 변경 외에도 특정 쿼리를 실행할 때만 제한 없이 데이터를 조회하고 싶다면 다음과 같은 방법을 사용할 수 있습니다.

  • 쿼리 끝에 LIMIT 조건을 추가하지 않고 실행하면 설정된 최대 행 수까지 조회됩니다.
  • 무제한으로 조회하고 싶은 경우:
    • Preferences의 "Limit Rows" 값을 0으로 설정하면 모든 데이터를 제한 없이 조회할 수 있습니다. 하지만 데이터가 많을 경우 Workbench가 느려지거나 멈출 수 있으니 주의하세요.
SELECT * FROM your_table;

4. 주의

  • 많은 데이터를 조회할 때
    • 너무 많은 행을 한 번에 조회하면 MySQL Workbench가 느려질 수 있습니다. 필요한 데이터만 가져오는 조건(WHERE)을 추가하는 것을 추천합니다.
  • 설정 복원
    • 필요에 따라 다시 기본값(1,000)으로 복원할 수 있습니다.

MySQL Workbench를 사용하다 보면 SQL 예약어를 대문자로 통일하면 가독성이 좋아지고, 코드 스타일을 일관되게 유지할 수 있습니다. MySQL Workbench는 이 작업을 자동으로 처리해 주는 기능을 제공합니다. 아래 단계를 따라 설정하면 SQL 예약어를 자동으로 대문자로 변환할 수 있습니다.

 

1. SQL Editor 설정에서 예약어 대문자 활성화

MySQL Workbench는 SQL 구문을 자동으로 스타일링할 수 있는 기능을 제공합니다. 예약어를 자동으로 대문자로 바꾸려면 아래 단계를 따르세요:

  1. Workbench 열기: MySQL Workbench를 실행합니다.
  2. Preferences 열기:
    • Windows: Edit > Preferences
    • Mac: MySQL Workbench > Preferences
  3. SQL Editor 설정으로 이동:
    • Preferences 창에서 SQL Editor 탭을 선택합니다.
  4. Syntax Style 변경:
    • "Query Editor" 섹션으로 이동합니다.
    • Use UPPERCASE keywords on completion 옵션을 활성화합니다.
  5. 저장 및 적용:
    • 설정을 저장하고 적용한 뒤 Workbench를 다시 시작하세요.

 

'SQL > tool' 카테고리의 다른 글

MySQL Workbench에서 한 번에 더 많은 Rows를 조회하는 방법  (1) 2024.12.16

데이터베이스에서 트랜잭션(Transaction)은 데이터의 일관성과 안정성을 보장하는 데 중요한 역할을 합니다. 데이터 변경 작업을 묶어서 실행하거나, 오류 발생 시 이전 상태로 되돌릴 수 있는 기능을 제공합니다.
이번 글에서는 트랜잭션의 개념과 COMMIT, ROLLBACK의 활용 방법을 살펴보겠습니다.


1. 트랜잭션의 개념

트랜잭션이란?

  • 트랜잭션(Transaction)은 데이터베이스에서 하나의 논리적인 작업 단위를 의미합니다. 여러 작업을 하나의 단위로 묶어서 실행하며, 데이터의 일관성(Consistency)을 보장합니다.

트랜잭션은 다음 4가지 특성을 만족해야 합니다(ACID 특성)

Atomicity (원자성) 작업이 모두 성공하거나, 전혀 수행되지 않은 상태를 보장해야 합니다.
Consistency (일관성) 작업 전후 데이터가 일관성 있는 상태를 유지해야 합니다.
Isolation (격리성) 트랜잭션 간의 작업이 서로 영향을 주지 않도록 독립적으로 수행되어야 합니다.
Durability (내구성) 트랜잭션이 성공적으로 완료되면 결과가 영구적으로 반영되어야 합니다.

트랜잭션의 실행 흐름

  1. 트랜잭션 시작 (START TRANSACTION 또는 BEGIN).
  2. 작업 수행 (INSERT, UPDATE, DELETE 등).
  3. 결과를 확정(COMMIT)하거나 취소(ROLLBACK)하여 완료.

2. COMMIT과 ROLLBACK

COMMIT

  • 작업을 완료하고 데이터 변경 사항을 데이터베이스에 영구적으로 반영합니다.
  • COMMIT 이후에는 트랜잭션의 변경 사항을 되돌릴 수 없습니다.

문법

COMMIT;

ROLLBACK

  • 작업 도중 오류가 발생하거나 취소해야 할 경우, 데이터 변경 사항을 트랜잭션 시작 이전 상태로 되돌립니다.
  • 트랜잭션 내에서만 사용 가능합니다.

문법

ROLLBACK;

예제

1. 트랜잭션 시작 후 COMMIT

  • 계좌에 $1,000을 추가하고 $100을 차감한 작업을 COMMIT으로 확정합니다.
START TRANSACTION; 

INSERT INTO Account (AccountId, Balance) VALUES (1, 1000);
UPDATE Account
SET Balance = Balance - 100
WHERE AccountId = 1; 

COMMIT;

 

2. 트랜잭션 시작 후 ROLLBACK

  • 작업 도중 오류가 발생한 경우, ROLLBACK으로 모든 변경 사항을 취소합니다.
START TRANSACTION;

INSERT INTO Account (AccountId, Balance) VALUES (2, 500); 

UPDATE Account SET Balance = Balance + 100
WHERE AccountId = 2; 

ROLLBACK;

SAVEPOINT

  • 트랜잭션 내에서 특정 지점을 저장하여 부분적으로 롤백할 수 있는 기능입니다.

문법

SAVEPOINT savepoint_name;
ROLLBACK TO savepoint_name;

예제

START TRANSACTION;

INSERT INTO Account (AccountId, Balance) VALUES (3, 1000);
SAVEPOINT sp1;

UPDATE Account SET Balance = Balance - 200 WHERE AccountId = 3;
SAVEPOINT sp2;

ROLLBACK TO sp1; -- sp1 이후의 작업을 취소
COMMIT;

3. 자동 커밋 (Auto-Commit)

MySQL에서는 기본적으로 자동 커밋(Auto-Commit) 모드가 활성화되어 있습니다.

자동 커밋 모드에서는 각 쿼리가 실행될 때마다 자동으로 COMMIT이 수행됩니다.

자동 커밋 끄기

SET autocommit = 0; -- 자동 커밋 비활성화

START TRANSACTION;

INSERT INTO Account (AccountId, Balance) VALUES (4, 200);

COMMIT; -- 명시적으로 COMMIT 실행

자동 커밋 다시 활성화

SET autocommit = 1;

4. 요약

  • 트랜잭션: 데이터를 안전하게 처리하기 위해 여러 작업을 하나의 단위로 묶습니다.
  • COMMIT: 작업을 완료하고 변경 사항을 영구적으로 저장합니다.
  • ROLLBACK: 작업 중단 시 변경 사항을 취소하고 이전 상태로 복원합니다.
  • SAVEPOINT: 트랜잭션 내 특정 지점을 저장하여 부분적으로 롤백할 수 있습니다.
  • 자동 커밋: MySQL 기본 설정으로, 명시적인 트랜잭션 관리가 필요하면 Auto-Commit을 비활성화합니다.

SQL 트랜잭션은 데이터 무결성을 보장하며, 특히 중요한 데이터를 다룰 때 필수적인 도구입니다.

다음 글에서는 SQL 윈도우 함수를 다뤄보겠습니다.

'SQL > 학습정리' 카테고리의 다른 글

SQL 복합 쿼리  (0) 2024.12.14
SQL 서브쿼리  (0) 2024.12.12
SQL Join  (0) 2024.12.11
SQL 집계함수  (0) 2024.12.10
SQL 기본 문법 2  (0) 2024.12.09

SQL 복합 쿼리는 여러 쿼리의 결과를 하나로 결합하거나 특정 조건에 따라 결과를 비교하는 기능을 제공합니다. MySQL 8.0.31 이상에서는 INTERSECTEXCEPT도 공식적으로 지원됩니다. 이번 글에서는 UNION, UNION ALL, INTERSECT, EXCEPT의 개념과 활용 방법을 예제와 함께 살펴보겠습니다.


1. UNION과 UNION ALL

연산자 설명

UNION 중복된 데이터를 제거하고 결과를 결합
UNION ALL 중복된 데이터를 포함하여 모든 결과를 결합

기본 문법

SELECT 컬럼명
FROM 테이블1
UNION [ALL]
SELECT 컬럼명
FROM 테이블2;

예제

1. 중복 제거한 결과 반환 (UNION)

SELECT FirstName, LastName
FROM Customer
UNION
SELECT FirstName, LastName
FROM Employee;
  • 고객과 직원 테이블에서 이름 목록을 합칩니다.

2. 중복 포함한 결과 반환 (UNION ALL)

SELECT FirstName, LastName
FROM Customer
UNION ALL
SELECT FirstName, LastName
FROM Employee;
  • 고객과 직원 테이블에서 이름 목록을 중복 포함하여 합칩니다.

3. ORDER BY와 함께 사용

SELECT FirstName, LastName
FROM Customer
UNION
SELECT FirstName, LastName
FROM Employee
ORDER BY FirstName ASC;
  • 고객과 직원 이름을 합친 후 이름 기준으로 오름차순 정렬합니다.

2. INTERSECT

INTERSECT는 두 쿼리의 결과에서 공통된 데이터를 반환합니다.

기본 문법

SELECT 컬럼명
FROM 테이블1
INTERSECT
SELECT 컬럼명
FROM 테이블2;

예제

1. 고객(Customer)과 직원(Employee) 중 이름이 같은 사람 조회

 

SELECT FirstName, LastName FROM Customer
INTERSECT 
SELECT FirstName, LastName FROM Employee;

 

2. 두 테이블에서 동일한 국가 조회

 

SELECT Country FROM Customer
INTERSECT
SELECT Country FROM Employee;

3. EXCEPT

EXCEPT는 첫 번째 쿼리의 결과에서 두 번째 쿼리의 결과를 제외한 차집합을 반환합니다.

Oracle에서는 MINUS라는 이름으로 사용됩니다.

기본 문법

SELECT 컬럼명
FROM 테이블1
EXCEPT
SELECT 컬럼명
FROM 테이블2;

예제

1. 고객(Customer) 중 직원(Employee)에는 없는 사람 조회

SELECT FirstName, LastName FROM Customer 
EXCEPT
SELECT FirstName, LastName FROM Employee;

 

2. 직원(Employee) 테이블에는 없고 고객(Customer) 테이블에만 있는 국가 조회

SELECT Country FROM Customer 
EXCEPT
SELECT Country FROM Employee;

4. MySQL에서 INTERSECT와 EXCEPT

MySQL 8.0.31부터는 INTERSECT와 EXCEPT가 기본적으로 지원되지만, 이전 버전에서는 아래와 같은 대체 방법을 사용할 수 있습니다.

INTERSECT의 대체 쿼리

SELECT Customer.FirstName, Customer.LastName
FROM Customer
INNER JOIN Employee
ON Customer.FirstName = Employee.FirstName
   AND Customer.LastName = Employee.LastName;

EXCEPT의 대체 쿼리

SELECT Customer.FirstName, Customer.LastName
FROM Customer
LEFT JOIN Employee
ON Customer.FirstName = Employee.FirstName
   AND Customer.LastName = Employee.LastName
WHERE Employee.FirstName IS NULL;


5. 요약

연산자 설명 MySQL 지원 여부

UNION 중복 제거 후 결과를 합칩니다. 지원
UNION ALL 중복 포함 후 결과를 합칩니다. 지원
INTERSECT 두 쿼리의 공통된 데이터를 반환합니다. MySQL 8.0.31 이상 지원
EXCEPT 첫 번째 결과에서 두 번째 결과를 제외한 데이터를 반환합니다. MySQL 8.0.31 이상 지원

결론

  • MySQL 8.0.31부터 INTERSECTEXCEPT를 기본적으로 지원하므로, 대체 쿼리 없이 간편하게 사용할 수 있습니다.
  • 이전 버전을 사용하는 경우 INNER JOINLEFT JOIN으로 동일한 결과를 구현할 수 있습니다.
  • SQL 복합 쿼리는 데이터 분석 및 통합에서 강력한 도구이므로, 다양한 상황에서 활용할 수 있습니다.

SQL 복합 쿼리는 데이터 통합 및 비교에 강력한 도구입니다. 데이터베이스 시스템에 따라 지원 여부가 다르므로, MySQL의 대안 방법도 익혀두는 것이 좋습니다. 다음 글에서는 SQL 트랜잭션과 롤백에 대해 알아보겠습니다.

'SQL > 학습정리' 카테고리의 다른 글

SQL 트랜잭션과 롤백  (1) 2024.12.15
SQL 서브쿼리  (0) 2024.12.12
SQL Join  (0) 2024.12.11
SQL 집계함수  (0) 2024.12.10
SQL 기본 문법 2  (0) 2024.12.09

문제 링크

🔗 Programmers - 아픈 동물 조회 문제


문제 요약

  • 요구사항
    동물 보호소에 들어온 동물 중 아픈 동물의 아이디와 이름을 조회합니다.
    결과는 아이디 순으로 정렬되어야 합니다.
  • 출력 컬럼
    ANIMAL_ID, NAME

문제 내용

동물 보호소에 들어온 동물 중 아픈 동물만 조회하는 SQL문을 작성해 주세요.
조건에 맞는 동물들을 ANIMAL_ID 순으로 정렬합니다.


풀이 과정 및 코드

풀이 과정

  1. 데이터베이스 테이블: ANIMAL_INS
    • 동물의 아이디, 이름, 상태(INTAKE_CONDITION)가 저장된 테이블.
  2. 조회 조건:
    • INTAKE_CONDITION = 'Sick'인 데이터만 조회.
  3. 정렬 기준:
    • ANIMAL_ID 순으로 오름차순(ORDER BY ANIMAL_ID ASC).
  4. 필요한 컬럼:
    • ANIMAL_ID, NAME

SQL 코드

SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS 
WHERE INTAKE_CONDITION = 'Sick';

SQL 개념 정리

  • WHERE: 조건을 지정하여 데이터를 필터링하는 SQL 명령어.
  • ORDER BY: 정렬을 수행하는 SQL 명령어.
    • 기본값은 오름차순(ASC) 정렬입니다.

문제 링크

🔗 Programmers - 동물 보호소 데이터 조회 문제 (ANIMAL_ID순)


문제 요약

  • 요구사항
    동물 보호소에 들어온 모든 동물의 아이디와 이름을 ANIMAL_ID 순으로 조회합니다.
  • 출력 컬럼
    ANIMAL_ID, NAME

문제 내용

동물 보호소에 들어온 모든 동물의 아이디와 이름을 ANIMAL_ID 순으로 조회하는 SQL문을 작성해 주세요.


풀이 과정 및 코드

풀이 과정

  1. 데이터베이스 테이블: ANIMAL_INS
    • 동물의 아이디와 이름이 저장된 테이블.
  2. 정렬 기준:
    • ANIMAL_ID 순으로 오름차순(ORDER BY ANIMAL_ID ASC).
  3. 필요한 컬럼:
    • ANIMAL_ID, NAME

SQL 코드

SELECT ANIMAL_ID, NAME FROM ANIMAL_INS ORDER BY ANIMAL_ID;
SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID;​

SQL 개념 정리

  • ORDER BY: 정렬을 수행하는 SQL 명령어.
    • 기본값은 오름차순(ASC) 정렬입니다.
문제 링크

🔗 Programmers - 동물 보호소 가장 먼저 들어온 동물 조회 문제


문제 요약

  • 요구사항
    동물 보호소에 가장 먼저 들어온 동물의 이름을 조회합니다.
  • 출력 컬럼
    NAME

문제 내용

동물 보호소에 가장 먼저 들어온 동물의 이름을 조회하는 SQL문을 작성해 주세요.


풀이 과정 및 코드

풀이 과정

  1. 데이터베이스 테이블: ANIMAL_INS
    • 동물의 이름과 보호 시작일(DATETIME)이 저장된 테이블.
  2. 정렬 기준:
    • 보호 시작일(DATETIME) 기준 오름차순(ORDER BY DATETIME ASC).
  3. 제한 조건:
    • 가장 먼저 들어온 동물 1마리만 조회(LIMIT 1).
  4. 필요한 컬럼:
    • NAME

SQL 코드

 
SELECT NAME FROM ANIMAL_INS ORDER BY DATETIME ASC LIMIT 1;
SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME ASC LIMIT 1;​

 


SQL 개념 정리

  • ORDER BY: 정렬을 수행하는 SQL 명령어.
    • ASC: 오름차순 정렬(생략가능)
  • LIMIT: 결과의 출력 개수를 제한하는 SQL 명령어.
    • LIMIT 1: 결과를 1개로 제한.

+ Recent posts