DataStore поддерживает два режима совместимости, которые определяют, будут ли выходные данные формироваться для совместимости с pandas или оптимизироваться для производительности Raw SQL.
| Режим | значение compat_mode | Описание |
|---|
| Pandas (по умолчанию) | "pandas" | Полная совместимость с поведением pandas. Сохраняется порядок строк, поддерживаются MultiIndex и set_index, применяются исправления dtype, стабильная сортировка при равенстве ключей и обёртки -If/isNaN. |
| Performance | "performance" | Выполнение с приоритетом SQL. Полностью устранены все накладные расходы на совместимость с pandas. Максимальная пропускная способность, но структура результатов может отличаться от pandas. |
Что отключает режим производительности
| Накладные расходы | Поведение в режиме Pandas | Поведение в режиме производительности |
|---|
| Сохранение порядка строк | внедрение _row_id, rowNumberInAllBlocks(), подзапросы __orig_row_num__ | Отключено — порядок строк не гарантируется |
| Стабильное разрешение равенства при сортировке | к ORDER BY добавляется rowNumberInAllBlocks() ASC | Отключено — строки с одинаковыми значениями могут идти в произвольном порядке |
| Parquet preserve_order | input_format_parquet_preserve_order=1 | Отключено — разрешено параллельное чтение Parquet |
| Автоматический ORDER BY для GroupBy | добавляется ORDER BY group_key (поведение pandas по умолчанию: sort=True) | Отключено — группы возвращаются в произвольном порядке |
| WHERE dropna для GroupBy | добавляется WHERE key IS NOT NULL (поведение pandas по умолчанию: dropna=True) | Отключено — группы с NULL включаются |
| set_index для GroupBy | ключи групп задаются как индекс | Отключено — ключи групп остаются столбцами |
| Столбцы MultiIndex | agg({'col': ['sum','mean']}) возвращает столбцы MultiIndex | Отключено — плоские имена столбцов (col_sum, col_mean) |
Обёртки -If/isNaN | sumIf(col, NOT isNaN(col)) для skipna | Отключено — обычный sum(col) (ClickHouse нативно пропускает NULL) |
toInt64 для count | toInt64(count()) для соответствия pandas int64 | Отключено — возвращается нативный SQL-тип данных |
fillna(0) для sum из одних NaN | сумма из одних NaN возвращает 0 (поведение pandas) | Отключено — возвращает NULL |
| Коррекция dtype | abs() беззнаковый→знаковый и т. д. | Отключено — нативные SQL-типы данных |
| Сохранение индекса | восстанавливает исходный индекс после выполнения SQL | Отключено |
first()/last() | argMin/argMax(col, rowNumberInAllBlocks()) | any(col) / anyLast(col) — быстрее, но недетерминированно |
| Агрегация одним SQL-запросом | ColumnExpr groupby материализует промежуточный DataFrame | Внедряет LazyGroupByAgg в цепочку lazy-операций — один SQL-запрос |
Включение режима производительности
Использование объекта config
from chdb.datastore.config import config
# Включить режим производительности
config.use_performance_mode()
# Вернуться к совместимости с pandas
config.use_pandas_compat()
# Проверить текущий режим
print(config.compat_mode) # 'pandas' или 'performance'
Использование функций модуля
from chdb.datastore.config import set_compat_mode, CompatMode, is_performance_mode
# Включить режим производительности
set_compat_mode(CompatMode.PERFORMANCE)
# Проверка
print(is_performance_mode()) # True
# Вернуться к значению по умолчанию
set_compat_mode(CompatMode.PANDAS)
Использование удобных импортов
from chdb import use_performance_mode, use_pandas_compat
use_performance_mode()
# ... высокопроизводительные операции ...
use_pandas_compat()
При включении режима производительности движок выполнения автоматически устанавливается в chdb. Отдельно вызывать config.use_chdb() не нужно.
Когда использовать режим производительности
Используйте режим производительности, если:
- Обрабатываете большие наборы данных (от сотен тысяч до миллионов строк)
- Выполняете рабочие нагрузки с интенсивной агрегацией (groupby, sum, mean, count)
- Порядок строк не имеет значения (например, для агрегированных результатов, отчетов, панелей мониторинга)
- Вам нужна максимальная пропускная способность SQL и минимальные накладные расходы
- Важно использование памяти (параллельное чтение Parquet, без промежуточных DataFrame)
Оставайтесь в режиме pandas, если:
- Вам нужно точное поведение pandas (порядок строк, MultiIndex, dtypes)
- Вам важно, чтобы
first()/last() возвращали действительно первую/последнюю строку
- Вы используете
shift(), diff(), cumsum(), которые зависят от порядка строк
- Вы пишете тесты, сравнивающие вывод DataStore с pandas
В режиме производительности порядок строк не гарантируется ни для одной операции. Это относится к следующему:
- Результаты фильтрации
- Результаты агрегации
GroupBy
head() / tail() без явного sort_values()
- Агрегации
first() / last()
Если вам нужны упорядоченные результаты, добавьте явный sort_values():
config.use_performance_mode()
ds = pd.read_csv("data.csv")
# Без сортировки (быстро)
result = ds.groupby("region")["revenue"].sum()
# С сортировкой (всё ещё быстро, просто добавляет ORDER BY)
result = ds.groupby("region")["revenue"].sum().sort_values()
| Аспект | Режим Pandas | режим производительности |
|---|
| Расположение ключа группировки | Индекс (через set_index) | Обычный столбец |
| Порядок групп | Сортируются по ключу (по умолчанию) | Произвольный порядок |
| Группы с NULL | Исключаются (по умолчанию dropna=True) | Включаются |
| Формат столбцов | MultiIndex для нескольких агрегаций | Плоские имена (col_func) |
first()/last() | Детерминированные (порядок строк) | Недетерминированные (any()/anyLast()) |
config.use_performance_mode()
# Сумма группы, состоящей только из NaN, возвращает NULL (не 0)
# Count возвращает native uint64 (не принудительный int64)
# Без обёрток -If: sum() вместо sumIf()
result = ds.groupby("cat")["val"].sum()
Выполнение одним SQL-запросом
В режиме производительности агрегирование ColumnExpr с groupby (например, ds[condition].groupby('col')['val'].sum()) выполняется одним SQL-запросом, а не в два этапа, как в режиме pandas:
config.use_performance_mode()
# Режим Pandas: два SQL-запроса (filter → materialize → groupby)
# Режим производительности: один SQL-запрос (WHERE + GROUP BY в одном запросе)
result = ds[ds["rating"] > 3.5].groupby("category")["revenue"].sum()
# Сгенерированный SQL (один запрос):
# SELECT category, sum(revenue) FROM data WHERE rating > 3.5 GROUP BY category
Это позволяет избежать промежуточной материализации DataFrame и может значительно сократить использование памяти и время выполнения.
Сравнение с движком выполнения
Режим производительности (compat_mode) и движок выполнения (execution_engine) — независимые параметры конфигурации:
| Параметр | Управляет | Значения |
|---|
execution_engine | Какой движок выполняет вычисления | auto, chdb, pandas |
compat_mode | Нужно ли преобразовывать вывод для совместимости с pandas | pandas, performance |
При установке compat_mode='performance' значение execution_engine автоматически задаётся как chdb, поскольку режим производительности предназначен для выполнения SQL.
from chdb.datastore.config import config
# Это независимые настройки
config.use_chdb() # Принудительно использовать движок chDB, сохранить совместимость с pandas
config.use_performance_mode() # Принудительно использовать chDB + убрать накладные расходы pandas
Тестирование в режиме производительности
При написании тестов для режима производительности результаты могут отличаться от pandas порядком строк и структурой данных. Используйте следующие стратегии:
Сравнение после сортировки (агрегации, фильтры)
# Отсортировать обе стороны по одинаковым столбцам перед сравнением
ds_result = ds.groupby("cat")["val"].sum()
pd_result = pd_df.groupby("cat")["val"].sum()
ds_sorted = ds_result.sort_index()
pd_sorted = pd_result.sort_index()
np.testing.assert_array_equal(ds_sorted.values, pd_sorted.values)
Проверка диапазона значений (первое/последнее)
# first() с any() возвращает произвольный элемент из группы
result = ds.groupby("cat")["val"].first()
for group_key in groups:
assert result.loc[group_key] in group_values[group_key]
Схема и число строк (LIMIT без ORDER BY)
# head() без sort_values: набор строк недетерминирован
result = ds.head(5)
assert len(result) == 5
assert set(result.columns) == expected_columns
1. Включайте в начале скрипта
from chdb.datastore.config import config
config.use_performance_mode()
# Все последующие операции получают преимущество
ds = pd.read_parquet("data.parquet")
result = ds[ds["amount"] > 100].groupby("region")["amount"].sum()
2. Явно задавайте сортировку, когда важен порядок
# Для отображения или последующей обработки, требующей определённого порядка
result = (ds
.groupby("region")["revenue"].sum()
.sort_values(ascending=False)
)
3. Используйте для батч- и ETL-нагрузок
config.use_performance_mode()
# ETL-конвейер — порядок не важен, важна пропускная способность
summary = (ds
.filter(ds["date"] >= "2024-01-01")
.groupby(["region", "product"])
.agg({"revenue": "sum", "quantity": "sum", "rating": "mean"})
)
summary.to_df().to_parquet("summary.parquet")
4. Переключение режимов в одном сеансе
# Режим производительности для ресурсоёмких вычислений
config.use_performance_mode()
aggregated = ds.groupby("cat")["val"].sum()
# Возврат в режим pandas для точного сравнения
config.use_pandas_compat()
detailed = ds[ds["val"] > 100].head(10)
Последнее изменение 10 июня 2026 г.