El método explain() muestra el plan de ejecución de una consulta de DataStore, lo que te ayuda a entender qué operaciones se realizarán y qué SQL se generará.
Uso básico
from pathlib import Path
Path("sales.csv").write_text("""\
region,product,category,amount,quantity,price,date,order_id
East,Widget,Electronics,5200,10,120,2024-01-15,1001
West,Gadget,Electronics,800,5,160,2024-02-20,1002
East,Gizmo,Home,6500,3,100,2024-03-10,1003
North,Widget,Electronics,4500,6,150,2024-06-18,1004
West,Gadget,Electronics,2000,8,250,2024-09-14,1005
""")
from chdb import datastore as pd
ds = pd.read_csv("sales.csv")
query = (ds
.filter(ds['amount'] > 1000)
.groupby('region')
.agg({'amount': ['sum', 'mean']})
.sort('sum', ascending=False)
)
# Ver el plan de ejecución
query.explain()Sintaxis
explain(verbose=False) -> NoneParámetros:
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
verbose |
bool | False |
Muestra metadatos adicionales |
Formato de salida
Salida estándar
================================================================================
plan de ejecución (in execution order)
================================================================================
[1] 📊 Data Source: file('sales.csv', 'csv')
Operations:
────────────────────────────────────────────────────────────────────────────────
️ Segment 1 [chDB] (from source): Operations 2-5
️ Note: SQL operations after Pandas ops use Python() table function
[2] 🚀 [chDB] WHERE: "amount" > 1000
[3] 🚀 [chDB] GROUP BY: region
[4] 🚀 [chDB] AGGREGATE: sum(amount), avg(amount)
[5] 🚀 [chDB] ORDER BY: sum DESC
────────────────────────────────────────────────────────────────────────────────
Final State: 📊 Pending (lazy, not yet executed)
└─> Will execute when print(), .to_df(), .execute() is called
────────────────────────────────────────────────────────────────────────────────
Generated SQL Query:
────────────────────────────────────────────────────────────────────────────────
SELECT region, SUM(amount) AS sum, AVG(amount) AS mean
FROM file('sales.csv', 'csv')
WHERE "amount" > 1000
GROUP BY region
ORDER BY sum DESC
================================================================================Leyenda de los iconos
| Icono | Significado |
|---|---|
| 📊 | Fuente de datos |
| 🚀 | Operación de chDB (SQL) |
| 🐼 | Operación de pandas |
Salida detallada
query.explain(verbose=True)El modo detallado muestra detalles adicionales de cada operación, incluida la consulta SQL completa con mecanismos internos de seguimiento del orden de las filas.
Tres fases de ejecución
La salida de EXPLAIN muestra las operaciones en tres fases:
Fase 1: Construcción de consultas SQL (diferida)
Operaciones que se compilan a SQL:
1. Source: file('sales.csv', 'CSVWithNames')
2. Filter: amount > 1000
3. GroupBy: region
4. Aggregate: sum(amount)Fase 2: Momento de ejecución
Cuando se produce un trigger:
5. Execute SQL -> DataFrame
Trigger: to_df() calledFase 3: Operaciones de DataFrame
Operaciones posteriores a la ejecución:
6. [pandas] pivot_table(...)
7. [pandas] apply(custom_func)Comprender el plan
Información de la fuente
Source: file('sales.csv', 'CSVWithNames')file()- función de tablafile()de ClickHouse'CSVWithNames'- formato de archivo con fila de encabezado
Otros tipos de origen:
Source: s3('bucket/data.parquet', ...)
Source: mysql('host', 'db', 'table', ...)
Source: __dataframe__ (pandas DataFrame input)Operaciones de filtrado
Filter: amount > 1000 AND status = 'active'Muestra la cláusula WHERE que se aplicará.
GroupBy y Aggregate
GroupBy: region, category
Aggregate: sum(amount), avg(amount), count(id)Muestra las columnas de GROUP BY y las funciones de agregación.
Operaciones de ordenación
Sort: sum DESC, region ASCMuestra la cláusula ORDER BY.
Limitar operaciones
Limit: 10
Offset: 100Muestra LIMIT y OFFSET.
Información del motor
Al usar el modo detallado, puede ver qué motor se utilizará:
Filter: amount > 1000
- Engine: chdb
- Pushdown: Yes
Apply: custom_function
- Engine: pandas
- Pushdown: NoPushdown
- Sí: La operación se ejecutará en la fuente de datos (SQL)
- No: La operación requiere ejecutarse con pandas
Ejemplos
Consulta simple
from pathlib import Path
Path("data.csv").write_text("""\
name,age,city,salary,department
Alice,25,NYC,55000,Engineering
Bob,30,LA,65000,Product
Charlie,35,NYC,80000,Engineering
Diana,28,SF,70000,Design
Eve,42,NYC,95000,Product
""")
ds = pd.read_csv("data.csv")
ds.filter(ds['age'] > 25).explain()================================================================================
Plan de ejecución (en orden de ejecución)
================================================================================
[1] 📊 Data Source: file('data.csv', 'csv')
Operaciones:
────────────────────────────────────────────────────────────────────────────────
️ Segment 1 [chDB] (desde la fuente): Operaciones 2-2
[2] 🚀 [chDB] WHERE: "age" > 25
────────────────────────────────────────────────────────────────────────────────
Consulta SQL generada:
────────────────────────────────────────────────────────────────────────────────
SELECT * FROM file('data.csv', 'csv') WHERE "age" > 25
================================================================================Agregación compleja
query = (ds
.filter(ds['date'] >= '2024-01-01')
.filter(ds['amount'] > 100)
.select('region', 'category', 'amount')
.groupby('region', 'category')
.agg({
'amount': ['sum', 'mean', 'count']
})
.sort('sum', ascending=False)
.limit(20)
)
query.explain()================================================================================
plan de ejecución (in execution order)
================================================================================
[1] 📊 Data Source: file('sales.csv', 'csv')
Operations:
────────────────────────────────────────────────────────────────────────────────
️ Segment 1 [chDB] (from source): Operations 2-8
[2] 🚀 [chDB] WHERE: "date" >= '2024-01-01'
[3] 🚀 [chDB] WHERE: "amount" > 100
[4] 🚀 [chDB] SELECT: region, category, amount
[5] 🚀 [chDB] GROUP BY: region, category
[6] 🚀 [chDB] AGGREGATE: sum(amount), avg(amount), count(amount)
[7] 🚀 [chDB] ORDER BY: sum DESC
[8] 🚀 [chDB] LIMIT: 20
────────────────────────────────────────────────────────────────────────────────
Generated SQL Query:
────────────────────────────────────────────────────────────────────────────────
SELECT region, category,
SUM(amount) AS sum,
AVG(amount) AS mean,
COUNT(amount) AS count
FROM file('sales.csv', 'csv')
WHERE "date" >= '2024-01-01' AND "amount" > 100
GROUP BY region, category
ORDER BY sum DESC
LIMIT 20
================================================================================SQL y pandas combinados
Cuando las operaciones no pueden llevarse por completo a SQL, el plan muestra varios segmentos:
query = (ds
.filter(ds['age'] > 25) # SQL
.groupby('city') # SQL
.agg({'salary': 'mean'}) # SQL
.apply(lambda x: x * 1.1) # pandas (activa la división del segmento)
.filter(ds['mean'] > 50000) # SQL (nuevo segmento)
)
query.explain()================================================================================
plan de ejecución (in execution order)
================================================================================
[1] 📊 Data Source: file('data.csv', 'csv')
Operations:
────────────────────────────────────────────────────────────────────────────────
️ Segment 1 [chDB] (from source): Operations 2-4
️ Segment 2 [Pandas] (on DataFrame): Operation 5
️ Segment 3 [chDB] (on DataFrame): Operation 6
️ Note: SQL operations after Pandas ops use Python() table function
[2] 🚀 [chDB] WHERE: "age" > 25
[3] 🚀 [chDB] GROUP BY: city
[4] 🚀 [chDB] AGGREGATE: avg(salary)
[5] 🐼 [Pandas] APPLY: lambda
[6] 🚀 [chDB] WHERE: "mean" > 50000
================================================================================Depuración con explain()
Verificar la lógica de filtrado
# Verifica que tu filtro sea correcto
query = ds.filter((ds['age'] > 25) & (ds['city'] == 'NYC'))
query.explain()
# La salida muestra: Filter: age > 25 AND city = 'NYC'Verificar la selección de columnas
# Comprobar la poda de columnas
query = ds.select('name', 'age').filter(ds['age'] > 25)
query.explain()
# La salida muestra: SELECT name, age FROM ... WHERE age > 25Comprender la agregación
# Verificar funciones de agregación
query = ds.groupby('dept').agg({'salary': ['sum', 'mean', 'std']})
query.explain()
# La salida muestra: SELECT dept, SUM(salary), AVG(salary), stddevPop(salary)Buenas prácticas
1. Verifique antes de ejecutar consultas grandes
# Siempre explicar primero para datos de gran volumen
query = ds.complex_pipeline()
query.explain() # Verificar el plan
# Si el plan es correcto
result = query.to_df() # Ejecutar2. Usa detallado para depurar
# Cuando algo parece estar mal
query.explain(verbose=True)
# Muestra la selección del motor e información de pushdown3. Comparar con to_sql()
# explain() muestra el plan
query.explain()
# to_sql() muestra solo el SQL
print(query.to_sql())
# Ambos útiles para distintos propósitos4. Comprobar el estado del pushdown
# El modo detallado muestra si las operaciones se aplican con pushdown
query.explain(verbose=True)
# Si Pushdown: No, la operación se ejecuta en pandas
# Considere reestructurar la consulta para mejorar el rendimiento