El perfilador de DataStore ayuda a medir el tiempo de ejecución e identificar cuellos de botella en el rendimiento.
from chdb import datastore as pd
from chdb.datastore.config import config, get_profiler
# Habilitar el perfilado
config.enable_profiling()
# Ejecutar las operaciones
ds = pd.read_csv("large_data.csv")
result = (ds
.filter(ds['amount'] > 100)
.groupby('category')
.agg({'amount': 'sum'})
.sort('sum', ascending=False)
.head(10)
.to_df()
)
# Ver el informe
profiler = get_profiler()
print(profiler.report())
from chdb.datastore.config import config
# Habilitar el perfilado
config.enable_profiling()
# Deshabilitar el perfilado
config.disable_profiling()
# Comprobar si el perfilado está habilitado
print(config.profiling_enabled) # True or False
from chdb.datastore.config import get_profiler
profiler = get_profiler()
Muestra un informe de rendimiento.
profiler.report(min_duration_ms=0.1)
Parámetros:
| Parámetro | Tipo | Predeterminado | Descripción |
|---|
min_duration_ms | float | 0.1 | Muestra solo pasos con una duración >= esta |
Salida de ejemplo:
======================================================================
EXECUTION PROFILE
======================================================================
45.79ms (100.0%) Total Execution
23.25ms ( 50.8%) Query Planning [ops_count=2]
22.29ms ( 48.7%) SQL Segment 1 [ops=2]
20.48ms ( 91.9%) SQL Execution
1.74ms ( 7.8%) Result to DataFrame
----------------------------------------------------------------------
TOTAL: 45.79ms
======================================================================
El informe muestra:
- Duración en milisegundos de cada paso
- Porcentaje del tiempo con respecto al padre/al total
- Anidamiento jerárquico de operaciones
- Metadatos de cada paso (p. ej.,
ops_count, ops)
Mide manualmente el tiempo de ejecución de un bloque de código.
with profiler.step("custom_operation"):
# Tu código aquí
expensive_operation()
Elimina todos los datos de perfilado.
Obtenga un diccionario con los nombres de los pasos y sus duraciones (ms).
summary = profiler.summary()
for name, duration in summary.items():
print(f"{name}: {duration:.2f}ms")
Salida de ejemplo:
Total Execution: 45.79ms
Total Execution.Cache Check: 0.00ms
Total Execution.Query Planning: 23.25ms
Total Execution.SQL Segment 1: 22.29ms
Total Execution.SQL Segment 1.SQL Execution: 20.48ms
Total Execution.SQL Segment 1.Result to DataFrame: 1.74ms
| Nombre del paso | Descripción |
|---|
Total Execution | Tiempo total de ejecución |
Query Planning | Tiempo dedicado a planificar la consulta |
SQL Segment N | Ejecución del segmento SQL N |
SQL Execution | Ejecución real de la consulta SQL |
Result to DataFrame | Conversión de los resultados a un DataFrame de pandas |
Cache Check | Verificación de la caché de consultas |
Cache Write | Escritura de los resultados en la caché |
- Pasos de planificación (Planificación de consultas): Suelen ser rápidos
- Pasos de ejecución (Ejecución de SQL): Donde se realiza el trabajo real
- Pasos de transferencia (Resultado a DataFrame): Conversión de datos a pandas
Identificación de cuellos de botella
======================================================================
EXECUTION PROFILE
======================================================================
200.50ms (100.0%) Total Execution
10.25ms ( 5.1%) Query Planning [ops_count=4]
190.00ms ( 94.8%) SQL Segment 1 [ops=4]
185.00ms ( 97.4%) SQL Execution <- Main bottleneck
5.00ms ( 2.6%) Result to DataFrame
----------------------------------------------------------------------
TOTAL: 200.50ms
======================================================================
Perfilar una sola consulta
config.enable_profiling()
profiler = get_profiler()
profiler.clear() # Limpiar datos anteriores
# Ejecutar consulta
result = ds.filter(...).groupby(...).agg(...).to_df()
# Ver el perfil de esta consulta
print(profiler.report())
Perfilar varias consultas
config.enable_profiling()
profiler = get_profiler()
profiler.clear()
# Consulta 1
with profiler.step("Query 1"):
result1 = query1.to_df()
# Consulta 2
with profiler.step("Query 2"):
result2 = query2.to_df()
print(profiler.report())
profiler = get_profiler()
# Enfoque 1: Filtrar y luego agrupar
profiler.clear()
with profiler.step("filter_then_groupby"):
result1 = ds.filter(ds['x'] > 10).groupby('y').sum().to_df()
summary1 = profiler.summary()
time1 = summary1.get('filter_then_groupby', 0)
# Enfoque 2: Agrupar y luego filtrar
profiler.clear()
with profiler.step("groupby_then_filter"):
result2 = ds.groupby('y').sum().filter(ds['x'] > 10).to_df()
summary2 = profiler.summary()
time2 = summary2.get('groupby_then_filter', 0)
print(f"Approach 1: {time1:.2f}ms")
print(f"Approach 2: {time2:.2f}ms")
print(f"Winner: {'Approach 1' if time1 < time2 else 'Approach 2'}")
Consejos para la optimización
1. Compruebe el tiempo de ejecución de SQL
Si SQL execution es el cuello de botella:
- Añada más filtros para reducir los datos
- Use Parquet en lugar de CSV
- Compruebe que haya índices adecuados (para fuentes de datos de bases de datos)
2. Verifique el tiempo de E/S
Si read_csv o read_parquet es el cuello de botella:
- Use Parquet (columnar, comprimido)
- Lea solo las columnas necesarias
- Filtre en origen si es posible
3. Comprobar la transferencia de datos
Si to_df es lento:
- El conjunto de resultados puede ser demasiado grande
- Añade más filtros o un límite
- Usa
head() para obtener una vista previa
from chdb.datastore.config import config
# Perfilar con chdb
config.use_chdb()
profiler.clear()
result_chdb = query.to_df()
time_chdb = profiler.total_duration_ms
# Perfilar con pandas
config.use_pandas()
profiler.clear()
result_pandas = query.to_df()
time_pandas = profiler.total_duration_ms
print(f"chdb: {time_chdb:.2f}ms")
print(f"pandas: {time_pandas:.2f}ms")
1. Perfila antes de optimizar
# ¡No adivines, mide!
config.enable_profiling()
result = your_query.to_df()
print(get_profiler().report())
2. Limpiar entre cada prueba
profiler.clear() # Limpiar datos anteriores
# Ejecutar prueba
print(profiler.report())
3. Usa min_duration_ms para enfocarte
# Mostrar solo operaciones >= 100ms
profiler.report(min_duration_ms=100)
4. Perfila datos representativos
# Perfila con tamaños de datos reales
# Los datos de prueba pequeños pueden no mostrar los verdaderos cuellos de botella
5. Deshabilitar en producción
# Desarrollo
config.enable_profiling()
# Producción
config.set_profiling_enabled(False) # Evitar sobrecarga
Ejemplo: sesión de perfilado completa
from chdb import datastore as pd
from chdb.datastore.config import config, get_profiler
# Configuración inicial
config.enable_profiling()
config.enable_debug() # Vea también qué está pasando
profiler = get_profiler()
# Cargar datos
profiler.clear()
print("=== Loading Data ===")
ds = pd.read_csv("sales_2024.csv") # 10 M de filas
print(profiler.report())
# Consulta 1: Filtro simple
profiler.clear()
print("\n=== Query 1: Simple Filter ===")
result1 = ds.filter(ds['amount'] > 1000).to_df()
print(profiler.report())
# Consulta 2: Agregación compleja
profiler.clear()
print("\n=== Query 2: Complex Aggregation ===")
result2 = (ds
.filter(ds['amount'] > 100)
.groupby('region', 'category')
.agg({
'amount': ['sum', 'mean', 'count'],
'quantity': 'sum'
})
.sort('sum', ascending=False)
.head(20)
.to_df()
)
print(profiler.report())
# Resumen
print("\n=== Summary ===")
print(f"Query 1: {len(result1)} rows")
print(f"Query 2: {len(result2)} rows")
Última modificación el 10 de junio de 2026