> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Руководство по производительности

> Советы по оптимизации производительности DataStore по сравнению с pandas

DataStore обеспечивает заметно более высокую производительность, чем pandas, во многих операциях. В этом руководстве объясняется, почему это так и как оптимизировать рабочие нагрузки.

## Почему DataStore работает быстрее

### 1. SQL Pushdown

Operations выполняются на стороне источника данных:

```python theme={null}
# pandas: Loads ALL data, then filters in memory
df = pd.read_csv("huge.csv")       # Load 10GB
df = df[df['year'] == 2024]        # Filter in Python

# DataStore: Filter at source
ds = pd.read_csv("huge.csv")       # Just metadata
ds = ds[ds['year'] == 2024]        # Filter in SQL
df = ds.to_df()                    # Only load filtered data
```

### 2. Отсечение столбцов

Считываются только необходимые столбцы:

```python theme={null}
# DataStore: Only reads name, age columns
ds = pd.read_parquet("wide_table.parquet")
result = ds.select('name', 'age').to_df()

# vs pandas: Reads all 100 columns, then selects
```

### 3. Отложенное вычисление

Несколько операций сводятся к одному запросу:

```python theme={null}
# DataStore: One optimized SQL query
result = (ds
    .filter(ds['amount'] > 100)
    .groupby('region')
    .agg({'amount': 'sum'})
    .sort('sum', ascending=False)
    .head(10)
    .to_df()
)

# Becomes:
# SELECT region, SUM(amount) FROM data
# WHERE amount > 100
# GROUP BY region ORDER BY sum DESC LIMIT 10
```

***

## Бенчмарк: DataStore и pandas

### Тестовая среда

* Данные: 10 миллионов строк
* Оборудование: стандартный ноутбук
* Формат файла: CSV

### Результаты

| Операция | pandas (мс) | DataStore (мс) | Победитель |
| - | - | - | - |
| Подсчет в GroupBy | 347 | 17 | **DataStore (19.93x)** |
| Комбинация операций | 1,535 | 234 | **DataStore (6.56x)** |
| Сложный конвейер | 2,047 | 380 | **DataStore (5.39x)** |
| MultiFilter+Sort+Head | 1,963 | 366 | **DataStore (5.36x)** |
| Filter+Sort+Head | 1,537 | 350 | **DataStore (4.40x)** |
| Head/Limit | 166 | 45 | **DataStore (3.69x)** |
| Сверхсложный (10+ операций) | 1,070 | 338 | **DataStore (3.17x)** |
| Агрегация GroupBy | 406 | 141 | **DataStore (2.88x)** |
| Select+Filter+Sort | 1,217 | 443 | **DataStore (2.75x)** |
| Filter+GroupBy+Sort | 466 | 184 | **DataStore (2.53x)** |
| Filter+Select+Sort | 1,285 | 533 | **DataStore (2.41x)** |
| Sort (одиночный) | 1,742 | 1,197 | **DataStore (1.45x)** |
| Filter (одиночный) | 276 | 526 | Сопоставимо |
| Sort (multiple) | 947 | 1,477 | Сопоставимо |

### Ключевые выводы

1. **Операции GroupBy**: DataStore до **19,93 раза быстрее**
2. **Сложные конвейеры**: DataStore **в 5–6 раз быстрее** (за счёт SQL pushdown)
3. **Простые операции среза**: Производительность сопоставима — разность незначительна
4. **Лучший сценарий использования**: Многошаговые операции с GroupBy/агрегацией
5. **Zero-copy**: `to_df()` работает без накладных расходов на преобразование данных

***

## Когда DataStore предпочтительнее

### Ресурсоемкие агрегации

```python theme={null}
# DataStore excels: 19.93x faster
result = ds.groupby('category')['amount'].sum()
```

### Сложные конвейеры

```python theme={null}
# DataStore excels: 5-6x faster
result = (ds
    .filter(ds['date'] >= '2024-01-01')
    .filter(ds['amount'] > 100)
    .groupby('region')
    .agg({'amount': ['sum', 'mean', 'count']})
    .sort('sum', ascending=False)
    .head(20)
)
```

### Обработка больших файлов

