2026/06 11

Ch07. 인덱스 - 인덱스와 동등 비교

데이터베이스에서 인덱스는 다음 세 가지 상황에 사용된다.동등 비교(=), 범위 검색(BETWEEN, >, =, LIKE 등), "ORDER BY"를 통한 정렬 작업인덱스와 동등 비교"type: ref"는 동등 비교(=) 조건이나 "JOIN"에서 인덱스를 사용했다는 의미다. "EXPLAIN"을 사용해서 동등 비교를 확인해보고, 인덱스가 있을 때와 없을 때의 차이를 살펴보자 인덱스가 있을 때 1) 인덱스 생성CREATE INDEX idx_items_item_name ON items (item_name); 2) 인덱스 생성 확인show index from items; 3) "Explain"으로 쿼리 실행 계획 확인EXPLAIN SELECT * FROM items WHERE item_name = '게이밍 노트북..

Ch07. 인덱스 - 인덱스 생성, 조회, 삭제

CREATE INDEX : 인덱스 생성하기CREATE INDEX 인덱스이름 ON 테이블이름 (컬럼1, 컬럼2, ...);인덱스 이름: 생성할 인덱스에 고유한 이름을 붙여준다. 보통 idx_테이블명_컬럼명과 같은 규칙으로 지으면 관리하기 편하다.테이블 이름: 인덱스를 생성할 대상 테이블.컬럼: 인덱스를 구성할 컬럼. 하나 이상의 컬럼을 지정할 수 있다.우리는 "items" 테이블에서 특정 "item_name"으로 상품을 검색하는 경우가 많다고 가정하고 "item_name" 컬럼에 대한 인덱스를 생성해 보겠다.CREATE INDEX idx_items_item_name ON items (item_name);이 쿼리를 실행하면, 데이터베이스는 "items" 테이블의 모든 "item_name" 값을 읽어 정렬한 ..

Ch07. 인덱스 - 트리 자료 구조

