<@U0A71G31CDV> starrocks에서 테이블 만들건데, index어떻게 걸어?
# questions-and-troubleshooting
s
@Rocky starrocks에서 테이블 만들건데, index어떻게 걸어?
r
StarRocks에서 테이블을 생성할 때 인덱스를 설정하는 방법은 크게 3가지로 나뉩니다. 데이터의 특성과 쿼리 패턴에 맞춰 적절한 인덱스를 선택하는 것이 중요합니다. 1. 정렬 키 (Prefix Index) - 가장 중요 StarRocks는 데이터를 저장할 때 지정된 컬럼 순서대로 정렬하며, 이 정렬된 컬럼의 앞부분(최대 36바이트)을 자동으로 *Prefix Index*로 사용합니다. 별도의
INDEX
구문 없이도
ORDER BY
절이나 테이블 생성 시 앞쪽에 배치한 컬럼들이 이 역할을 합니다. * 설정 방법: `ORDER BY (컬럼1, 컬럼2, ...)`에 자주 필터링 조건(
WHERE
)으로 사용하는 컬럼을 넣습니다. * 주의: 카디널리티(중복도가 낮은 정도)가 높은 컬럼을 앞쪽에 배치하는 것이 성능상 유리합니다. 2. Bitmap Index (비트맵 인덱스) 데이터의 종류가 많지 않은 컬럼(Low Cardinality)이나, 여러 조건을 조합해서 조회할 때 효과적입니다. * 생성 방법 (테이블 생성 시):
Copy code
sql
    CREATE TABLE example_table (
        user_id INT,
        gender CHAR(1),
        INDEX idx_gender (gender) USING BITMAP
    )
    DUPLICATE KEY(user_id)
    DISTRIBUTED BY HASH(user_id);
* 나중에 추가 시:
CREATE INDEX idx_name ON table_name (column_name) USING BITMAP;
3. Bloom Filter Index (블룸 필터 인덱스) ID값처럼 종류가 매우 많은 컬럼(High Cardinality)에 대해
WHERE column = 'abc'
또는
IN
조건으로 조회할 때 성능을 크게 향상시킵니다. * 설정 방법: 테이블 생성 시 `PROPERTIES`에 지정합니다.
Copy code
sql
    CREATE TABLE example_table (
        order_id VARCHAR(100),
        price INT
    )
    DUPLICATE KEY(order_id)
    DISTRIBUTED BY HASH(order_id)
    PROPERTIES (
        "bloom_filter_columns" = "order_id" -- 여기에 컬럼 지정
    );
