Tema 4 · 6 · Ejercicio adicional C: optimizar el lago y defender el presupuesto
Presentación del Tema 4: «Ejercicio C · Optimizar el lago y defender el presupuesto» y «Ejercicio C · paso a paso». Duración: 60 a 120 minutos. Coste: céntimos (decenas de MB, salvo la tabla de texto, que escribe unos 400 MB). Es un ejercicio opcional de ampliación.
Qué vas a hacer
Con los datos de NYC Taxi que ya tienes cargados, vas a medir cuánto lee Athena en cinco consultas habituales (la «línea base»), aplicar cuatro optimizaciones (menos columnas, filtro de partición, Parquet frente a texto, compactar), calcular cuánto ahorra cada una y traducirlo a dinero para defender un presupuesto. Terminas con dos medidas de higiene: una regla de ciclo de vida en S3 y un presupuesto en AWS Budgets.
Qué se crea en AWS: en la base demo_datalake_db, las tablas nyc_taxi_csv (texto, unos 400 MB) y viajes_compacto (Parquet compactado, unos 36 MB), con sus ficheros en athena-results/tables/; opcionalmente una regla de ciclo de vida en el bucket y un presupuesto de toda la cuenta en AWS Budgets.
Qué contiene esta carpeta
| Fichero | Para qué sirve | Paso en que se usa |
|---|---|---|
5-athena-optimizar.sql |
SQL de apoyo, la solución probada: línea base, las cuatro optimizaciones, orden de impacto y costes, higiene (ciclo de vida y presupuesto, en comentarios) y limpieza | Pasos 2 a 5 |
README.md |
Esta guía | - |
Intenta resolverlo primero por tu cuenta y usa el SQL para comprobar tus cifras. Cómo usarlo: ábrelo con cat o nano en CloudShell (o desde tu PC), copia las sentencias en el editor de Athena y ejecútalas de una en una, con el workgroup demo-athena-workgroup y la base demo_datalake_db. Este fichero no lleva comentarios detrás del ;: los valores esperados van en la línea de ENCIMA. Si añades tus propios comentarios, no los pongas detrás del ; en la misma línea (la API de Athena da MALFORMED_QUERY, Only one sql statement is allowed).
Antes de empezar
- Necesitas el Data Lake de 04.01 y los datos de NYC Taxi de 04.03 NYC Taxi (tablas
nyc_taxi_yellow_rawy compañía, con los 5 meses de 2025 por defecto). La cabecera de5-athena-optimizar.sqldice «Requiere NYC Taxi cargado (./gestionar-nyc-taxi.sh)»: ese script está en la carpeta 04.03, no en esta; si no lo ejecutaste, hazlo allí antes de seguir. - Las cifras de abajo son de los 5 meses de 2025 por defecto (2025-05 a 2025-09: 20.638.874 viajes en la raw). Con otros meses salen cifras distintas, pero las relaciones (3,1 veces más, 4,9 veces menos, 11,5 veces...) se mantienen.
- Cómo leer Data scanned: 04.02.
Cómo llevar los ficheros a CloudShell
- En tu PC, comprime esta carpeta (
04.06-optimizarpresupuesto) en un zip y no la descomprimas. - En CloudShell (región
eu-north-1): Actions > Upload file >04.06-optimizarpresupuesto.zip. - Descomprime y entra:
unzip -o 04.06-optimizarpresupuesto.zip && cd 04.06-optimizarpresupuesto && chmod -R u+rwX . && chmod +x *.sh 2>/dev/null; ls
Si ya subiste
g214-materiales.zip(README principal), no necesitas este zip: entra concd ~/g214-materiales/tema4/04.06-optimizarpresupuestoy, si algún fichero daPermission denied, ejecuta allíchmod -R u+rwX . && chmod +x *.sh.
(Esta carpeta no tiene scripts .sh: el chmod no hace nada. El SQL se pega en Athena y los comandos de higiene se ejecutan en CloudShell.)
Paso a paso
Paso 1 · Averigua tu bucket
BUCKET=$(aws cloudformation describe-stacks --stack-name g214-datalake-demo --region eu-north-1 \
--query "Stacks[0].Outputs[?OutputKey=='S3Bucket'].OutputValue" --output text)
echo "$BUCKET"
Paso 2 · Línea base
Mide con agregados (SUM), no con LIMIT: con LIMIT 100 Athena lee en paralelo y corta cuando quiere, las cifras no son estables y el «filtro de partición» puede salir leyendo más que la consulta sin filtro. Tampoco sirve COUNT(*): sobre Parquet lee solo metadatos (0 B). Coste = max(bytes, 10 MB) x 5 USD por TB.
Ejecuta las cinco consultas habituales del apartado 1 del SQL y anota el Data scanned de cada una. Qué verás: SELECT * LIMIT 100 2.567.885 B (la primera vez; LIMIT no da cifras estables); COUNT(*) 0 B; AVG(tip_amount) con payment_type = 1 20.803.771 B; GROUP BY pulocationid 16.383.473 B; SUM(total_amount) por mes 35.482.600 B.
Paso 3 · Las cuatro optimizaciones
Mide antes de tocar nada: sin la línea base no hay ahorro que demostrar. Una optimización cada vez (apartados 2 a 5 del SQL). Qué verás:
| Optimización | Antes | Después |
|---|---|---|
| 1 · solo las columnas necesarias | 4 columnas: 108.875.095 B | 1 columna: 35.482.600 B (3,1 veces más con 4 columnas) |
| 2 · filtro de partición (1 mes de 5) | 35.482.600 B | 7.274.878 B (4,9 veces menos) |
3 · Parquet frente a texto (nyc_taxi_csv, TEXTFILE comprimido en gzip) |
texto: unos 407 MB (406.947.430 y 407.013.111 B en dos medidas) | Parquet: 35,5 MB (11,5 veces menos) |
4 · compactar (viajes_compacto) |
35,5 MB | unos 36,5 MB (36.377.849 y 36.561.656 B en dos medidas): sin ahorro apreciable (entre un 2 y un 3 % más) porque los ficheros mensuales ya son grandes (de 60 a 75 MB) |
Paso 4 · Orden de impacto y coste
Ahorro de cada medida, de mayor a menor: Parquet frente a texto 91 %; filtro de partición 79 %; una columna frente a cuatro 67 %; compactar entre -2 y -3 %. Las cifras exactas varían algo de una ejecución a otra: valen las relaciones.
Coste a 100 consultas al día durante 30 días (3.000 consultas al mes; 5 USD/TB, mínimo 10 MB): texto 0,0020 USD por consulta (6,10 USD al mes); Parquet sin filtro 0,00018 USD (0,53 USD al mes); con filtro de partición, que lee 7,3 MB y factura el mínimo de 10 MB, 0,00005 USD (0,15 USD al mes). Estos costes usan el TB decimal (10^12 bytes); con el TB binario de la presentación (1.099.511.627.776 bytes) salen un 9 % menos (por ejemplo, 5,55 USD al mes en el texto).
Alternativa a copiar los valores de Recent queries: el historial de Data scanned por CLI.
for id in $(aws athena list-query-executions --work-group demo-athena-workgroup --region eu-north-1 \
--no-paginate --max-results 20 --query 'QueryExecutionIds' --output text); do
aws athena get-query-execution --query-execution-id "$id" --region eu-north-1 \
--query 'QueryExecution.[QueryExecutionId,Statistics.DataScannedInBytes,Statistics.TotalExecutionTimeInMillis]' --output text
done
Qué verás: una línea por consulta con su identificador, los bytes escaneados y los milisegundos.
Paso 5 · Higiene (opcional)
Higiene 1 · caducar resultados de Athena, con cuidado. Los ficheros de tus tablas CTAS (titanic_parquet, nyc_taxi_yellow_curated, nyc_taxi_csv, viajes_compacto, aire_curated...) están dentro de athena-results/tables/<id>/. Una regla de ciclo de vida de 7 días sobre todo athena-results/ los borraría y esas tablas devolverían 0 filas sin dar ningún error. Aplica la regla solo al prefijo athena-results/Unsaved/ (resultados de las consultas lanzadas desde la consola). Son dos reglas, no una: «Expire current versions» (7 días) y «Delete expired object delete markers» no se pueden combinar en la misma regla (por API da MalformedXML; en la consola las dos casillas se excluyen). Por consola: S3 > tu bucket > Management > Create lifecycle rule, con ese prefijo; en la primera regla marca «Expire current versions» a 7 días y, porque el bucket tiene versionado, «Permanently delete noncurrent versions» a 1 día; crea una segunda regla, con el mismo prefijo, que solo tenga «Delete expired object delete markers». Los resultados de consultas lanzadas desde scripts o CLI están en athena-results/<id>.csv (más su .metadata), no en Unsaved/: esa regla no los cubre; bórralos a mano cuando quieras con aws s3 rm "s3://$BUCKET/athena-results/" --recursive --exclude "tables/*" (el filtro deja intactas las tablas: probado, borra los resultados sueltos y las tablas CTAS siguen dando filas). Por CLI, guarda esto como ciclo-vida.json (cada regla lleva su Filter; la primera lleva NoncurrentVersionExpiration y la segunda solo ExpiredObjectDeleteMarker):
{
"Rules": [
{ "ID": "caducar-resultados-athena", "Status": "Enabled",
"Filter": { "Prefix": "athena-results/Unsaved/" },
"Expiration": { "Days": 7 },
"NoncurrentVersionExpiration": { "NoncurrentDays": 1 } },
{ "ID": "limpiar-marcadores-athena", "Status": "Enabled",
"Filter": { "Prefix": "athena-results/Unsaved/" },
"Expiration": { "ExpiredObjectDeleteMarker": true } }
]
}
aws s3api put-bucket-lifecycle-configuration --bucket "$BUCKET" \
--lifecycle-configuration file://ciclo-vida.json --region eu-north-1
aws s3api get-bucket-lifecycle-configuration --bucket "$BUCKET" --region eu-north-1
La primera orden sustituye todas las reglas de ciclo de vida del bucket: el bucket del stack no trae ninguna, así que aquí no pierdes nada. (La primera regla se probó por API; la segunda sigue la documentación de put-bucket-lifecycle-configuration: una regla con ExpiredObjectDeleteMarker no puede llevar Days.)
Higiene 2 · presupuesto. Billing and Cost Management > Budgets > Create budget > Cost budget (mensual), por ejemplo 10 USD, con alerta al 80 % por correo. Es un presupuesto de toda la cuenta (la alerta manda un correo real): bórralo al terminar si no lo quieres; si la consola no te deja, por CLI: aws budgets delete-budget --account-id "$(aws sts get-caller-identity --query Account --output text)" --budget-name <nombre-del-presupuesto> (la región del servicio Budgets es global; el nombre lo ves con aws budgets describe-budgets --account-id <id>).
Errores frecuentes
| Qué ves | Causa | Solución |
|---|---|---|
TABLE_NOT_FOUND con nyc_taxi_yellow_raw |
No cargaste NYC Taxi | Haz 04.03 |
| Las cifras no se parecen a las de arriba | Cargaste otros meses o mides con LIMIT/COUNT(*) |
Mide con SUM; compara relaciones, no valores absolutos |
| El «filtro de partición» lee más que la consulta sin filtro | Mediste con LIMIT |
Usa agregados (SUM) |
MalformedXML al aplicar la regla de ciclo de vida |
Se combinó «Expire current versions» con «Delete expired object delete markers» en la misma regla, o falta el Filter |
Dos reglas, cada una con su Filter (paso 5, Higiene 1) |
Una tabla CTAS (titanic_parquet, aire_curated...) devuelve 0 filas sin error |
Una regla de ciclo de vida borró athena-results/tables/ |
Aplica la regla solo a athena-results/Unsaved/ y recrea la tabla |
MALFORMED_QUERY / Only one sql statement is allowed |
Hay un comentario -- ... detrás de un ; en la misma línea |
Pon el comentario en la línea de encima o bórralo; ejecuta de una en una |
Limpieza
Solo lo de esta actividad, en este orden (el stack NO se borra aquí: se borra al final del Tema 4 desde 04.01, y debe ser lo último):
- En Athena:
DROP TABLE nyc_taxi_csv;yDROP TABLE viajes_compacto;. Para encontrar el<id>de sus ficheros:SHOW CREATE TABLE demo_datalake_db.nyc_taxi_csv;. - Borra sus ficheros de
athena-results/tables/<id>/(la CTAS de texto escribe unos 400 MB con 5 meses;DROP TABLEno borra los ficheros), o borra el stack completo desde 04.01. - Si creaste un presupuesto en AWS Budgets solo para este ejercicio y no lo quieres, bórralo (es de toda la cuenta).
- Borra
ciclo-vida.jsonde CloudShell si lo creaste:rm -f ciclo-vida.json.
Cómo sabes que has terminado
- [ ] Tienes tu línea base de las cinco consultas con su Data scanned.
- [ ] Has medido las cuatro optimizaciones y tus relaciones se parecen a 3,1 / 4,9 / 11,5 / sin ahorro.
- [ ] Sabes ordenar las medidas por ahorro (Parquet 91 %, partición 79 %, columnas 67 %, compactar -2 a -3 %) y calcular el coste mensual (6,10 / 0,53 / 0,15 USD).
- [ ] Sabes por qué no se debe aplicar una regla de ciclo de vida a todo
athena-results/. - [ ] (Si es el último ejercicio) Vuelve a 04.01 para la limpieza final y borra el stack.
Anterior: 04.05 Euribor e IPC · Siguiente: 04.07 Panel Streamlit y seguridad