CREATE INDEX
CREATE INDEX는 테이블에 인덱스를 만들어 조회, 조인, 정렬의 쿼리 성능을 끌어올려요.
출처: 문서
본문
테이블에 인덱스를 만들어서 조회(lookup), 조인, 정렬에 대한 쿼리 성능을 높여요.
문법
CREATE [UNIQUE] INDEX [IF NOT EXISTS] [schema-name.]index-name
ON table-name (column-or-expr [COLLATE collation-name] [ASC|DESC], ...)
[WHERE filter-expression];
설명
CREATE INDEX는 테이블의 하나 이상 컬럼이나 표현식 위에 인덱스를 만들어요. Turso는 SQLite와 같은 형식의 B-tree 인덱스를 써요. 쿼리 플래너는 인덱스가 쿼리를 빠르게 할 수 있을 때 자동으로 인덱스를 활용해요 — SQL 문에서 인덱스를 명시적으로 참조할 필요가 없어요.
매개변수
| 매개변수 | 설명 |
|---|---|
UNIQUE |
고유성 제약을 강제해요. 인덱스 컬럼에 중복 값이 생기게 되는 INSERT나 UPDATE는 Turso가 거절해요. |
IF NOT EXISTS |
같은 이름의 인덱스가 이미 있을 때 오류를 막아줘요. 인덱스가 있으면 문은 아무 것도 하지 않아요. |
schema-name |
테이블이 들어 있는 붙은(attached) 데이터베이스 이름. 생략하면 main 데이터베이스 |
index-name |
데이터베이스 안에서 고유한 인덱스 이름 |
table-name |
인덱스를 만들 테이블 |
column-or-expr |
인덱스에 넣을 컬럼 이름이나 표현식. 여러 항목은 쉼표로 구분해요. |
COLLATE collation-name |
인덱스 컬럼에 적용할 선택적 콜레이션 시퀀스 (예: NOCASE). |
ASC / DESC |
인덱스 컬럼의 정렬 방향. 기본값은 ASC. |
WHERE filter-expression |
부분(partial) 인덱스를 만드는 선택적 필터. 표현식과 일치하는 행만 인덱스에 들어가요. |
컬럼 인덱스
가장 흔한 형태는 하나 이상의 컬럼을 이름으로 인덱싱하는 거예요.
-- Single-column index
CREATE INDEX idx_users_email ON users (email);
-- Multi-column (composite) index
CREATE INDEX idx_orders_customer_date ON orders (customer_id, order_date DESC);
복합(composite) 인덱스는 쿼리가 여러 컬럼으로 필터링하거나 정렬할 때 유용해요. 컬럼 순서가 중요해요 — (a, b) 인덱스는 a만으로 필터링하는 쿼리는 빠르게 해주지만, b만으로 필터링하는 쿼리는 도와주지 못해요.
UNIQUE 인덱스
UNIQUE 인덱스는 인덱스 컬럼에서 같은 값 조합을 가진 행이 둘 이상 있을 수 없게 강제해요. NULL 값들은 서로 다른 것으로 취급되기 때문에, UNIQUE 인덱스는 인덱스 컬럼이 NULL인 행을 여러 개 허용해요.
CREATE UNIQUE INDEX idx_users_email_unique ON users (email);
-- This succeeds:
INSERT INTO users (email) VALUES ('[email protected]');
-- This fails with a UNIQUE constraint violation:
INSERT INTO users (email) VALUES ('[email protected]');
부분 인덱스 (Partial Indexes)
부분 인덱스는 WHERE 절을 만족하는 행만 담아요. 부분 인덱스는 전체 인덱스보다 작고, 항상 같은 필터 조건을 포함하는 쿼리에서 더 효율적이에요.
-- Index only active orders
CREATE INDEX idx_active_orders ON orders (customer_id)
WHERE status = 'active';
-- The query planner uses this index when the WHERE clause matches
SELECT * FROM orders WHERE status = 'active' AND customer_id = 42;
부분 인덱스의 WHERE 절은 테이블의 아무 컬럼이나 참조할 수 있고, 연산자, 리터럴 값, 내장 함수를 쓸 수 있어요. 서브쿼리는 허용되지 않아요.
표현식 인덱스
표현식 인덱스는 원시 컬럼 값 대신 표현식의 결과를 저장해요. 쿼리가 계산된 값으로 자주 필터링하거나 정렬할 때 표현식 인덱스를 쓰세요.
-- Index on lowercase email for case-insensitive lookups
CREATE INDEX idx_users_email_lower ON users (lower(email));
-- The query planner can use this index for:
SELECT * FROM users WHERE lower(email) = '[email protected]';
-- Index on an arithmetic expression
CREATE INDEX idx_items_total ON items (quantity * unit_price);
인덱스 안의 각 표현식은 인덱싱된 테이블의 컬럼만 참조하는 결정적(deterministic) 표현식이어야 해요. 집계 함수와 서브쿼리는 허용되지 않아요.
커스텀 인덱스 방식
**Turso 확장 기능**: 커스텀 인덱스 방식은 인덱싱을 B-tree 너머로 확장해요. 이 기능은 실험적이며 사용 전에 [활성화](/sql-reference/experimental-features)해야 해요.Turso는 USING 절로 대안 인덱스 방식을 지정할 수 있게 해줘요.
CREATE INDEX index-name ON table-name USING method-name (columns...);
USING fts로 전문 검색하기
fts 인덱스 방식은 Tantivy로 구동되는 전문 검색 인덱스를 만들어요. FTS 인덱스는 WITH 절을 통해 토크나이저 설정을 지원해요.
-- Basic FTS index
CREATE INDEX idx_articles_search ON articles USING fts (title, body);
-- FTS index with custom tokenizers
CREATE INDEX idx_articles_search ON articles USING fts (
title WITH tokenizer=simple,
body WITH tokenizer=ngram
);
FTS 인덱스가 만들어지면 search() 함수로 조회할 수 있어요:
SELECT * FROM articles WHERE search(articles, 'database performance');
예제
흔한 조회 패턴을 위한 인덱스
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
category TEXT,
price REAL,
in_stock INTEGER DEFAULT 1
);
-- Speed up lookups by category
CREATE INDEX idx_products_category ON products (category);
-- Speed up price range queries within a category
CREATE INDEX idx_products_cat_price ON products (category, price);
비즈니스 규칙을 강제하는 유니크 인덱스
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL,
department TEXT
);
CREATE UNIQUE INDEX idx_employees_email ON employees (email);
상태 필터를 위한 부분 인덱스
CREATE TABLE tasks (
id INTEGER PRIMARY KEY,
assignee TEXT,
status TEXT DEFAULT 'pending',
due_date TEXT
);
-- Only index pending tasks -- completed tasks are rarely queried
CREATE INDEX idx_pending_tasks ON tasks (assignee, due_date)
WHERE status = 'pending';
더 알아보기 (Learn more)
- DROP INDEX - 인덱스 제거하기
- REINDEX - 인덱스 다시 만들기
- CREATE TABLE - 인라인 UNIQUE와 PRIMARY KEY 제약
- EXPLAIN - 쿼리 계획에서 인덱스 사용 확인