```python theme={null}
# DataStore: Only loads what you need
ds = pd.read_parquet("huge_file.parquet")
result = ds.filter(ds['id'] == 12345).to_df()  # Fast!
```

### Операции над несколькими столбцами

```python theme={null}
# DataStore: Combines into single SQL
ds['total'] = ds['price'] * ds['quantity']
ds['is_large'] = ds['total'] > 1000
ds = ds.filter(ds['is_large'])
```

***

## Когда производительность pandas сопоставима

В большинстве сценариев DataStore не уступает pandas по производительности или превосходит его. Однако в следующих случаях pandas может быть немного быстрее:

### Небольшие наборы данных (\<1,000 строк)

```python theme={null}
# For very small datasets, overhead is minimal for both
# Performance difference is negligible
small_df = pd.DataFrame({'x': range(100)})
```

### Простые операции среза

```python theme={null}
# Single slice operations without aggregation
df = df[df['x'] > 10]  # pandas slightly faster
ds = ds[ds['x'] > 10]  # DataStore comparable
```

### Пользовательские лямбда-функции Python

```python theme={null}
# pandas required for custom Python code
def complex_function(row):
    return custom_logic(row)

df['result'] = df.apply(complex_function, axis=1)
```

> [!NOTE]
>
> **Важно**
>
> Даже в сценариях, где DataStore работает «медленнее», производительность обычно **сопоставима с pandas** — для практического использования разница пренебрежимо мала. Преимущества DataStore при сложных операциях с лихвой перевешивают такие редкие случаи.
>
> Для более тонкой настройки выполнения см. [Настройка движка выполнения](https://clickhouse.com/docs/ru/chdb/configuration/execution-engine.md).

***

## Интеграция DataFrame с поддержкой zero-copy

DataStore использует **zero-copy** при чтении и записи pandas DataFrame. Это означает:

```python theme={null}
# to_df() does NOT copy data - it's a zero-copy operation
result = ds.filter(ds['x'] > 10).to_df()  # No data conversion overhead

# Same for creating DataStore from DataFrame
ds = DataStore(existing_df)  # No data copy
```

**Ключевые выводы:**

* `to_df()` практически ничего не стоит — без сериализации и копирования данных в памяти
* Создание DataStore из pandas DataFrame происходит мгновенно
* Память используется совместно между DataStore и представлениями pandas

***

## Советы по оптимизации

### 1. Включите режим производительности для ресурсоёмких рабочих нагрузок

Для рабочих нагрузок с интенсивной агрегацией, где вам не требуется точный формат вывода pandas (порядок строк, столбцы MultiIndex, корректировка dtype), включите режим производительности для максимальной пропускной способности:

```python theme={null}
from chdb.datastore.config import config

config.use_performance_mode()

# Now all operations use SQL-first execution with no pandas overhead:
# - Parallel Parquet reading (no preserve_order)
# - Single-SQL aggregation (filter+groupby in one query)
# - No row-order preservation overhead
# - No MultiIndex, no dtype corrections
result = (ds
    .filter(ds['amount'] > 100)
    .groupby('region')
    .agg({'amount': ['sum', 'mean', 'count']})
)
```

**Ожидаемое улучшение**: ускорение до 2–8 раз для рабочих нагрузок с filter+groupby, снижение использования памяти при работе с большими файлами Parquet.

См. [режим производительности](https://clickhouse.com/docs/ru/chdb/configuration/performance-mode.md) для получения полной информации.

### 2. Используйте формат Parquet вместо CSV

```python theme={null}
# CSV: Slower, reads entire file
ds = pd.read_csv("data.csv")

# Parquet: Faster, columnar, compressed
ds = pd.read_parquet("data.parquet")

# Convert once, benefit forever
df = pd.read_csv("data.csv")
df.to_parquet("data.parquet")
```

**Ожидаемое ускорение**: чтение в 3–10 раз быстрее

### 3. Фильтруйте как можно раньше

```python theme={null}
# Good: Filter first, then aggregate
result = (ds
    .filter(ds['date'] >= '2024-01-01')  # Reduce data early
    .groupby('category')['amount'].sum()
)

# Less optimal: Process all data
result = (ds
    .groupby('category')['amount'].sum()
    .filter(ds['sum'] > 1000)  # Filter too late
)
```

### 4. Выбирайте только нужные столбцы

```python theme={null}
# Good: отсечение столбцов
result = ds.select('name', 'amount').filter(ds['amount'] > 100)

# Less optimal: All columns loaded
result = ds.filter(ds['amount'] > 100)  # Loads all columns
```

### 5. Используйте SQL-агрегации

```python theme={null}
# GroupBy is where DataStore shines
# Up to 20x speedup!
result = ds.groupby('category').agg({
    'amount': ['sum', 'mean', 'count', 'max'],
    'quantity': 'sum'
})
```

### 6. Используйте head() вместо полноценных запросов

```python theme={null}
# Don't load entire result if you only need a sample
result = ds.filter(ds['type'] == 'A').head(100)  # LIMIT 100

# Avoid this for large results
# result = ds.filter(ds['type'] == 'A').to_df()  # Loads everything
```

### 7. Пакетные операции

```python theme={null}
# Good: Single execution
result = ds.filter(ds['x'] > 10).filter(ds['y'] < 100).to_df()

# Bad: Multiple executions
result1 = ds.filter(ds['x'] > 10).to_df()  # Execute
result2 = result1[result1['y'] < 100]       # Execute again
```

### 8. Используйте explain() для оптимизации

```python theme={null}
# View the query plan before executing
query = ds.filter(...).groupby(...).agg(...)
query.explain()  # Check if operations are pushed down

# Then execute
result = query.to_df()
```

***

## Профилирование рабочей нагрузки

### Включить профилирование

```python theme={null}
from chdb.datastore.config import config, get_profiler

config.enable_profiling()

# Run your workload
result = your_pipeline()

# View report
profiler = get_profiler()
profiler.report()
```

### Выявите узкие места

```text theme={null}
Performance Report
==================
Step                    Duration    % Total
----                    --------    -------
SQL execution           2.5s        62.5%     <- Bottleneck!
read_csv                1.2s        30.0%
Other                   0.3s        7.5%
```

### Сравнение подходов

```python theme={null}
# Test approach 1
profiler.reset()
result1 = approach1()
time1 = profiler.get_steps()[-1]['duration_ms']

# Test approach 2
profiler.reset()
result2 = approach2()
time2 = profiler.get_steps()[-1]['duration_ms']

print(f"Approach 1: {time1:.0f}ms")
print(f"Approach 2: {time2:.0f}ms")
```

***

## Сводка рекомендаций

| Практика | Эффект |
| - | - |
| Включите режим производительности | В 2–8 раз быстрее для задач с агрегацией |
| Используйте файлы Parquet | Чтение в 3–10 раз быстрее |
| Фильтруйте как можно раньше | Сократите объём обрабатываемых данных |
| Выбирайте только нужные столбцы | Сократите I/O и расход памяти |
| Используйте GroupBy/агрегации | До 20 раз быстрее |
| Выполняйте операции батчами | Избегайте повторного выполнения |
| Профилируйте перед оптимизацией | Находите реальные узкие места |
| Используйте explain() | Проверяйте оптимизацию запроса |
| Используйте head() для выборок | Избегайте полного сканирования таблицы |

***

## Краткое руководство по выбору

| Ваша рабочая нагрузка | Рекомендация |
| - | - |
| GroupBy/агрегация | Используйте DataStore |
| Сложный многоэтапный конвейер | Используйте DataStore |
| Большие файлы с фильтрами | Используйте DataStore |
| Простые операции среза | Любой из вариантов (сопоставимая производительность) |
| Пользовательские Python лямбда-функции | Используйте pandas или откладывайте преобразование на потом |
| Очень небольшой объём данных (\<1,000 строк) | Любой из вариантов (разница пренебрежимо мала) |

> [!TIP]
>
> Для автоматического выбора оптимального движка используйте `config.set_execution_engine('auto')` (по умолчанию).
> Для максимальной пропускной способности в рабочих нагрузках с агрегацией используйте `config.use_performance_mode()`.
> Подробности см. в разделах [Движок выполнения](https://clickhouse.com/docs/ru/chdb/configuration/execution-engine.md) и [Режим производительности](https://clickhouse.com/docs/ru/chdb/configuration/performance-mode.md).