4. 기타 특수 인덱스 (최신 버전) * Inverted Index (역색인): 텍스트 검색(
LIKE
등) 속도를 높일 때 사용합니다. (
USING GIN
) * N-Gram Bloom Filter: 긴 문자열의 부분 일치 검색을 최적화할 때 사용합니다. (
USING NGRAMBF
) * Vector Index: AI/벡터 유사도 검색 시 사용합니다. (
USING VECTOR
) 요약 가이드 1. 공통: 가장 자주 쓰는 필터 컬럼을
ORDER BY
맨 앞에 둡니다. 2. 동등 비교(=, IN): 해당 컬럼이 유니크에 가깝다면 *Bloom Filter*를, 값의 종류가 적다면 *Bitmap*을 고려하세요. 3. 텍스트 검색:
LIKE '%word%'
조회가 많다면 *Inverted Index*를 고려하세요. References • sql-reference/sql-statements/table_bucket_part_index/CREATE_INDEX.md • sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.md • table_design/indexes/Bloomfilter_index.md • table_design/indexes/vector_index.md
s
@Rocky 그냥 조회 성능을 위한 index를 걸고싶어, 일반 mysql처럼
r
MySQL과 같은 일반적인 보조 인덱스(Secondary Index) 기능을 원하신다면, StarRocks에서는 *'Inverted Index(역색인)'*가 그 역할을 가장 비슷하게 수행합니다. MySQL은 B-Tree 인덱스를 주로 사용하지만, 대용량 분석 시스템인 StarRocks는 데이터 저장 방식이 다르기 때문에 아래 2가지를 조합해서 인덱스 전략을 짭니다. ────────── 1. MySQL의 'Primary Key' 효과:
ORDER BY
(Prefix Index)
StarRocks 테이블 생성 시
ORDER BY
절에 적힌 컬럼들은 데이터가 정렬되어 저장됩니다. 이 컬럼들은 자동으로 *Prefix Index*가 생성되어
WHERE
조건에 해당 컬럼이 있으면 속도가 압도적으로 빠릅니다. * 특징: 테이블당 하나만 설정 가능. * 팁: 가장 자주 조회 조건으로 쓰는 컬럼 3~4개를 순서대로 넣으세요. 2. MySQL의 'Secondary Index' 효과:
Inverted Index
(추천)
v3.3 버전부터 지원되는 *Inverted Index (GIN)*는 MySQL에서 일반 인덱스를 거는 것과 가장 유사한 효과를 줍니다. `ORDER BY`에 포함되지 않은 컬럼으로 조회할 때 성능을 대폭 높여줍니다. * 설정 방법 (테이블 생성 시):
Copy code
sql
    CREATE TABLE search_table (
        id BIGINT,
        user_name VARCHAR(50),
        city VARCHAR(20),
        -- 일반적인 등호(=), 범위(>, <), IN 조건을 위한 인덱스
        INDEX idx_user (user_name) USING GIN("parser" = "none")
    )
    DUPLICATE KEY(id)
    ORDER BY (id) -- 기본 정렬 키
    DISTRIBUTED BY HASH(id);
* `"parser" = "none"`의 의미: MySQL 인덱스처럼 값 전체를 그대로 인덱싱한다는 뜻입니다. (텍스트 검색이 목적이라면
english
,
chinese
등의 parser를 사용) * 장점:
=
,
!=
,
>
,
<
,
IN
,
LIKE
조건을 모두 가속할 수 있습니다. 3. 기타 인덱스 선택 기준 MySQL 스타일의 인덱스 외에 데이터 특성에 따라 아래를 선택합니다. 인덱스 종류 | 추천 상황 (MySQL 비유) | 특징 Inverted Index | 일반적인 보조 인덱스 | 가장 범용적임. 등호, 범위, LIKE 가속 Bitmap Index | 성별, 지역 등 (중복값 많음) | 데이터 종류(Cardinality)가 적을 때 매우 효율적 Bloom Filter | ID, UUID 등 (중복값 거의 없음) | 특정 값이 '없음'을 빠르게 판단하여 스캔량 감소 요약: 어떻게 걸면 될까? 1. 가장 많이 쓰는 조회 컬럼은 *`ORDER BY`*에 넣는다. (가장 중요) 2. 그 외에 자주 검색되는 컬럼은 *`INDEX ... USING GIN("parser" = "none")`*을 추가한다. 3. 이미 만든 테이블에 인덱스를 추가하고 싶다면:
Copy code
sql
    ALTER TABLE table_name ADD INDEX idx_name (column_name) USING GIN("parser" = "none");