인덱스가 어떤 방식으로 데이터를 빠르게 검색하는지 이해하려면 먼저 트리 자료 구조를 알아야 한다.트리는 부모 노드와 자식 노드로 구성된다.여기서는 각 원이 노드다. 노드 안에는 데이터와 다음 노드들의 위치가 보관된다.가장 높은 조상을 루트(root)라 한다. (이 그림을 뒤집어보면 왜 트리라고 하는지, 처음을 루트라고 하는지 이해가 될 것이다.)자식이 2개까지 올 수 있는 트리를 이진트리라 한다.여기에 노드의 왼쪽 자손은 더 작은 값을 가지고, 오른쪽 자손은 더 큰 값을 가지는 것을 이진 탐색 트리라 한다.이진 탐색 트리 - 입력 예시이진 탐색 트리의 핵심은 데이터를 입력하는 시점에 정렬해서 보관한다는 점이다. 그리고 작은 값은 왼쪽에 큰 값은 오른쪽에 저장한다. 데이터 (10, 5, 15, 1, 6, ..

Ch07. 인덱스 - 인덱스 소개

다시 책의 비유로 돌아가 보자. 우리는 책에서 특정 단어를 찾을 때 책을 처음부터 다 읽지 않는다. 책의 맨 뒤에 있는 "찾아보기(색인)" 페이지를 활용한다. "찾아보기" 페이지는 어떻게 구성되어 있는가?책의 중요한 키워드들이 알파벳순, 가나다순(정렬된 순서)으로 정리되어 있다.각 키워드 옆에는 그 키워드가 등장하는 페이지 번호가 적혀 있다.그런데 여기서 중요한 점이 있다. 우리는 찾아보기 페이지를 보고 어떻게 빨리 데이터를 찾을 수 있을까? 바로 중요한 키워드들이 가나다순(정렬된 순서)로 정리되어 있기 때문이다! 인덱스는 특정 컬럼(들)의 데이터를 기반으로 생성되는, 원본 테이블과는 별개의 특수한 자료 구조다.인덱스는 지정된 컬럼(예: item_name)의 값과, 해당 값을 가진 실제 데이터 행의 위치..

Ch07. 인덱스 - 인덱스가 필요한 이유

우리 쇼핑몰이 대성공을 거두어, 판매하는 상품 수가 25개가 아니라 50만 개, 100만 개로 늘어났다고 상상해 보자. 이제 고객이 우리 쇼핑몰에서 "게이밍 노트북"을 검색한다. 우리 시스템은 데이터베이스에 다음의 쿼리를 실행할 것이다.select * from items where item_name = '게이밍 노트북'; 데이터가 몇 건 없었을 때는 눈 깜짝할 사이에 끝나던 이 쿼리가, 이제는 3초, 5초, 혹은 그 이상이 걸리기 시작한다. 서비스 속도가 느려지고 고객들은 답답함을 느껴 떠나간다. 분명 쿼리는 똑같은데, 왜 이렇게 느려진 걸까? 데이터베이스 안에서 도대체 무슨 일이 벌어지고 있는 걸까? 느린 검색의 원인: 풀 테이블 스캔 (Full Table Scan)인덱스가 없는 테이블에서 특정 데이터..

Ch06. 뷰 - 뷰의 장점과 단점

뷰의 장점편리성과 재사용성가장 큰 장점이다. 복잡한 "SELECT" 쿼리(수십 줄에 달하는 "JOIN", 서브쿼리, "CASE" 문의 조합)를 뷰 뒤에 숨겨둘 수 있다.사용자 입장: 쿼리의 내부 로직을 전혀 몰라도, "SELECT * FROM v_my_report;" 한 줄만으로 원하는 결과를 얻을 수 있다.개발자 입장: 동일한 로직이 여러 곳에서 필요할 때, 뷰 하나만 만들어두면 모두가 재사용할 수 있다. 만약 로직을 수정해야 할 경우, 뷰의 정의(ALTER VIEW)만 한 번 수정하면 이 뷰를 사용하는 모든 곳에 즉시 반영되므로 유지보수성이 극적으로 향상된다. 보안성실무에서 뷰를 사용하는 가장 중요한 이유 중 하나다. 뷰는 데이터베이스에 대한 섬세한 "권한 제어"를 가능하게 한다.특정 컬럼 숨기기: ..

Ch06. 뷰 - 생성, 조회, 수정, 삭제

CREATE VIEW: 뷰 생성하기CREATE VIEW 뷰이름 AS SELECT 쿼리문;뷰 이름 앞에는 "v_"나 "view_" 같은 접두사를 붙여서 다른 테이블과 쉽게 구분할 수 있도록 하는 것이 실무에서 흔히 사용하는 좋은 습관이다.create view v_category_order_status as SELECT p.category, COUNT(*) AS total_orders, SUM(CASE WHEN o.status = 'COMPLETED' THEN 1 ELSE 0 END) AS completed_count, SUM(CASE WHEN o.status = 'SHIPPED' THEN 1 ELSE 0 END) AS shipped_count, SUM(CASE WHEN o.status = 'PENDI..

Ch06. 뷰 - 뷰(View)란?

이 쿼리를 우리 쇼핑몰의 재무팀, 마케팅팀, 운영팀에서 매일 아침 확인해야 하는 핵심 지표라고 가정해 보자. SELECT p.category, COUNT(*) AS total_orders, SUM(CASE WHEN o.status = 'COMPLETED' THEN 1 ELSE 0 END) AS completed_count, SUM(CASE WHEN o.status = 'SHIPPED' THEN 1 ELSE 0 END) AS shipped_count, SUM(CASE WHEN o.status = 'PENDING' THEN 1 ELSE 0 END) AS pending_countFROM orders oJOIN products p ON o.product_id = p.product_idGROUP BY ..

Ch05. CASE문 - 조건부 집계

"하나의 쿼리로, 전체 주문 건수와 함께 "결제 완료(COMPLETED)", "배송(SHIPPED)", "주문 대기(PENDING)" 상태의 주문이 각각 몇 건인지 별도의 컬럼으로 나누어 보고 싶다." "피벗 테이블(Pivot Table)"이라는 이름은 데이터를 다양한 관점에서 "회전(pivot)" 시켜 분석할 수 있는 기능 때문에 붙여진 이름이다. UNION으로 합치는 방법"UNION"을 사용하면 여러 "SELECT" 문의 결과를 하나로 합칠 수 있다. 이때 각 "SELECT" 문의 컬럼 수가 같아야 하며, 컬럼의 데이터 타입도 호환되어야 한다.-- Unionselect 'Total' as category, count(*)from ordersunion allselect status as ..

Ch05. CASE문 - 그룹핑

"고객들을 출생 연대에 따라 "1990년대생", "1980년대생", "그 이전 출생"으로 분류하고, 각 그룹에 고객이 총 몇 명씩 있는지 알고 싶다." 분류(Classification): CASE 문을 사용해 각 고객에게 "1990년대생", "1980년대생", "그 이전 출생" 중 하나의 라벨을 붙여준다.집계(Aggregation): 1단계에서 만들어진 라벨을 기준으로 "GROUP BY"하고, "COUNT()" 함수를 사용해 각 라벨(그룹)에 속한 고객 수를 센다. 1단계: CASE 문으로 각 고객 분류하기select name, birth_date, case when year(birth_date) >= 1990 then '1990년대생' when year(birth_date)..