<@U0A71G31CDV> PK테이블 만들건데, distribute by hash에는 어...
# questions-and-troubleshooting
s
@Rocky PK테이블 만들건데, distribute by hash에는 어떤 컬럼이 들어가는게 이상적이야?
r
StarRocks의 *Primary Key(PK) 테이블*에서
DISTRIBUTED BY HASH
컬럼(버킷 키)을 선정할 때는 다음의 원칙을 따르는 것이 가장 이상적입니다. 1. [필수] PK의 부분 집합이어야 함 PK 테이블에서는 *버킷 키로 설정하려는 컬럼이 반드시 Primary Key에 포함*되어야 합니다. * 예: PK가 `(order_id, dt)`라면, 버킷 키는
order_id
또는
dt
, 혹은
(order_id, dt)
전체가 될 수 있습니다. (PK에 없는 컬럼은 버킷 키로 쓸 수 없음) 2. 높은 카디널리티 (High Cardinality) 데이터가 여러 버킷에 골고루 분산되도록 *중복도가 낮고 유니크한 값이 많은 컬럼*을 선택해야 합니다. * 이상적: ID, Serial Number, 주문번호 등 * 피해야 할 것: 성별, 상태값(Y/N), 날짜(파티션 키와 겹칠 경우 데이터 쏠림 위험) 등 중복이 심한 컬럼 3. 자주 사용되는 쿼리 조건 (Bucket Pruning)
WHERE
절에서 필터 조건으로 자주 쓰이는 컬럼을 버킷 키로 잡으면, 쿼리 시 해당 버킷만 골라 읽는 *Bucket Pruning*이 작동하여 성능이 비약적으로 향상됩니다. * 예:
WHERE user_id = 123
형태의 쿼리가 많다면 `user_id`를 버킷 키로 설정 4. 조인(Join) 성능 고려 (Colocate Join) 두 테이블을 조인할 때, *조인 키를 두 테이블 모두의 버킷 키*로 설정하고 버킷 수를 맞추면 *Colocate Join*이 발생합니다. 이는 네트워크를 통한 데이터 이동(Shuffle) 없이 로컬에서 바로 조인을 수행하게 해줍니다. ────────── 요약 가이드 * 최우선: PK 중 하나이면서 값이 매우 다양한 컬럼 (예:
user_id
,
order_id
) * 개수: 보통 1~3개 이내의 컬럼을 권장합니다. * 데이터 쏠림 주의: 특정 값에 데이터가 몰려있다면(Skew), 해당 컬럼만 단독으로 버킷 키로 쓰지 말고 다른 PK 컬럼과 조합하세요. 예시 코드:
Copy code
sql
CREATE TABLE orders (
    order_id BIGINT NOT NULL,
    dt DATE NOT NULL,
    user_id INT NOT NULL,
    amount DECIMAL(10, 2)
) PRIMARY KEY (order_id) -- order_id가 PK
DISTRIBUTED BY HASH (order_id) -- PK인 order_id를 버킷 키로 사용 (이상적)
PROPERTIES ("enable_persistent_index" = "true");
``` ## References - [table_design/table_types/primary_key_table.md](https://docs.starrocks.io/docs/table_design/table_types/primary_key_table) - [best_practices/primarykey_table.md](https://docs.starrocks.io/docs/best_practices/primarykey_table) - [best_practices/bucketing.md](https://docs.starrocks.io/docs/best_practices/bucketing) - [table_design/data_distribution/Data_distribution.md](https://docs.starrocks.io/docs/table_design/data_distribution/Data_distribution)
s
@Rocky pandas dataframe에서 upsert하려면 어떻게해
r
StarRocks의 *Primary Key(PK) 테이블*은 데이터가 삽입될 때 동일한 PK가 있으면 자동으로 업데이트(Upsert)를 수행합니다. Pandas DataFrame의 데이터를 Upsert하는 가장 대표적인 두 가지 방법을 소개합니다. 1.
starrocks
라이브러리와
df.to_sql
사용 (가장 간단한 방법)
SQLAlchemy 기반의 공식 Python 클라이언트를 사용하여
to_sql
메서드로 데이터를 밀어 넣을 수 있습니다. 대상 테이블이 *Primary Key 테이블*로 생성되어 있다면,
if_exists='append'
설정만으로 중복 키에 대해 Upsert가 발생합니다.
Copy code
python
import pandas as pd
from sqlalchemy import create_engine

# 1. SQLAlchemy 엔진 생성 (pip install starrocks)
# 형식: starrocks://<user>:<password>@<host>:<port>/<database>
engine = create_engine("<starrocks://root:@127.0.0.1:9030/test_db>")

# 2. 샘플 데이터프레임 생성
df = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie'],
    'score': [100, 90, 85]
})

# 3. 데이터 삽입 (PK 테이블인 경우 자동으로 Upsert 수행)
df.to_sql('my_pk_table', engine, if_exists='append', index=False)
* 장점: 코드가 매우 간단함. * 단점: 대량의 데이터를 처리할 때 속도가 느릴 수 있음 (JDBC/Insert 방식의 한계). ────────── 2. Stream Load 사용 (고성능 권장 방식) 데이터가 수만 건 이상인 경우, StarRocks의 핵심 기능인 *Stream Load*를 사용하는 것이 훨씬 빠릅니다. Pandas의 `to_csv`로 데이터를 변환한 뒤 HTTP 통신으로 바로 쏴주는 방식입니다.
Copy code
python
import requests
import io

def stream_load_upsert(df, host, port, db, table, user, password):
    # 1. 데이터프레임을 CSV 버퍼로 변환
    csv_buffer = io.StringIO()
    df.to_csv(csv_buffer, index=False, header=False)
    
    # 2. Stream Load API 호출
    url = f"http://{host}:{port}/api/{db}/{table}/_stream_load"
    headers = {
        "Expect": "100-continue",
        "column_separator": ",",
        "format": "csv"
    }
    
    auth = (user, password)
    response = requests.put(url, data=csv_buffer.getvalue().encode('utf-8'), headers=headers, auth=auth)
    return response.json()

# 사용 예시
df = pd.DataFrame({'id': [1], 'name': ['Rocky'], 'score': [99]})
res = stream_load_upsert(df, 'FE_HOST', 8030, 'test_db', 'my_pk_table', 'root', '')
print(res)
* 장점: 매우 빠름 (초당 수십만 건 이상 가능). * 중요:
Expect: 100-continue
헤더를 포함해야 하며, 대상 테이블은 반드시 *Primary Key 테이블*이어야 합니다. ────────── 필수 확인 사항 성공적인 Upsert를 위해서는 대상 테이블이 반드시 다음과 같이 Primary Key 엔진으로 생성되어 있어야 합니다.
Copy code
sql
CREATE TABLE my_pk_table (
    id INT NOT NULL,
    name VARCHAR(65533),
    score INT
) PRIMARY KEY (id)  -- 이 설정이 있어야 Upsert가 작동함
DISTRIBUTED BY HASH(id);
참고: * 부분 업데이트 (Partial Update): 만약 데이터프레임에 테이블의 일부 컬럼만 있고 해당 컬럼만 업데이트하고 싶다면, Stream Load 시 헤더에 `partial_update: true`를 추가하세요. (StarRocks v2.5 이상) * 조건부 업데이트:
__op
컬럼을 명시하여 특정 조건에서만 Upsert 하거나 Delete를 동시에 수행할 수도 있습니다. References • loading/Load_to_Primary_Key_tables.md • loading/InsertInto.md • unloading/arrow_flight.md • table_design/table_types/primary_key_table.md References • faq/Others.md • loading/Load_to_Primary_Key_tables.md • loading/InsertInto.md • unloading/arrow_flight.md