References • table_design/indexes/inverted_index.md • sql-reference/sql-statements/table_bucket_part_index/CREATE_INDEX.md • table_design/indexes/Bitmap_index.md References • table_design/indexes/inverted_index.md • best_practices/query_tuning/schema_tuning.md
s
@Rocky alter로 inverted index 사용하는 예시를 하나알려줘
r
기존 테이블에 `ALTER TABLE`을 사용하여 *Inverted Index(역색인)*를 추가하는 구체적인 예시입니다. 가장 일반적인 용도(MySQL의 일반 인덱스처럼 사용)와 텍스트 검색용 두 가지 상황으로 나누어 설명해 드립니다. 1. 일반적인 검색 성능 향상용 (ID, 이름 등 정확한 일치) MySQL의 일반 인덱스처럼 특정 값을 빠르게 찾고 싶을 때 사용합니다.
"parser" = "none"
설정이 핵심입니다.
Copy code
sql
-- 'users' 테이블의 'user_name' 컬럼에 인덱스 추가
ALTER TABLE users 
ADD INDEX idx_user_name (user_name) USING GIN("parser" = "none");
* 용도:
WHERE user_name = 'rocky'
,
WHERE user_name IN ('a', 'b')
등의 쿼리 가속. 2. 긴 문장 내 키워드 검색용 (Full-text Search) 로그 메시지나 게시글 내용처럼 긴 문자열에서 특정 단어를 찾고 싶을 때 사용합니다.
Copy code
sql
-- 'logs' 테이블의 'message' 컬럼에 단어 단위 인덱스 추가
ALTER TABLE logs 
ADD INDEX idx_message (message) USING GIN("parser" = "english");
* 용도:
WHERE message MATCH 'error'
처럼 특정 단어가 포함되었는지 찾는 쿼리 가속. ────────── 주의사항 및 팁 1. 동작 방식:
ALTER TABLE
명령어를 실행하면 백그라운드에서 기존 데이터에 대해 인덱스 생성 작업이 시작됩니다. 2. 진행 상태 확인: 인덱스가 잘 생성되고 있는지 아래 명령어로 확인할 수 있습니다.
Copy code
sql
    SHOW ALTER TABLE COLUMN;
(State가 `FINISHED`가 되면 인덱스가 완전히 적용된 것입니다.) 3. 삭제 방법: 만약 인덱스를 지우고 싶다면 다음 명령어를 사용합니다.
Copy code
sql
    ALTER TABLE users DROP INDEX idx_user_name;
