Indexing

DBX는 Bloom Filter 기반 인덱스를 제공하여 쿼리 성능을 크게 향상시킵니다.

Overview

DBX 인덱스의 주요 특징:

  • Bloom Filter 기반: 메모리 효율적인 확률적 자료구조
  • 빠른 조회: O(1) 시간 복잡도로 존재 여부 확인
  • 낮은 False Positive: 정확도 99% 이상
  • 자동 업데이트: 데이터 삽입 시 자동으로 인덱스 갱신

Quick Start

use dbx_core::Database;

let db = Database::open_in_memory()?;

// 인덱스 생성
db.create_index("users", "email")?;

// 데이터 삽입 (자동으로 인덱스 업데이트)
db.insert("users", b"user:1", b"alice@example.com")?;

// 빠른 조회
let row_ids = db.index_lookup("users", "email", b"alice@example.com")?;

Step-by-Step Guide

1. 인덱스 생성

테이블과 컬럼에 대한 인덱스를 생성합니다:

use dbx_core::Database;

let db = Database::open_in_memory()?;

// 'users' 테이블의 'email' 컬럼에 인덱스 생성
db.create_index("users", "email")?;

println!("✓ Index created on users.email");

2. 데이터 삽입

데이터를 삽입하면 인덱스가 자동으로 업데이트됩니다:

// 데이터 삽입
for i in 0..1000 {
    let key = format!("user:{}", i).into_bytes();
    let email = format!("user{}@example.com", i).into_bytes();
    db.insert("users", &key, &email)?;
}

println!("✓ Inserted 1000 users (index auto-updated)");

3. 인덱스 조회

인덱스를 사용하여 빠르게 데이터를 찾습니다:

// 특정 이메일을 가진 사용자 찾기
let email = b"user500@example.com";
let row_ids = db.index_lookup("users", "email", email)?;

println!("✓ Found {} matching rows", row_ids.len());

// 실제 데이터 조회
for row_id in row_ids {
    let key = format!("user:{}", row_id).into_bytes();
    if let Some(value) = db.get("users", &key)? {
        println!("  - {}: {}", row_id, String::from_utf8_lossy(&value));
    }
}

4. 성능 비교

인덱스 사용 전후의 성능을 비교합니다:

use std::time::Instant;

// 인덱스 없이 조회 (전체 스캔)
let start = Instant::now();
let mut found = 0;
for i in 0..1000 {
    let key = format!("user:{}", i).into_bytes();
    if let Some(_) = db.get("users", &key)? {
        found += 1;
    }
}
let without_index = start.elapsed();
println!("Without index: {:?} ({} rows)", without_index, found);

// 인덱스로 조회
let start = Instant::now();
let row_ids = db.index_lookup("users", "email", b"user500@example.com")?;
let with_index = start.elapsed();
println!("With index: {:?} ({} rows)", with_index, row_ids.len());

let speedup = without_index.as_secs_f64() / with_index.as_secs_f64();
println!("✓ Speedup: {:.2}x faster", speedup);

Complete Example

use dbx_core::{Database, DbxResult};
use std::time::Instant;

fn main() -> DbxResult<()> {
    println!("=== DBX Indexing Example ===\n");
    
    let db = Database::open_in_memory()?;
    
    // 1. 인덱스 생성
    println!("--- Creating Index ---");
    db.create_index("users", "email")?;
    println!("✓ Index created\n");
    
    // 2. 대량 데이터 삽입
    println!("--- Inserting Data ---");
    let start = Instant::now();
    for i in 0..10000 {
        let key = format!("user:{}", i).into_bytes();
        let email = format!("user{}@example.com", i).into_bytes();
        db.insert("users", &key, &email)?;
    }
    let insert_time = start.elapsed();
    println!("✓ Inserted 10,000 users in {:?}\n", insert_time);
    
    // 3. 인덱스 조회
    println!("--- Index Lookup ---");
    let start = Instant::now();
    let row_ids = db.index_lookup("users", "email", b"user5000@example.com")?;
    let lookup_time = start.elapsed();
    println!("✓ Found {} rows in {:?}\n", row_ids.len(), lookup_time);
    
    // 4. 실제 데이터 조회
    println!("--- Fetching Data ---");
    for row_id in &row_ids {
        let key = format!("user:{}", row_id).into_bytes();
        if let Some(value) = db.get("users", &key)? {
            println!("  Row {}: {}", row_id, String::from_utf8_lossy(&value));
        }
    }
    
    println!("\n=== Example Complete ===");
    Ok(())
}

Running the Example

cargo run --example index_test

Expected Output

=== DBX Indexing Example ===

--- Creating Index ---
✓ Index created

--- Inserting Data ---
✓ Inserted 10,000 users in 45ms

--- Index Lookup ---
✓ Found 1 rows in 12μs

--- Fetching Data ---
  Row 5000: user5000@example.com

=== Example Complete ===

Performance Characteristics

Bloom Filter 특성

작업 시간 복잡도 메모리 사용량
인덱스 생성 O(1) ~10 bytes/key
삽입 O(1) -
조회 O(1) -
False Positive < 1% -

성능 벤치마크

10,000개 행에서의 성능:

전체 스캔:    ~5ms
인덱스 조회:  ~12μs
속도 향상:    ~400x

Best Practices

1. 인덱스 생성 시점

// ✅ GOOD: 데이터 삽입 전에 인덱스 생성
db.create_index("users", "email")?;
for i in 0..10000 {
    db.insert("users", &key, &value)?;
}

// ⚠️ OK: 데이터 삽입 후에도 가능 (재구축 필요)
for i in 0..10000 {
    db.insert("users", &key, &value)?;
}
db.create_index("users", "email")?;  // 기존 데이터 인덱싱

2. 인덱스 선택

자주 조회하는 컬럼에만 인덱스를 생성하세요:

// ✅ GOOD: WHERE 절에 자주 사용되는 컬럼
db.create_index("users", "email")?;
db.create_index("orders", "user_id")?;

// ❌ BAD: 거의 조회하지 않는 컬럼
db.create_index("logs", "timestamp")?;  // 불필요

3. 메모리 관리

인덱스는 메모리를 사용하므로 필요한 것만 생성하세요:

// 인덱스 메모리 사용량 추정
// ~10 bytes per key
// 1M keys = ~10MB

Limitations

False Positives

Bloom Filter는 확률적 자료구조이므로 False Positive가 발생할 수 있습니다:

// 인덱스 조회 결과는 "아마도 존재함"
let row_ids = db.index_lookup("users", "email", b"test@example.com")?;

// 실제 데이터 확인 필요
for row_id in row_ids {
    if let Some(value) = db.get("users", &key)? {
        // 실제로 존재하는 데이터
    }
}

지원하지 않는 기능

  • 범위 쿼리 (range queries)
  • 정렬 (sorting)
  • 부분 일치 (partial matching)

Next Steps


Copyright © 2026 ByteLogicCore. MIT OR Apache-2.0 License.

This site uses Just the Docs, a documentation theme for Jekyll.