lección 9
Encontrar la tabla correcta y saber cuánto cuesta tu consulta
Navegar un almacén con cientos de tablas, verificar que la tabla es la correcta, y entender por que en la nube cada SELECT tiene un precio.
⏱ 50 min
Tu primer día como analista en una empresa con un almacén de datos real se parece mucho a llegar a una biblioteca enorme sin catálogo visible. Sabes que la respuesta esta ahi dentro, pero hay 400 tablas con nombres que nadie te ha explicado. Algunas se llaman stg_payments_v2_old. Otras, fact_revenue_daily_backup_DO_NOT_USE. Y las que parecen buenas tienen 87 columnas sin documentar. Este es el momento en el que te preguntas: ¿como encuentro la tabla correcta?
Y hay una segunda pregunta que en la universidad nadie te cuenta: en la nube, cada consulta cuesta dinero. No es una metáfora. Literalmente, cada vez que escribes SELECT y pulsas ejecutar, la plataforma mide cuántos datos ha tenido que leer y te pasa la factura. Se han visto facturas de cientos de miles de dólares por un error humano. Así que no basta con encontrar la tabla: hay que saber preguntar sin arruinar el presupuesto del equipo.
Esta lección tiene dos partes bien diferenciadas. La primera es una estrategia de exploracion: como orientarte en un almacén desconocido y llegar a la tabla correcta en minutos, no en días. La segunda es una lección de economia: como funciona la facturación en la nube y que practicas convierten una consulta cara en una barata. Las dos se necesitan mutuamente, porque de nada sirve encontrar la tabla perfecta si luego la consultas de una forma que escanea todo el historico de cinco anos.
### Parte 1: encontrar la tabla correcta
Antes de existir los almacenes de datos en la nube, la información vivia en hojas de calculo repartidas por los ordenadores (computadoras) de cada departamento. Si necesitabas un dato, preguntabas a la persona correcta. Eso funcionaba cuando habia veinte empleados y tres hojas. Pero cuando una empresa crece, el número de tablas crece más rápido que el número de personas que las entienden. Es habitual encontrar almacenes con 300, 500 o incluso 2.000 tablas. Y no todas están bien nombradas ni documentadas.
La buena noticia: hay un sistema. Todos los almacenes modernos (BigQuery, Snowflake, Databricks, Redshift, y también DuckDB en tu portátil) exponen metadatos, es decir, datos sobre los propios datos. Esos metadatos te dicen qué tablas existen, qué columnas tienen, cuántas filas ocupan, cuando se actualizaron por última vez. Y se consultan con SQL, el mismo lenguaje que ya conoces.
### La estrategia de búsqueda: de lo general a lo concreto
### Paso 1: empieza por el esquema correcto
La mayoría de almacenes organizan sus tablas en capas, como los pisos de un edificio. Cada capa tiene un proposito. Los nombres más habituales son: raw o staging (los datos tal cual llegan de la fuente, sin limpiar), intermediate o transform (datos ya transformados pero no listos para consumo), y gold, analytics, marts o reporting (los datos preparados para que los consulte un analista o un dashboard). Tu, como analista, casi siempre empiezas por la capa gold o analytics. Es donde viven las tablas de hechos y dimensiones limpias, con nombres legibles y grano documentado.
Si no sabes cómo se llaman las capas en tu empresa, el primer comando es listar los esquemas disponibles. Un esquema (schema en inglés) es un contenedor lógico dentro de una base de datos, como una carpeta dentro de un disco duro. Cada esquema agrupa tablas relacionadas.
1-- Listar todos los esquemas de la base de datos2-- Funciona en la mayoría de almacenes que siguen el estandar SQL3SELECT schema_name4FROM information_schema.schemata5ORDER BY schema_name;67-- Resultado tipico en un almacén bien organizado:8-- | schema_name |9-- |-----------------|10-- | analytics | <-- aqui empiezas11-- | intermediate |12-- | raw_crm |13-- | raw_payments |14-- | staging |
INFORMATION_SCHEMA es un estandar SQL: existe en PostgreSQL, BigQuery, Snowflake, Redshift y DuckDB.
### Paso 2: busca por nombre con prefijos
Una vez dentro del esquema de consumo, necesitas ver que tablas hay. Si el equipo de ingeniería de datos ha hecho bien su trabajo, las tablas de hechos empezaran por fact_ y las dimensiones por dim_. Si buscas las ventas, fact_sales o fact_orders son candidatas inmediatas. Si buscas información de clientes, dim_customer o dim_client. Pero no siempre es tan limpio: a veces las tablas se llaman orders, revenue_daily, o report_marketing_q3. En esos casos, el nombre es tu primera pista, no tu respuesta definitiva.
1-- Listar todas las tablas de un esquema concreto2SELECT table_name, table_type3FROM information_schema.tables4WHERE table_schema = 'analytics'5ORDER BY table_name;67-- Si buscas algo relacionado con ventas:8SELECT table_name9FROM information_schema.tables10WHERE table_schema = 'analytics'11 AND table_name LIKE '%sales%'12ORDER BY table_name;1314-- Resultado:15-- | table_name |16-- |-----------------------|17-- | fact_sales |18-- | fact_sales_returns |19-- | agg_daily_sales |
INFORMATION_SCHEMA.TABLES te da el inventario completo. El LIKE filtra por patron cuando hay cientos de tablas.
Consejo de senior: cuando llegas a un almacén nuevo, lo primero que hago es sacar la lista completa de tablas del esquema de consumo y pegarla en un documento. Solo los nombres, sin más. Los leo como si fueran un indice de libro. En cinco minutos ya se que dominios cubre (ventas, clientes, producto, logistica) y cuales faltan. Ese documento luego lo voy anotando a mano conforme descubro que hace cada tabla. En tres semanas tienes un diccionario de datos casero que vale oro para el siguiente que llegue.
### Paso 3: mira las columnas con DESCRIBE o INFORMATION_SCHEMA
Ya tienes una tabla candidata. Antes de consultarla, mira qué columnas tiene. Esto te dice dos cosas: si la tabla contiene los campos que necesitas para responder tu pregunta, y qué tipo de datos guarda cada columna (un VARCHAR no es lo mismo que un INTEGER a la hora de filtrar o agregar). Hay dos formas estándar de hacerlo.
1-- Opcion A: DESCRIBE (sintaxis corta, funciona en DuckDB, MySQL, Snowflake)2DESCRIBE analytics.fact_sales;34-- Opcion B: INFORMATION_SCHEMA (estandar SQL, funciona en todas partes)5SELECT column_name, data_type, is_nullable6FROM information_schema.columns7WHERE table_schema = 'analytics'8 AND table_name = 'fact_sales'9ORDER BY ordinal_position;1011-- Resultado:12-- | column_name | data_type | is_nullable |13-- |---------------|-----------|-------------|14-- | sale_id | BIGINT | NO |15-- | date_key | INTEGER | NO |16-- | customer_key | INTEGER | NO |17-- | product_key | INTEGER | NO |18-- | store_key | INTEGER | YES |19-- | quantity | INTEGER | NO |20-- | net_amount | DECIMAL | NO |21-- | discount_pct | DECIMAL | YES |
DESCRIBE es rápido para una mirada inicial. INFORMATION_SCHEMA te da más detalle y se puede filtrar con WHERE.
Fíjate en los nombres de las columnas que terminan en _key: son claves foraneas que apuntan a dimensiones. Si ves customer_key, sabes que hay una dim_customer en algun sitio. Si ves date_key, hay una dim_date. Eso ya te esta contando la historia del modelo sin que nadie te lo explique. Y las columnas numericas sin sufijo _key (quantity, net_amount, discount_pct) son las métricas, los hechos medibles.
### Paso 4: verifica el grano con COUNT vs COUNT DISTINCT
Ya sabes qué columnas tiene la tabla. Pero antes de confiar en ella, necesitas confirmar su granularidad. Recuerda: el grano es lo que representa cada fila. Si asumes que cada fila es un pedido pero en realidad es una línea de pedido, tus sumas van a salir multiplicadas. El truco más rápido para verificar el grano es comparar el número total de filas con el número de valores distintos de la columna que crees que es la clave primaria.
1-- Verificar el grano: ¿es una fila por venta (sale_id)?2SELECT3 COUNT(*) AS total_filas,4 COUNT(DISTINCT sale_id) AS sale_ids_unicos5FROM analytics.fact_sales;67-- Si ambos coinciden: el grano es una fila por sale_id. Perfecto.8-- | total_filas | sale_ids_unicos |9-- |-------------|-----------------|10-- | 2.847.391 | 2.847.391 | <-- coinciden: sale_id es PK1112-- ¿Y si sospecho que el grano es más fino (linea de pedido)?13SELECT14 COUNT(*) AS total_filas,15 COUNT(DISTINCT order_id) AS pedidos_unicos16FROM analytics.fact_sales;1718-- | total_filas | pedidos_unicos |19-- |-------------|----------------|20-- | 2.847.391 | 1.203.456 | <-- no coinciden: hay ~2.4 lineas por pedido
Si COUNT(*) y COUNT(DISTINCT pk) coinciden, esa columna identifica cada fila de forma unica y has encontrado el grano.
Nunca asumas el grano por el nombre de la tabla. He visto tablas llamadas fact_orders donde cada fila era una linea de pedido, y tablas llamadas order_lines donde habian colapsado todo a un pedido por fila. El unico juez es el dato: COUNT(*) vs COUNT(DISTINCT). Dos minutos que te ahorran una semana de números falsos.
### Paso 5: confirma que la tabla está fresca
Encontraste la tabla, tiene las columnas correctas y el grano es el esperado. Falta un paso: confirmar que se actualiza. Un almacén no es una foto instantanea: es un proceso que se ejecuta periodicamente (cada hora, cada día, cada semana). Si la tabla se actualizo por última vez hace tres meses, puede que haya un pipeline roto y los datos esten obsoletos. Tu informe diria la verdad de marzo, no la de hoy.
1-- Comprobar la fecha más reciente en una tabla de hechos2SELECT3 MAX(order_date) AS ultima_fecha_dato,4 COUNT(*) FILTER (WHERE order_date >= CURRENT_DATE - INTERVAL '7 days') AS filas_ultima_semana5FROM analytics.fact_sales;67-- Si hoy es 15 de julio y ultima_fecha_dato es 14 de julio, la tabla se8-- actualizo ayer. Si es 3 de mayo, algo esta roto.910-- En BigQuery puedes ver los metadatos de actualizacion directamente:11-- SELECT * FROM region-eu.INFORMATION_SCHEMA.TABLE_STORAGE12-- WHERE table_name = 'fact_sales'13-- (te da last_modified_time, total_rows, total_logical_bytes)
Comprobar la frescura es el último paso antes de confiar en una tabla. Si el dato no es de ayer, pregunta al ingeniero.
### Cuando no hay documentación: la investigacion humana
El escenario ideal es que tu empresa tenga un catálogo de datos (herramientas como DataHub, Alation, Atlan o el propio catálogo integrado de Snowflake o BigQuery). En ese catálogo buscas por palabra clave y te aparece una ficha con la descripcion de cada tabla, quien es su responsable, cuando se actualiza y de donde vienen los datos. Pero seamos realistas: la mayoría de empresas, especialmente las que contratan a su primer analista, no tienen eso. Asi que necesitas una estrategia B.
- 01.Pregunta al data engineer o al analista senior. Es la vía más rápida. No preguntes "que tablas hay" (demasiado abierto). Pregunta algo concreto: "Necesito las ventas diarias por producto, desglosadas por tienda. ¿Que tabla uso y que columna tiene el importe neto?". Una pregunta concreta recibe una respuesta útil.
- 02.Mira los dashboards existentes. Si la empresa tiene dashboards en produccion, detras de cada grafico hay una consulta SQL. Esa consulta te dice que tablas usa, que filtros aplica y como calcula las métricas. Es ingeniería inversa: si el dashboard muestra el revenue mensual, la tabla que lo alimenta tiene los datos de revenue.
- 03.Busca en la herramienta de BI o en el repositorio de consultas. Muchas empresas guardan las queries en un repositorio de Git, en Looker o en Mode. Buscar por palabra clave ahi es como buscar en Google, pero para datos internos.
- 04.Lee el código del pipeline ETL si tienes acceso. Los ficheros de dbt (modelos .sql) o los DAGs de orquestacion te cuentan de donde viene cada tabla y que transformaciones aplica. Es la documentación más fiable, porque si miente, el pipeline no funciona.
Consejo de senior: la ingeniería inversa de dashboards es mi técnica favorita cuando llego a una empresa nueva. Abro los tres dashboards más usados (el de ventas, el de producto y el de finanzas), miro que SQL hay detras, y en una hora tengo un mapa mental de las 10-15 tablas que importan. El 80% de las preguntas de negocio se responde con el 20% de las tablas. Encuentra esas 10-15 y ya tienes tu base.
### Parte 2: cuánto cuesta tu consulta
En tu portátil, con DuckDB o con una base de datos local, ejecutar una consulta cuesta cero (aparte de la electricidad). Pero en la nube, cada consulta tiene un precio. El motivo es sencillo: cuando ejecutas un SELECT en BigQuery o Snowflake, la plataforma enciende decenas o cientos de maquinas durante unos segundos para leer tus datos en paralelo. Esas maquinas consumen CPU, memoria y ancho de banda, y eso se factura.
El modelo de facturación varía segun la plataforma, pero se reduce a dos familias:
- Pago por bytes escaneados: BigQuery. Cada consulta mide cuántos bytes ha tenido que leer del almacenamiento para ejecutarse. A enero de 2025, el precio es de 6,25 dolares por terabyte escaneado. Si tu consulta lee 100 GB, cuesta 0,63 dolares. Si lee 10 TB porque hiciste un SELECT * de toda la historia, cuesta 62,50 dolares. Por una sola consulta.
- Pago por tiempo de computacion (creditos): Snowflake y Databricks. Enciendes un "almacén virtual" (warehouse) con una potencia determinada, y pagas por cada segundo que esta encendido procesando tu consulta. Un warehouse XS cuesta ~2 dolares por hora. Uno 4XL, ~128 dolares por hora. Cuanto más grande, más rápido termina, pero más caro el segundo.
### La consulta de cientos de miles de dólares: una historia real
Se han visto facturas de cientos de miles de dólares por un error así. El mecanismo: un ingeniero ejecuta un SELECT * FROM events sin filtro de fecha contra una tabla de eventos de clickstream que acumula años de datos. La tabla pesa 160 terabytes. A 6,25 dólares por terabyte, esa consulta cobra unos 1.000 dólares. Pero no la ejecutó una vez: la puso dentro de un pipeline automatizado que corría cada hora. Cuando alguien se dio cuenta cinco semanas después, la factura de BigQuery superaba los 800.000 dólares. En la nube, un error de principiante escala a velocidad de máquina.
No hace falta llegar a ese extremo. He visto equipos de analistas que generaban facturas de 15.000 dólares al mes cuando podrían haber sido 1.500, simplemente porque nadie les enseñó a seleccionar solo las columnas que necesitan y a filtrar por fecha antes de hacer un JOIN. La diferencia entre un analista junior y uno que lleva un año es que el segundo mira el estimador de coste antes de darle a ejecutar.
### Estimar el coste ANTES de ejecutar
Todas las plataformas te ofrecen una forma de saber cuánto va a costar una consulta sin ejecutarla. Es como pedir presupuesto antes de encargar la obra. En BigQuery es un DRY RUN. En Snowflake y otros, es EXPLAIN. En DuckDB también existe EXPLAIN, y aunque no hay factura, te ensena a leer un plan de ejecucion.
1-- BigQuery: estimacion de bytes (se puede hacer desde la interfaz2-- o con la opcion --dry_run en bq CLI)3-- La interfaz web de BigQuery muestra arriba a la derecha:4-- "This query will process 2.4 GB when run"5-- antes de que pulses Ejecutar.67-- DuckDB: ver el plan de ejecucion sin ejecutar la consulta8EXPLAIN9SELECT customer_key, SUM(net_amount) AS total10FROM fact_sales11WHERE order_date >= '2024-01-01'12GROUP BY customer_key;1314-- El plan te muestra cuántas filas estima leer, que filtros aplica,15-- y en que orden procesa los pasos. No cuesta dinero.
Siempre mira el estimador antes de ejecutar. En BigQuery lo tienes en la esquina superior derecha de la consola.
### Las tres reglas de oro para no arruinarte
### Regla 1: nunca SELECT *, siempre nombra tus columnas
Los almacenes de datos usan formato columnar (lo viste en Parquet). Esto significa que cada columna se almacena por separado en disco. Cuando pides SELECT *, la plataforma lee TODAS las columnas, incluso las 77 que no necesitas. Si tu tabla tiene 80 columnas y tú solo necesitas 3, estás pagando por leer 77 columnas de más. En una tabla de 10 TB con 80 columnas, leer solo 3 te cuesta unos 2,34 dólares en vez de 62,50: el 96 % menos, por escribir tres nombres en vez de un asterisco.
1-- MAL: lee las 80 columnas de la tabla (10 TB)2-- Coste estimado en BigQuery: ~$62.503SELECT *4FROM analytics.fact_events5WHERE event_date >= '2024-01-01';67-- BIEN: lee solo las 3 columnas que necesitas (~375 GB)8-- Coste estimado en BigQuery: ~$2.349SELECT user_id, event_name, event_timestamp10FROM analytics.fact_events11WHERE event_date >= '2024-01-01';1213-- Ahorro: 96% del coste por consulta
SELECT * es la forma más cara de explorar una tabla. Nombrar columnas es la optimizacion más sencilla y más efectiva.
### Regla 2: filtra SIEMPRE por la columna de partición
Las tablas grandes en la nube están particionadas, es decir, divididas en trozos por una columna (casi siempre la fecha). Cuando filtras por esa columna, la plataforma solo lee los trozos que encajan con tu filtro. Si tu tabla tiene 5 anos de datos particionados por día y filtras WHERE date >= "2024-06-01", solo lee 6 meses en vez de 5 anos. Eso es leer un 10% del total. Si no filtras, lee el 100%.
La analogía: imagina una estantería con 60 cajones, uno por mes. Si buscas las facturas de junio, abres un cajon. Si no dices que mes, el sistema abre los 60 y mira dentro de todos. El coste del contable es el mismo por cajon: cuántos menos abras, menos pagas.
En BigQuery, LIMIT no reduce el coste. Esto sorprende a todo el mundo. SELECT * FROM tabla LIMIT 10 escanea TODA la tabla y luego te devuelve solo 10 filas. El escaneo completo ya se ha facturado. LIMIT es útil para ver la forma del dato sin desbordar tu pantalla, pero no para ahorrar dinero. Lo que ahorra dinero es filtrar por la partición y seleccionar solo tus columnas.
### Regla 3: usa LIMIT para explorar, no para ahorrar
Cuando estas investigando una tabla nueva y quieres ver cómo son los datos (que pinta tienen los valores, si hay nulos, que formato tienen las fechas), LIMIT 100 es tu amigo. Te da una muestra sin abrumar tu pantalla. Pero recuerda: en BigQuery ya has pagado el escaneo completo. En Snowflake, el warehouse se apaga más rápido porque procesa menos filas, así que si tiene un efecto en coste. La distincion importa segun donde trabajes.
### Particionado: la infraestructura que no ves pero que decide tu factura
No eres tu quien decide como se particiona una tabla (eso lo hace el ingeniero de datos), pero si necesitas saber POR QUE columna esta particionada. Porque si filtras por una columna que no es la de partición, el sistema no puede saltarse trozos y lee todo igualmente. Es como tener una estantería ordenada por mes pero buscar por nombre de cliente: tienes que abrir todos los cajones.
1-- En BigQuery: ver por que columna esta particionada una tabla2SELECT table_name, partition_column, partition_type3FROM `project.dataset.INFORMATION_SCHEMA.PARTITIONS`4WHERE table_name = 'fact_events';56-- En Snowflake: ver el clustering (equivalente funcional)7SHOW TABLES LIKE 'fact_events';8-- La columna "cluster_by" te dice la clave de clustering910-- La regla: tu WHERE debe incluir SIEMPRE la columna de partición.11-- Si la tabla esta particionada por event_date, tu consulta lleva:12WHERE event_date >= '2024-01-01' AND event_date < '2024-07-01'13-- Asi el motor salta 4.5 anos de datos y solo lee 6 meses.
Conocer la columna de partición es saber donde esta el interruptor del ahorro.
### Juntando las dos partes: el flujo completo
Consejo de senior: en mis primeros meses en BigQuery, ponia un alias en mi .bashrc que ejecutaba toda consulta en DRY RUN primero. Si superaba 50 GB, me preguntaba si queria continuar. Era excesivo, pero me salvo de dos sustos. Hoy lo que hago es más sencillo: antes de ejecutar cualquier consulta sobre una tabla que no conozco, hago un DESCRIBE y un SELECT de 5 filas filtrado por la fecha más reciente. Esos dos comandos cuestan centimos y me dan el contexto para escribir la consulta final bien a la primera.
### Resumen: tu checklist antes de consultar
- 01.Identifica el esquema de consumo (gold, analytics, marts).
- 02.Busca la tabla por nombre usando INFORMATION_SCHEMA o SHOW TABLES.
- 03.Mira sus columnas con DESCRIBE o INFORMATION_SCHEMA.COLUMNS.
- 04.Verifica el grano: COUNT(*) vs COUNT(DISTINCT clave).
- 05.Confirma que la tabla está fresca: MAX(fecha) cercano a hoy.
- 06.Antes de ejecutar, mira el estimador de coste (DRY RUN o EXPLAIN).
- 07.Selecciona SOLO las columnas que necesitas (nunca SELECT *).
- 08.Filtra SIEMPRE por la columna de partición (casi siempre la fecha).
Regístrate para guardar tu progreso.
## comentarios
Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.
Inicia sesión para comentar y responder.
cargando comentarios...