참고: Inverted Index는 StarRocks *3.3 버전 이상*부터 정식 지원하므로, 사용 중인 버전을 꼭 확인해 보세요. (
SELECT VERSION();
) References • table_design/indexes/inverted_index.md • sql-reference/sql-statements/table_bucket_part_index/ALTER_TABLE.md • sql-reference/sql-statements/table_bucket_part_index/CREATE_INDEX.md
s
@Rocky “parser” = “none”이 뭐야
r
`"parser" = "none"`은 Inverted Index(역색인)를 만들 때 *"데이터를 쪼개지 않고 전체를 하나의 덩어리로 인덱싱하겠다"*는 설정입니다. 일반적인 텍스트 검색 엔진은 문장을 단어 단위로 자르지만(토큰화), `"none"`을 사용하면 *MySQL의 일반적인 B-Tree 인덱스처럼 작동*하게 됩니다. 주요 특징 1. 전체 일치 (Exact Match): * 예를 들어, 컬럼에 `"StarRocks is fast"`라는 값이 들어있다면, 이 전체 문장이 일치해야 인덱스를 탑니다. * 단어인 `"StarRocks"`나 `"fast"`만 검색해서는 인덱스 효과를 볼 수 없습니다. 2. 데이터 타입 제한 없음: * 문자열(VARCHAR, STRING)뿐만 아니라 숫자(INT, BIGINT), 날짜(DATETIME) 타입에도 사용할 수 있습니다. 3. 지원하는 연산: *
=
,
!=
,
>
,
>=
,
<
,
<=
,
IN
연산에 대해 검색 성능을 높여줍니다. *
LIKE
검색의 경우, `LIKE 'abc%'`와 같은 전방 일치 검색에서도 성능 향상을 기대할 수 있습니다. ────────── 다른 설정과의 비교 설정값 | 처리 방식 | 적합한 용도
"parser" = "none"
| 원문 그대로 저장 | ID, 사용자 이름, 상태 코드 등 정확한 값 비교
"parser" = "english"
| 영어 단어 단위로 쪼개서 저장 | 로그 메시지, 설명글 등 영어 키워드 검색
"parser" = "chinese"
| 중국어 형태소 분석 후 저장 | 중국어 텍스트 검색 왜 사용하나요? StarRocks에서 `ORDER BY`에 포함되지 않은 컬럼으로
WHERE column = 'value'
조회를 하면 전체 데이터를 다 뒤져야 할 수도 있습니다(Full Scan). 이때 `"parser" = "none"`으로 인덱스를 걸어두면, 테이블 전체를 읽지 않고 인덱스를 통해 해당 데이터가 있는 위치만 콕 집어낼 수 있어 조회 속도가 매우 빨라집니다. 한 줄 요약: MySQL에서 컬럼에 그냥 `INDEX`를 거는 것과 가장 유사한 동작을 하게 만드는 옵션입니다. References • table_design/indexes/inverted_index.md • sql-reference/sql-statements/table_bucket_part_index/CREATE_INDEX.md
s
@Rocky bloom_filter_index로 해야할거같은데, bloom_filter_columns에 적은 순서가 중요해?
r
결론부터 말씀드리면, `bloom_filter_columns`에 적는 컬럼의 순서는 전혀 중요하지 않습니다. 그 이유는 StarRocks가 Bloom Filter를 처리하는 방식 때문입니다. 1. 왜 순서가 상관없나요? MySQL의 복합 인덱스(Composite Index)는 여러 컬럼을 묶어서 하나의 인덱스 트리를 만들지만, StarRocks의 Bloom Filter는 *지정된 각 컬럼마다 개별적인 필터(인덱스)*를 생성합니다. * `"bloom_filter_columns" = "A, B"`라고 적으면 컬럼 A에 대한 필터 하나, 컬럼 B에 대한 필터 하나가 각각 독립적으로 생성됩니다. * 조회 시에도 쿼리 조건에 맞는 컬럼의 필터를 각각 따로 꺼내서 사용하므로, 어떤 것을 먼저 적었는지는 성능에 영향을 주지 않습니다. 2. 순서가 중요한 인덱스는 따로 있습니다:
ORDER BY
만약 MySQL의 복합 인덱스처럼 *순서가 성능에 결정적인 영향*을 주는 것을 찾으신다면, 그것은 테이블 생성 시 지정하는
ORDER BY
(Sort Key)
절입니다. * `ORDER BY (A, B, C)`: A가 가장 먼저 필터링에 사용되며, A 조건 없이 B나 C로만 조회하면 인덱스(Prefix Index) 효과를 제대로 보지 못합니다. (MySQL의 가장 왼쪽 접두사 원칙과 유사) 3. Bloom Filter 사용 시 진짜 중요한 것 순서보다는 아래의 *데이터 특성*을 고려하는 것이 훨씬 중요합니다. * 고유값(Cardinality)이 높은 컬럼: ID, 주민번호, 이메일처럼 값이 아주 다양한 컬럼에 걸어야 효과가 좋습니다. (성별처럼 값이 몇 개 없는 곳에는 비효율적) * = 또는 IN 조건: Bloom Filter는 오직
column = 1
또는
column IN (1, 2, 3)
같은 조건에서만 작동합니다. (범위 조회
>
나
<
에는 작동하지 않음) * 제외 대상: 해당 컬럼이 이미
ORDER BY
절의 앞부분에 포함되어 있다면, 이미 Prefix Index가 역할을 하고 있으므로 굳이 Bloom Filter를 또 걸 필요는 없습니다. 요약 * `bloom_filter_columns`의 순서는 상관없다. (각 컬럼별로 따로 생성됨) * 복합 인덱스 같은 효과를 내려면
ORDER BY
절의 컬럼 순서에 신경 써야 한다. * Bloom Filter는 *ID성 컬럼*의
=
조회
성능을 높이는 데 특화되어 있다. References • table_design/indexes/Bloomfilter_index.md • best_practices/query_tuning/schema_tuning.md • sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.md References • knowledge/usage/best-practice.md • table_design/indexes/Bloomfilter_index.md • best_practices/query_tuning/schema_tuning.md • sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.md
s
@Rocky 테이블 생성할때 starrocks에서 string으로 넣는거랑 varchar로 내가 byte정해서 넣는거랑 성능 차이가 있어?
r
StarRocks에서 `STRING`과 `VARCHAR(N)`은 저장 방식은 같지만, *쿼리 실행 시 메모리 관리 측면에서 차이가 발생*할 수 있습니다. 결론부터 말씀드리면, 가능한 한 적절한 길이를 지정한 *`VARCHAR(N)`을 사용하는 것이 성능상 유리*합니다. 구체적인 차이점은 다음과 같습니다. 1. 저장 공간 (Storage) - 차이 없음 * `STRING`과
VARCHAR
모두 가변 길이(Variable-length) 타입입니다. * 예를 들어, `VARCHAR(100)`과
STRING
컬럼에 똑같이 "Rocky"라는 5글자를 저장하면, 디스크에 차지하는 물리적인 저장 공간은 동일합니다. 2. 쿼리 성능 및 메모리 (Performance & Memory) - 차이 있음 * 메모리 예약(Pre-allocation): StarRocks의 일부 쿼리 실행 연산자(예: 조인, 집계 등)는 데이터를 처리하기 위해 메모리를 미리 할당합니다. 이때 실제 데이터의 길이가 아닌 *선언된 컬럼의 최대 길이*를 기준으로 메모리를 예약하는 경우가 있습니다. * `STRING`은 내부적으로 `VARCHAR(65533)`과 유사하게 취급됩니다. 따라서 `VARCHAR(20)`으로 충분한 컬럼을 `STRING`으로 설정하면, 시스템이 불필요하게 큰 메모리를 예약하게 되어 메모리 낭비가 발생하고 전체적인 쿼리 병렬 처리 능력이 떨어질 수 있습니다. 3. 프리픽스 인덱스 (Prefix Index) 영향 * StarRocks는 테이블의 앞부분 컬럼들을 조합해 36바이트의 *프리픽스 인덱스*를 생성합니다. * `VARCHAR`나
STRING
컬럼이 테이블 정의의 중간에 있으면 인덱스가 거기서 끊길 수 있습니다. 길이를 명확히 제한하면 인덱스 효율을 설계할 때 더 예측 가능해집니다. ────────── 요약 및 권장사항 1. 가장 좋은 방법: 실제 들어올 데이터의 최대 길이를 예상하여 *`VARCHAR(N)`*을 사용하세요. (예:
VARCHAR(50)
) 2. `STRING`을 쓰는 경우: 데이터의 길이를 도저히 가늠할 수 없거나, 65,533바이트를 초과하는 매우 긴 텍스트를 저장해야 할 때만 사용하세요. 3. 주의사항: StarRocks의 `VARCHAR(N)`에서 *`N`은 '글자 수'가 아니라 '바이트(Byte) 수'*입니다. 한글은 보통 한 글자에 3바이트를 차지하므로, 한글 10글자를 저장하려면 최소
VARCHAR(30)
이상으로 설정해야 합니다. 한 줄 결론: 디스크 용량은 같지만, *메모리 효율과 쿼리 속도*를 위해 `VARCHAR(N)`으로 길이를 지정해주는 것이 좋습니다. References • faq/table_design_faq.md • sql-reference/data-types/string-type/VARCHAR.md • faq/Sql_faq.md • faq/Others.md References • knowledge/usage/best-practice.md • faq/table_design_faq.md • faq/Others.md • sql-reference/data-types/string-type/VARCHAR.md • faq/Sql_faq.md • best_practices/query_tuning/schema_tuning.md