[{"content":"El mensaje en el canal de Slack del equipo de infraestructura era de esos que te hacen levantar la cabeza de la pantalla: \u0026ldquo;Disco al 95% en el db de producción. ¿Alguien puede mirar?\u0026rdquo;\nEl servidor era un MySQL 8.0 sobre Rocky Linux, un sistema de gestión usado por un centenar de usuarios. La base de datos en sí ocupaba unos 40 GB — nada extraordinario. Pero en el directorio de datos había 180 GB de binary logs. Seis meses de binlog que nadie había pensado en gestionar.\nNo es la primera vez que veo este escenario. De hecho, diría que es uno de los patrones más recurrentes en los tickets que me llegan. El binary log es una de esas funcionalidades de MySQL que trabajan en silencio, sin pedir nada — hasta que el disco se llena.\nQué son los binary log, en la práctica #El binary log es un registro secuencial de todos los eventos que modifican datos en la base de datos. Cada INSERT, UPDATE, DELETE, cada DDL — todo se escribe en archivos binarios numerados progresivamente: mysql-bin.000001, mysql-bin.000002 y así sucesivamente.\nEl nombre engaña un poco. No es un \u0026ldquo;log\u0026rdquo; en el sentido del syslog o del error log — no está hecho para ser leído por un humano. Es un flujo binario estructurado que MySQL usa internamente para dos propósitos fundamentales:\nReplicación: el slave lee los binlog del master para replicar las mismas operaciones Point-in-time recovery (PITR) : después de restaurar un backup, puedes \u0026ldquo;reaplicar\u0026rdquo; los binlog para llevar los datos hasta un momento preciso Sin el binary log, no puedes hacer ni una cosa ni la otra. Esta es la razón por la que el primer instinto — \u0026ldquo;desactivemos los binlog para que no llenen el disco\u0026rdquo; — es casi siempre equivocado.\nCómo genera MySQL los binlog #El binary logging se activa con el parámetro log_bin. Desde MySQL 8.0 está habilitado por defecto — un cambio importante respecto a versiones anteriores donde había que activarlo explícitamente.\n[mysqld] log_bin = /var/lib/mysql/mysql-bin server-id = 1 MySQL crea un nuevo archivo binlog en varias circunstancias:\nCuando el servidor se inicia o reinicia Cuando el archivo actual alcanza el tamaño definido por max_binlog_size (por defecto: 1 GB) Cuando ejecutas FLUSH BINARY LOGS Cuando ocurre una rotación manual Cada archivo binlog tiene un archivo índice asociado (mysql-bin.index) que registra todos los archivos binlog activos. Este archivo es crítico: si lo corrompes o lo modificas a mano, MySQL ya no sabe qué binlogs existen.\nSHOW BINARY LOGS; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000147 | 1073741824| | mysql-bin.000148 | 1073741824| | mysql-bin.000149 | 1073741824| | ... | | | mysql-bin.000318 | 524288000| +------------------+-----------+ 172 rows in set Ciento setenta y dos archivos. Cada uno de aproximadamente un gigabyte. La cuenta cuadra: 180 GB de binlog nunca purgados.\nEl papel en la replicación #En una arquitectura master-slave, el binary log es el mecanismo de transporte de datos. El flujo es este:\nEl master escribe cada transacción en el binlog El slave tiene un hilo (I/O thread) que se conecta al master y lee los binlog El slave escribe lo que recibe en su propio relay log Un segundo hilo (SQL thread) en el slave ejecuta los eventos del relay log Esto significa que los binlog en el master deben permanecer disponibles hasta que todos los slaves los hayan leído. Si borras un binlog que el slave no ha consumido todavía, la replicación se rompe.\nAntes de tocar cualquier binlog en un master, el comando a ejecutar es:\nSHOW REPLICA STATUS\\G -- o, en versiones más antiguas: SHOW SLAVE STATUS\\G El campo que interesa es Relay_Master_Log_File (o Source_Log_File en versiones recientes): te dice qué binlog está leyendo el slave en ese momento. Todos los archivos anteriores a ese son seguros para eliminar.\nPoint-in-time recovery: la otra razón por la que los binlog existen #El segundo uso — a menudo subestimado — es el point-in-time recovery. El escenario es este: tienes un backup hecho a las 3 de la madrugada. A las 14:30 alguien ejecuta un DROP TABLE equivocado. Sin binlog, puedes restaurar el backup y pierdes todo lo que pasó entre las 3:00 y las 14:30. Con los binlog, haces el restore y luego reaplicas los binlog hasta las 14:29.\n# Encontrar el evento del DROP TABLE mysqlbinlog --start-datetime=\u0026#34;2026-03-30 14:00:00\u0026#34; \\ --stop-datetime=\u0026#34;2026-03-30 15:00:00\u0026#34; \\ /var/lib/mysql/mysql-bin.000318 | grep -i \u0026#34;DROP\u0026#34; # Reaplicar los binlog hasta el momento antes del desastre mysqlbinlog --stop-datetime=\u0026#34;2026-03-30 14:29:00\u0026#34; \\ /var/lib/mysql/mysql-bin.000310 \\ /var/lib/mysql/mysql-bin.000311 \\ ... \\ /var/lib/mysql/mysql-bin.000318 | mysql -u root -p En la práctica, los binlog son tu póliza de seguros. El backup es la base, los binlog cubren el delta. Borrar los binlog sin un backup reciente es como cancelar el seguro el día antes de una tormenta.\nPURGE BINARY LOGS: la forma correcta de limpiar #Volvamos a nuestro servidor con el disco al 95%. La tentación de hacer un rm -f mysql-bin.* es fuerte. Pero es equivocada, por dos razones:\nMySQL no sabe que has borrado los archivos — el archivo índice sigue apuntando a binlogs que ya no existen Si hay una réplica activa, arriesgas romper la sincronización La forma correcta es el comando PURGE:\n-- Eliminar todos los binlog anteriores a un archivo específico PURGE BINARY LOGS TO \u0026#39;mysql-bin.000300\u0026#39;; -- O eliminar todos los binlog más antiguos que una fecha determinada PURGE BINARY LOGS BEFORE \u0026#39;2026-03-01 00:00:00\u0026#39;; PURGE hace tres cosas que rm no hace:\nActualiza el archivo índice Verifica que los archivos no sean necesarios para la replicación (en teoría — pero compruébalo tú antes) Elimina los archivos de forma ordenada En el caso de nuestro servidor, primero verifiqué que no hubiera slaves:\nSHOW REPLICAS; -- Empty set Ninguna réplica. Luego comprobé cuál era el binlog actual:\nSHOW MASTER STATUS; +------------------+----------+ | File | Position | +------------------+----------+ | mysql-bin.000318 | 52428800 | +------------------+----------+ Manteniendo los últimos 3 archivos por seguridad:\nPURGE BINARY LOGS TO \u0026#39;mysql-bin.000316\u0026#39;; Resultado: 175 GB liberados en pocos segundos. El disco bajó del 95% al 28%.\nConfigurar la retención automática #Resolver la emergencia es una cosa. Hacer que no vuelva a ocurrir es otra. MySQL ofrece dos parámetros para la gestión automática de la retención:\nexpire_logs_days (legacy) #[mysqld] expire_logs_days = 14 Elimina automáticamente los binlog más antiguos de 14 días. Simple pero tosco — la granularidad es solo en días.\nbinlog_expire_logs_seconds (MySQL 8.0+) #[mysqld] binlog_expire_logs_seconds = 1209600 # 14 días en segundos Misma lógica, pero con granularidad al segundo. Desde MySQL 8.0, este parámetro tiene prioridad sobre expire_logs_days. Si los configuras ambos, gana binlog_expire_logs_seconds.\nLa pregunta que siempre me hacen es: \u0026ldquo;¿Cuántos días de retención?\u0026rdquo;\nDepende. Pero aquí van mis reglas prácticas:\nEscenario Retención recomendada Servidor standalone, backup diario 7 días Master con réplica, backup diario 7-14 días Master con réplica lenta o en zonas diferentes 14-30 días Entornos regulados (finanzas, sanidad) 30-90 días, con archivo El principio es: la retención de los binlog debe cubrir al menos el doble del intervalo entre dos backups. Si haces backup cada noche, mantén al menos 2-3 días de binlog. Si haces backups semanales, al menos 14 días.\nEn el caso de nuestro servidor, no se había configurado ninguna retención. El valor por defecto de MySQL 8.0 es 30 días — pero ese valor había sido sobrescrito a 0 (sin expiración) en un my.cnf personalizado por alguien que \u0026ldquo;quería guardar todo por seguridad\u0026rdquo;. La ironía: la seguridad que quería garantizar estaba a punto de tumbar el servidor llenando el disco.\nLos tres formatos del binlog: STATEMENT, ROW, MIXED #No todos los binlog son iguales. MySQL soporta tres formatos de registro, y la elección tiene implicaciones concretas.\nSTATEMENT #Registra la instrucción SQL tal como fue ejecutada. Compacto, legible, pero problemático: funciones como NOW(), UUID(), RAND() producen resultados diferentes en el master y en el slave. Las consultas con LIMIT sin ORDER BY pueden producir resultados no deterministas.\nSET binlog_format = \u0026#39;STATEMENT\u0026#39;; ROW #Registra el cambio a nivel de fila — antes y después. Más pesado en términos de espacio, pero determinista al 100%. Si actualizas 10.000 filas, el binlog contiene 10.000 imágenes before/after. Grande, pero seguro.\nSET binlog_format = \u0026#39;ROW\u0026#39;; MIXED #MySQL decide caso por caso: usa STATEMENT cuando es seguro, cambia automáticamente a ROW cuando detecta operaciones no deterministas.\nSET binlog_format = \u0026#39;MIXED\u0026#39;; Mi consejo: usa ROW. Es el valor por defecto desde MySQL 5.7.7, es lo que Galera Cluster requiere, es lo que todas las herramientas de replicación modernas esperan. STATEMENT es un legado del pasado, MIXED es un compromiso que añade complejidad sin un beneficio real.\nEl único caso en que ROW se convierte en un problema es cuando haces operaciones masivas — un UPDATE sobre millones de filas genera un binlog enorme porque contiene el before y el after de cada fila. En esos casos, la solución no es cambiar el formato, sino dividir la operación en lotes:\n-- En vez de esto (genera binlog gigantesco): UPDATE orders SET status = \u0026#39;archived\u0026#39; WHERE order_date \u0026lt; \u0026#39;2025-01-01\u0026#39;; -- Mejor así (lotes de 10.000): UPDATE orders SET status = \u0026#39;archived\u0026#39; WHERE order_date \u0026lt; \u0026#39;2025-01-01\u0026#39; AND status != \u0026#39;archived\u0026#39; LIMIT 10000; -- Repetir hasta 0 rows affected mysqlbinlog: leer los binlog cuando hace falta #La herramienta de línea de comandos `mysqlbinlog` es el único modo de inspeccionar el contenido de los archivos binlog. Se usa en dos escenarios: debug de problemas de replicación y point-in-time recovery.\n# Leer un binlog en formato legible mysqlbinlog /var/lib/mysql/mysql-bin.000318 # Filtrar por intervalo temporal mysqlbinlog --start-datetime=\u0026#34;2026-03-30 10:00:00\u0026#34; \\ --stop-datetime=\u0026#34;2026-03-30 11:00:00\u0026#34; \\ /var/lib/mysql/mysql-bin.000318 # Filtrar por base de datos específica mysqlbinlog --database=gestionale /var/lib/mysql/mysql-bin.000318 # Si el formato es ROW, decodificar en SQL legible mysqlbinlog --verbose /var/lib/mysql/mysql-bin.000318 Con formato ROW, sin --verbose solo ves blobs binarios. Con --verbose obtienes las filas en formato pseudo-SQL comentado — no es bonito, pero se puede leer.\nEl principio: gestionar los binlog, no desactivarlos #De vez en cuando alguien sugiere resolver el problema \u0026ldquo;de raíz\u0026rdquo; desactivando los binlog:\n# NO HAGAS ESTO en producción skip-log-bin Sí, resuelve el problema de disco. Pero elimina:\nLa posibilidad de configurar una réplica en el futuro El point-in-time recovery La capacidad de analizar qué pasó en la base de datos después de un incidente La compatibilidad con herramientas de CDC (Change Data Capture) como Debezium Los binlog no son un problema. Los binlog no gestionados son un problema. La diferencia es un parámetro de configuración y un chequeo semanal. En el servidor que arreglé, la configuración final fue:\n[mysqld] log_bin = /var/lib/mysql/mysql-bin server-id = 1 binlog_format = ROW binlog_expire_logs_seconds = 604800 # 7 días max_binlog_size = 512M Un max_binlog_size de 512 MB en lugar del 1 GB por defecto — archivos más pequeños son más fáciles de gestionar, transferir y purgar. La retención a 7 días, con backup diario, garantiza cobertura PITR completa con ocupación de disco predecible.\nRevisión post intervención #Antes de cerrar el ticket, añadí un par de consultas al sistema de monitorización del cliente:\n-- Espacio ocupado por los binlog SELECT COUNT(*) AS num_files, ROUND(SUM(file_size) / 1024 / 1024 / 1024, 2) AS total_gb FROM information_schema.BINARY_LOGS; -- MySQL 8.0+ / Performance Schema -- O, para todas las versiones: SHOW BINARY LOGS; -- y sumar manualmente o con script # Alerta si los binlog superan los 20 GB #!/bin/bash BINLOG_SIZE=$(mysql -u monitor -p\u0026#39;pwd\u0026#39; -Bse \\ \u0026#34;SELECT ROUND(SUM(file_size)/1024/1024/1024,2) FROM performance_schema.binary_log_status\u0026#34; 2\u0026gt;/dev/null) # Fallback para versiones sin performance_schema.binary_log_status if [ -z \u0026#34;$BINLOG_SIZE\u0026#34; ]; then BINLOG_SIZE=$(du -sh /var/lib/mysql/mysql-bin.* 2\u0026gt;/dev/null | \\ awk \u0026#39;{sum+=$1} END {printf \u0026#34;%.2f\u0026#34;, sum/1024}\u0026#39;) fi if (( $(echo \u0026#34;$BINLOG_SIZE \u0026gt; 20\u0026#34; | bc -l) )); then echo \u0026#34;WARNING: binlog size ${BINLOG_SIZE} GB\u0026#34; fi Tres semanas después de la intervención, los binlog ocupaban 8 GB — exactamente dentro de la ventana prevista. El disco no ha vuelto a superar el 45%.\nEl binlog es como el aceite del motor: nunca piensas en él hasta que se enciende el testigo. La diferencia es que el motor te avisa. MySQL no — sigue escribiendo binlog mientras el filesystem responda. Cuando deja de responder, ya es tarde para preguntarse por qué no habías configurado la retención.\nGlosario #Binary log — Registro binario secuencial de MySQL que rastrea todas las modificaciones de datos (INSERT, UPDATE, DELETE, DDL), usado para la replicación y el point-in-time recovery. Habilitado por defecto desde MySQL 8.0.\nPITR — Point-in-Time Recovery: técnica de restauración que combina un backup completo con los binary log para llevar la base de datos a cualquier momento en el tiempo, no solo al momento del backup.\nRelay log — Archivo de log intermedio en el slave MySQL que recibe los eventos del binary log del master antes de ser ejecutados localmente por el hilo SQL.\nCDC — Change Data Capture: técnica para interceptar los cambios en los datos en tiempo real leyendo los logs de transacciones. Herramientas como Debezium leen los binary log de MySQL para propagar los cambios hacia sistemas externos.\nmysqlbinlog — Utilidad de línea de comandos de MySQL para leer, filtrar y reaplicar el contenido de los archivos binary log. Indispensable para el point-in-time recovery y el debug de replicación.\n","date":"31 marzo 2026","permalink":"https://ivanluminaria.com/es/posts/mysql/binary-log-mysql/","section":"Database Strategy","summary":"\u003cp\u003eEl mensaje en el canal de Slack del equipo de infraestructura era de esos que te hacen levantar la cabeza de la pantalla: \u0026ldquo;Disco al 95% en el db de producción. ¿Alguien puede mirar?\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eEl servidor era un MySQL 8.0 sobre Rocky Linux, un sistema de gestión usado por un centenar de usuarios. La base de datos en sí ocupaba unos 40 GB — nada extraordinario. Pero en el directorio de datos había 180 GB de binary logs. Seis meses de binlog que nadie había pensado en gestionar.\u003c/p\u003e","title":"Binary log en MySQL: qué son, cómo gestionarlos y cuándo puedes borrarlos"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/binlog/","section":"Tags","summary":"","title":"Binlog"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/categories/","section":"Categories","summary":"","title":"Categories"},{"content":" La diferencia entre un sistema que funciona\ny uno que realmente impulsa el negocio no es suerte.\nEs comprensión profunda de los planes de ejecución.\nEs control de privilegios y seguridad de los datos.\nEs modelado de datos alineado con los objetivos empresariales.\nEs rendimiento que se mantiene cuando la carga aumenta.\nLas bases de datos son el núcleo operativo del ecosistema digital de cualquier empresa.\nSostienen procesos críticos, habilitan decisiones basadas en datos y determinan la velocidad y eficiencia operativa.\nDentro del Motor es el espacio donde analizo lo que ocurre bajo el capó de PostgreSQL, Oracle y MySQL: performance tuning, seguridad, arquitectura y decisiones técnicas aplicables en entornos reales.\nPorque en el mundo data-driven actual, las bases de datos no son simples componentes de software.\nSon activos estratégicos que influyen en la competitividad, la fiabilidad y el crecimiento sostenible.\n","date":null,"permalink":"https://ivanluminaria.com/es/posts/","section":"Database Strategy","summary":"\u003cblockquote\u003e\n\u003cp\u003eLa diferencia entre un sistema que funciona\u003cbr\u003e\ny uno que realmente impulsa el negocio no es suerte.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eEs comprensión profunda de los planes de ejecución.\u003cbr\u003e\nEs control de privilegios y seguridad de los datos.\u003cbr\u003e\nEs modelado de datos alineado con los objetivos empresariales.\u003cbr\u003e\nEs rendimiento que se mantiene cuando la carga aumenta.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eLas bases de datos son el núcleo operativo del ecosistema digital de cualquier empresa.\u003cbr\u003e\nSostienen procesos críticos, habilitan decisiones basadas en datos y determinan la velocidad y eficiencia operativa.\u003cbr\u003e\u003c/p\u003e","title":"Database Strategy"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/disk-space/","section":"Tags","summary":"","title":"Disk-Space"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/","section":"Ivan Luminaria","summary":"","title":"Ivan Luminaria"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/mariadb/","section":"Tags","summary":"","title":"Mariadb"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/categories/mysql/","section":"Categories","summary":"","title":"Mysql"},{"content":"MySQL es la base de datos que no necesita presentación.\nEs el motor que impulsó el crecimiento de la web durante más de veinte años.\nNacido en 1995 en Suecia, en 2008 fue adquirido por Sun Microsystems — y cuando Oracle completó la adquisición de Sun en 2010, MySQL acabó en el portafolio del mayor proveedor de bases de datos comerciales del mundo. Yo era empleado de Oracle en ese momento, y recuerdo bien el clima: por un lado la curiosidad de ver cómo Oracle gestionaría un producto open source tan popular, por otro el temor de que MySQL fuera marginado a favor de la base de datos propietaria.\nEse temor llevó a Michael \u0026ldquo;Monty\u0026rdquo; Widenius — el creador original de MySQL — a hacer el fork en 2009, dando vida a MariaDB. Un proyecto que comparte sus raíces con MySQL pero ha tomado caminos propios en motores de almacenamiento, optimizador y funcionalidades avanzadas.\nLa historia ha demostrado que ambos proyectos sobrevivieron y evolucionaron, pero sus decisiones arquitectónicas divergen cada vez más. Conocer las diferencias no es academia — es necesidad operativa.\nEn esta sección exploro MySQL y MariaDB desde una perspectiva operativa: seguridad, gestión de usuarios, rendimiento y decisiones de diseño que marcan la diferencia en entornos de producción.\nPorque usar MySQL no es solo ejecutar consultas.\nEs entender cómo el motor gestiona conexiones, privilegios y recursos bajo carga real.\n","date":null,"permalink":"https://ivanluminaria.com/es/posts/mysql/","section":"Database Strategy","summary":"\u003cp\u003eMySQL es la base de datos que no necesita presentación.\u003cbr\u003e\nEs el motor que impulsó el crecimiento de la web durante más de veinte años.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eNacido en 1995 en Suecia, en 2008 fue adquirido por Sun Microsystems — y cuando Oracle completó la adquisición de Sun en 2010, MySQL acabó en el portafolio del mayor proveedor de bases de datos comerciales del mundo. Yo era empleado de Oracle en ese momento, y recuerdo bien el clima: por un lado la curiosidad de ver cómo Oracle gestionaría un producto open source tan popular, por otro el temor de que MySQL fuera marginado a favor de la base de datos propietaria.\u003cbr\u003e\u003c/p\u003e","title":"MySQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/recovery/","section":"Tags","summary":"","title":"Recovery"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/replication/","section":"Tags","summary":"","title":"Replication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/autovacuum/","section":"Tags","summary":"","title":"Autovacuum"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/bloat/","section":"Tags","summary":"","title":"Bloat"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/mvcc/","section":"Tags","summary":"","title":"Mvcc"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/performance/","section":"Tags","summary":"","title":"Performance"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/categories/postgresql/","section":"Categories","summary":"","title":"Postgresql"},{"content":"PostgreSQL no es solo una base de datos open source.\nEs el resultado de casi cuatro décadas de evolución académica e industrial.\nNacido en 1986 en la Universidad de Berkeley como evolución de Ingres, el proyecto original POSTGRES introdujo conceptos que en su momento eran vanguardia: extensibilidad, tipos de datos personalizados, reglas y un modelo relacional avanzado.\nEn 1996 se añadió soporte SQL y el nombre pasó a ser PostgreSQL.\nEl mundo, sin embargo, siguió llamándolo simplemente “Postgres”.\nY está bien así.\nEn esta sección analizo PostgreSQL desde una perspectiva arquitectónica y operativa: diseño, rendimiento, seguridad y decisiones técnicas aplicables en entornos reales.\nPorque elegir PostgreSQL no es solo elegir una base de datos open source.\nEs elegir un motor diseñado para ser extendido, analizado y comprendido en profundidad.\n","date":null,"permalink":"https://ivanluminaria.com/es/posts/postgresql/","section":"Database Strategy","summary":"\u003cp\u003ePostgreSQL no es solo una base de datos open source.\u003cbr\u003e\nEs el resultado de casi cuatro décadas de evolución académica e industrial.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eNacido en 1986 en la Universidad de Berkeley como evolución de Ingres, el proyecto original POSTGRES introdujo conceptos que en su momento eran vanguardia: extensibilidad, tipos de datos personalizados, reglas y un modelo relacional avanzado.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eEn 1996 se añadió soporte SQL y el nombre pasó a ser PostgreSQL.\u003cbr\u003e\nEl mundo, sin embargo, siguió llamándolo simplemente “Postgres”.\u003cbr\u003e\nY está bien así.\u003cbr\u003e\u003c/p\u003e","title":"PostgreSQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/vacuum/","section":"Tags","summary":"","title":"Vacuum"},{"content":"Hace un par de años me pidieron revisar un PostgreSQL en producción que \u0026ldquo;se ralentiza cada semana\u0026rdquo;. Siempre el mismo patrón: el lunes va bien, el viernes es un desastre. El fin de semana alguien reinicia el servicio y se empieza de nuevo.\nBase de datos de unos 200 GB. Las tablas principales ocupaban casi el triple del espacio efectivo de los datos. Queries cayendo en sequential scan donde no deberían. Tiempos de respuesta que subían día tras día.\nEl autovacuum estaba activo. Nadie lo había desactivado. Pero nadie lo había configurado tampoco.\n🧠 MVCC: por qué PostgreSQL genera \u0026ldquo;basura\u0026rdquo; #Para entender el problema hay que dar un paso atrás. PostgreSQL usa MVCC — Multi-Version Concurrency Control. Cada vez que haces un UPDATE, la base de datos no sobreescribe la fila original. Crea una nueva versión y marca la vieja como \u0026ldquo;muerta\u0026rdquo;.\nLo mismo para los DELETE: la fila no se elimina físicamente. Se marca como no visible para las nuevas transacciones.\nEstas filas muertas se llaman dead tuples. Y se quedan ahí, dentro de las páginas de datos, ocupando espacio en disco y ralentizando los escaneos.\nEs el precio que PostgreSQL paga por tener aislamiento transaccional sin bloqueos exclusivos en las lecturas. Un precio razonable — siempre que alguien pase a limpiar.\n🔧 VACUUM: qué hace realmente #El comando VACUUM hace una cosa simple: recupera el espacio ocupado por los dead tuples y lo hace reutilizable para nuevas inserciones.\nNo devuelve espacio al sistema operativo. No reorganiza la tabla. No compacta nada. Marca las páginas como reescribibles.\nVACUUM reporting.transactions; Esto basta en la mayoría de los casos. VACUUM es ligero, no bloquea las escrituras y puede funcionar en paralelo con las queries normales.\n¿Y VACUUM FULL? #VACUUM FULL es otra bestia. Reescribe físicamente la tabla entera, eliminando todo el espacio muerto. Devuelve espacio al sistema de archivos.\nPero el coste es brutal: toma un bloqueo exclusivo sobre la tabla durante toda la operación. Nadie lee, nadie escribe. En tablas grandes hablamos de minutos u horas.\nVACUUM FULL reporting.transactions; En producción, VACUUM FULL debe usarse muy raramente. En emergencias. Y siempre fuera de horario.\n⚙️ Autovacuum: el conserje silencioso #PostgreSQL tiene un daemon que ejecuta el VACUUM automáticamente: el autovacuum.\nSe activa cuando una tabla acumula suficientes dead tuples. El umbral se calcula así:\nvacuum threshold = autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor × n_live_tup Los valores por defecto:\nautovacuum_vacuum_threshold: 50 dead tuples autovacuum_vacuum_scale_factor: 0.2 (20%) Traducido: en una tabla con 10 millones de filas, el autovacuum arranca cuando los dead tuples superan 2.000.050. Dos millones de filas muertas antes de que alguien haga limpieza.\nPara una tabla con 500.000 updates al día, eso significa que el autovacuum se activa quizá cada 4 días. Mientras tanto el bloat crece, los escaneos se ralentizan, los índices se hinchan.\nPor eso el lunes todo iba bien y el viernes era un desastre.\n📊 Diagnóstico: leer pg_stat_user_tables #Lo primero que hay que hacer cuando sospechas un problema de vacuum es consultar pg_stat_user_tables:\nSELECT schemaname, relname, n_live_tup, n_dead_tup, round(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 1) AS dead_pct, last_vacuum, last_autovacuum, autovacuum_count, vacuum_count FROM pg_stat_user_tables WHERE n_dead_tup \u0026gt; 10000 ORDER BY n_dead_tup DESC; En el caso de mi cliente, la situación era esta:\nrelname | n_live_tup | n_dead_tup | dead_pct | last_autovacuum -------------------+------------+------------+----------+------------------ transactions | 12.400.000 | 3.800.000 | 23,5% | hace 3 días order_lines | 8.200.000 | 2.100.000 | 20,4% | hace 4 días inventory_moves | 5.600.000 | 1.900.000 | 25,3% | hace 5 días Casi una cuarta parte de las filas estaban muertas. El autovacuum funcionaba, pero con demasiada poca frecuencia para mantener el ritmo.\n🎯 Tuning: adaptar el autovacuum a la realidad #El truco no es desactivar el autovacuum. Nunca. El truco es configurarlo para las tablas que lo necesitan.\nPostgreSQL permite establecer parámetros de autovacuum por tabla individual:\nALTER TABLE reporting.transactions SET ( autovacuum_vacuum_scale_factor = 0.01, autovacuum_vacuum_threshold = 1000 ); Con esta configuración, el autovacuum arranca después de 1.000 + 1% de las filas vivas de dead tuples. En 12 millones de filas, se activa con ~121.000 dead tuples en vez de 2 millones.\ncost_delay: no estrangules al vacuum #Otro parámetro crítico es autovacuum_vacuum_cost_delay. Controla cuánto el vacuum \u0026ldquo;se frena a sí mismo\u0026rdquo; para no sobrecargar el I/O.\nEl valor por defecto es 2 milisegundos. En servidores modernos con SSD, es demasiado conservador. Reducirlo a 0 o 1 ms permite que el vacuum termine antes:\nALTER TABLE reporting.transactions SET ( autovacuum_vacuum_cost_delay = 0 ); max_workers #El valor por defecto es 3 workers de autovacuum. Si tienes decenas de tablas con mucho tráfico, 3 workers no bastan. Evalúa subirlos a 5–6, monitorizando el impacto en CPU e I/O:\n-- en postgresql.conf autovacuum_max_workers = 5 📏 Medir el bloat #¿Cómo sabes cuánto espacio están desperdiciando tus tablas?\nLa consulta clásica usa pgstattuple:\nCREATE EXTENSION IF NOT EXISTS pgstattuple; SELECT pg_size_pretty(pg_total_relation_size(\u0026#39;reporting.transactions\u0026#39;)) AS total_size, pg_size_pretty(pg_total_relation_size(\u0026#39;reporting.transactions\u0026#39;) - pg_relation_size(\u0026#39;reporting.transactions\u0026#39;)) AS index_size, * FROM pgstattuple(\u0026#39;reporting.transactions\u0026#39;); Los campos clave: dead_tuple_percent y free_space. Si dead_tuple supera el 20–30%, la tabla tiene un problema serio.\nUna alternativa menos precisa pero más ligera es estimar el bloat ratio comparando pg_class.relpages con las filas estimadas — hay consultas consolidadas en la comunidad para esto (la clásica \u0026ldquo;bloat estimation query\u0026rdquo; de PostgreSQL Experts).\n🛠️ Cuando VACUUM no basta: pg_repack #Si el bloat ya se ha ido de las manos — tablas al 50–70% de espacio muerto — el VACUUM normal no recupera todo. Libera los dead tuples, pero el espacio fragmentado permanece.\nVACUUM FULL funciona, pero bloquea todo.\nLa alternativa en producción es pg_repack: reconstruye la tabla online, sin bloqueos exclusivos prolongados.\npg_repack -d mydb -t reporting.transactions No es una solución para usar cada semana. Es la cura de choque para cuando la situación ya ha degenerado. La verdadera solución es no llegar a ese punto, con un autovacuum bien configurado.\n💬 El principio #Desactivar el autovacuum es lo peor que puedes hacerle a un PostgreSQL en producción. Lo he visto hacer \u0026ldquo;porque ralentiza las queries durante el día\u0026rdquo;. Claro, porque mientras tanto el bloat te está devorando la base de datos desde dentro.\nEl autovacuum con los valores por defecto de PostgreSQL está pensado para una base de datos genérica. Ninguna base de datos en producción es genérica. Cada tabla tiene su patrón de escritura, su volumen, su ritmo.\nTres cosas para llevarse:\nRevisa pg_stat_user_tables con regularidad. Si n_dead_tup crece más rápido de lo que el autovacuum puede limpiar, tienes un problema.\nConfigura scale_factor y threshold para las tablas de alto tráfico. No existe una configuración universal.\nNo esperes a que el bloat llegue al 50% para actuar. A ese punto las opciones son pocas y todas dolorosas.\nLas bases de datos no se mantienen solas. Ni siquiera las que tienen un daemon que lo intenta.\nGlosario #VACUUM — Comando PostgreSQL que recupera el espacio ocupado por dead tuples, haciéndolo reutilizable para nuevas inserciones sin devolverlo al sistema operativo.\nMVCC — Multi-Version Concurrency Control — modelo de concurrencia de PostgreSQL que mantiene múltiples versiones de las filas para garantizar aislamiento transaccional sin locks exclusivos en las lecturas.\nDead Tuple — Fila obsoleta en una tabla PostgreSQL, marcada como ya no visible después de un UPDATE o DELETE pero aún no eliminada físicamente del disco.\nAutovacuum — Daemon de PostgreSQL que ejecuta automáticamente VACUUM y ANALYZE en las tablas cuando el número de dead tuples supera un umbral configurable.\nBloat — Espacio muerto acumulado en una tabla o índice PostgreSQL debido a dead tuples no eliminados, que hincha el tamaño en disco y degrada el rendimiento.\n","date":"24 marzo 2026","permalink":"https://ivanluminaria.com/es/posts/postgresql/vacuum-autovacuum-postgresql/","section":"Database Strategy","summary":"\u003cp\u003eHace un par de años me pidieron revisar un PostgreSQL en producción que\n\u0026ldquo;se ralentiza cada semana\u0026rdquo;. Siempre el mismo patrón: el lunes va bien,\nel viernes es un desastre. El fin de semana alguien reinicia el\nservicio y se empieza de nuevo.\u003c/p\u003e\n\u003cp\u003eBase de datos de unos 200 GB. Las tablas principales ocupaban casi el\ntriple del espacio efectivo de los datos. Queries cayendo en sequential\nscan donde no deberían. Tiempos de respuesta que subían día tras día.\u003c/p\u003e","title":"VACUUM y autovacuum: por qué PostgreSQL necesita que alguien limpie"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/ai/","section":"Tags","summary":"","title":"Ai"},{"content":"Hace unos meses, durante una reunión con un cliente del sector bancario, el CTO dijo algo que se me quedó grabado.\n\u0026ldquo;Necesitamos a alguien que gestione la IA. No alguien que la use — alguien que la gobierne.\u0026rdquo;\nAsentí sin decir nada. Porque esa frase, en siete segundos, describía un rol que el mercado está buscando sin saber todavía cómo llamarlo.\n🧩 El malentendido fundamental #Hay una confusión generalizada, y la veo en cada proyecto donde la IA entra en juego.\nLa confusión es esta: pensar que \u0026ldquo;adoptar la IA\u0026rdquo; significa integrar un modelo, conectar una API, hacer que un asistente genere texto o código.\nNo. Eso es el aspecto técnico. El aspecto operativo. Es el trabajo de un data scientist o de un ingeniero ML. Trabajo importante, sin duda. Pero no es el trabajo de quien gobierna.\nGobernar la IA en un proyecto significa responder a preguntas que ningún modelo puede responder por ti:\n¿Dónde la IA genera valor real y dónde genera solo entusiasmo? ¿Cuánto cuesta mantenerla, no solo implementarla? ¿Qué pasa cuando el modelo se equivoca — y quién responde? ¿Cómo se integra con las arquitecturas que ya existen sin comprometer estabilidad ni seguridad? ¿Cómo se garantiza coherencia entre gobierno del dato, cumplimiento normativo y automatización? Si no tienes respuestas a estas preguntas, no estás gobernando la IA. La estás sufriendo.\n🏗️ No es un rol nuevo. Es un rol que aún no tenía nombre #Cuando lo pienso, me doy cuenta de que llevo haciendo este trabajo mucho antes de que alguien inventara la etiqueta \u0026ldquo;AI Manager\u0026rdquo;.\nTreinta años de arquitecturas de datos. Sistemas mission-critical en Telco, Banca, Seguros, Administración Pública. Entornos donde el dato no es un activo a monetizar — es una infraestructura a proteger.\nEn esos contextos siempre he hecho lo mismo: conectar la estrategia con la realidad técnica. Traducir las necesidades del negocio en soluciones que funcionan de verdad, no en la diapositiva sino en producción. Mediar entre quien lo quiere todo ya y quien sabe que ciertas cosas requieren tiempo y arquitectura.\nLa IA no ha cambiado este esquema. Lo ha hecho más visible.\nPorque la IA, a diferencia de una base de datos o de un ETL, es un tema que excita a los directivos y asusta a los técnicos. Todos quieren un trozo, pocos saben dónde ponerlo. Y el rol de quien está en medio — entre el entusiasmo de la dirección y la prudencia de la infraestructura — se vuelve crucial.\n📍 Dónde la IA genera valor real (y dónde no) #He aprendido algo en los últimos tres años, trabajando con la IA en contextos de proyecto concretos: el valor de la IA casi nunca está donde la gente cree.\nNo está en la generación automática de código. No está en el chatbot que responde a los clientes. No está en el informe que se escribe solo.\nEl valor real está en tres sitios:\n1. Aceleración del análisis\nLa IA es devastadora cuando tiene que analizar contexto. Leer miles de líneas de código, correlacionar logs, identificar patrones. Lo que a un senior le cuesta dos horas, la IA lo hace en segundos. No mejor — más rápido. Y la velocidad, en un proyecto con fechas límite, es dinero.\n2. Reducción del ruido decisional\nEn todo proyecto complejo hay un momento en que la información es demasiada y el equipo ya no sabe qué es urgente y qué es importante. La IA puede hacer triaje. Puede clasificar, priorizar, destacar anomalías. No decide por ti — te presenta los datos de forma que la decisión sea más clara.\n3. Documentación y transferencia de conocimiento\nNadie documenta con gusto. Nadie. La IA puede generar documentación a partir del código, de los commits, de las issues. No perfecta, pero suficiente para no perder conocimiento cuando alguien deja el proyecto. Y quien ha gestionado proyectos sabe cuánto cuesta eso.\nTodo lo demás — las demos que brillan, las presentaciones con porcentajes en negrita, los proveedores que prometen ROI de tres cifras — es ruido. El AI Manager es quien separa la señal del ruido.\n⚖️ El triángulo que el PM debe gobernar #En cada proyecto donde la IA entra en un entorno regulado, hay un triángulo que siempre vuelve:\nGobierno del dato — Cumplimiento normativo — Automatización.\nPuedes tener la automatización más eficiente del mundo, pero si viola las políticas de gobierno del dato, es un riesgo. Puedes tener un gobierno impecable, pero si bloquea toda forma de automatización, el proyecto no avanza. Puedes ser perfectamente compliant, pero si no sabes qué datos estás usando para entrenar o consultar el modelo, el cumplimiento es solo sobre el papel.\nEl AI Manager debe mantener en equilibrio estos tres vértices. Continuamente. No una vez al inicio del proyecto — cada semana.\nHe visto proyectos donde la IA se integraba sin que nadie hubiera verificado la procedencia de los datos de entrenamiento. En banca. Con datos sujetos a GDPR. El DPO lo descubrió tres meses después.\nEso no es incompetencia. Es ausencia de gobierno. Es la ausencia de alguien que haga la pregunta correcta en el momento correcto.\n🔬 Integrar, no sustituir #Algo que repito en cada kickoff meeting: la IA se integra en las arquitecturas existentes. No las sustituye.\nParece obvio, pero la tentación es siempre la misma: el proveedor que propone \u0026ldquo;repensar la infraestructura en clave IA\u0026rdquo;, el consultor que quiere una arquitectura greenfield, el directivo que ha visto una demo y ahora lo quiere todo nuevo.\nNo.\nLas arquitecturas mission-critical no se tiran porque ha llegado una tecnología nueva. Evolucionan. Se extienden. Se protegen.\nEl AI Manager es quien dice \u0026ldquo;este modelo se conecta aquí, con estas precauciones, con este plan de contingencia\u0026rdquo;. No quien dice \u0026ldquo;tiremos todo y rehagamos con IA\u0026rdquo;.\nEn treinta años de sistemas, he visto al menos cinco tecnologías \u0026ldquo;revolucionarias\u0026rdquo; que iban a cambiarlo todo. Cliente-servidor. Internet. Cloud. Big Data. Ahora IA. Ninguna lo cambió todo. Cada una cambió algo. Y quienes gestionaron bien el cambio fueron quienes lo integraron con inteligencia — no con entusiasmo.\n🎯 Por qué la IA no es magia #Hay una frase que uso a menudo, y no me canso de repetirla.\nLa IA no es magia. Es arquitectura aplicada a la inteligencia.\nUn modelo es un componente. Como una base de datos, como un message broker, como un balanceador de carga. Necesita inputs limpios, monitorización, mantenimiento, gobierno. Necesita a alguien que entienda lo que hace, lo que puede hacer, y sobre todo lo que no puede hacer.\nEl Project Manager que ignora estos aspectos y lo delega todo al equipo técnico está cometiendo el mismo error de quien delegaba la seguridad al administrador de sistemas y después se sorprendía de la fuga de datos.\nLa IA es una responsabilidad arquitectónica. Y como todas las responsabilidades arquitectónicas, se gobierna desde arriba. No desde abajo.\n💬 A quien está decidiendo si la IA \u0026ldquo;sirve\u0026rdquo; en su proyecto #Si estás evaluando introducir la IA en un proyecto — no en un experimento, en un proyecto real, con fechas límite, presupuesto y stakeholders — te doy un consejo que vale más que cualquier herramienta.\nNo empieces por la tecnología. Empieza por el problema.\n¿Cuál es el cuello de botella? ¿Dónde pierde más tiempo el equipo? ¿Dónde las decisiones son más lentas de lo necesario? ¿Dónde se pierde conocimiento?\nSi la respuesta a alguna de estas preguntas tiene que ver con analizar grandes volúmenes de datos, clasificar información, o acelerar procesos repetitivos — entonces la IA puede ayudarte. Pero solo si alguien la gobierna.\nY gobernarla no significa controlarla. Significa entenderla lo suficiente para saber cuándo confiar y cuándo no.\nEse es el trabajo del AI Manager. Y, se le llame así o no, es un rol que todo proyecto serio necesitará tener.\nGlosario #AI Manager — Rol profesional que gobierna el impacto de la inteligencia artificial en arquitecturas, procesos y personas, separando el valor real del ruido.\nData Governance — Conjunto de políticas, procesos y estándares que garantizan la calidad, seguridad y conformidad de los datos dentro de una organización.\nKnowledge Transfer — Proceso de transferencia de conocimiento entre personas, equipos o sistemas, crítico en proyectos IT donde la pérdida de know-how puede comprometer la continuidad operativa.\nROI — Return on Investment — relación entre el beneficio obtenido y el coste incurrido en una inversión.\nCompliance — Conformidad con las normativas, regulaciones y estándares aplicables — en el contexto AI incluye GDPR, regulaciones sectoriales y políticas internas sobre el uso de datos.\n","date":"17 marzo 2026","permalink":"https://ivanluminaria.com/es/posts/project-management/ai-manager-project-management/","section":"Database Strategy","summary":"\u003cp\u003eHace unos meses, durante una reunión con un cliente del sector bancario, el CTO dijo algo que se me quedó grabado.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Necesitamos a alguien que gestione la IA. No alguien que la use — alguien que la gobierne.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eAsentí sin decir nada. Porque esa frase, en siete segundos, describía un rol que el mercado está buscando sin saber todavía cómo llamarlo.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-el-malentendido-fundamental\" class=\"relative group\"\u003e🧩 El malentendido fundamental \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-el-malentendido-fundamental\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eHay una confusión generalizada, y la veo en cada proyecto donde la IA entra en juego.\u003c/p\u003e","title":"AI Manager y Project Management: cuando la inteligencia artificial entra en los proyectos"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/ai-manager/","section":"Tags","summary":"","title":"Ai-Manager"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/governance/","section":"Tags","summary":"","title":"Governance"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/categories/project-management/","section":"Categories","summary":"","title":"Project Management"},{"content":"He visto a project managers hacer llorar a desarrolladores senior en una reunión. He visto equipos brillantes destruidos por PMs que confundían la autoridad con el autoritarismo. He visto software entregado \u0026ldquo;a tiempo\u0026rdquo; que no funcionaba, y proyectos de millones de euros acabados en nada.\nY he visto lo contrario: equipos pequeños, autónomos, respetados — que construían sistemas sólidos en una fracción del tiempo y del presupuesto.\nLa diferencia nunca fue la tecnología. Siempre fue el método.\nDespués de treinta años en este oficio, hay algo que tengo claro: las personas no dan lo mejor de sí cuando tienen miedo. Lo dan cuando tienen confianza.\nConfianza en el equipo. Confianza en el proceso. Confianza en que si se equivocan, no serán castigadas — serán ayudadas.\nEl project manager que funciona no es el que controla, aterroriza y cuenta horas. Es el que:\ndefine objetivos claros y da al equipo la libertad de alcanzarlos construye competencias profundas y las protege de la rotación hace team building cada día, no una vez al año en el karting mide resultados, no horas en la oficina usa el smart working como ventaja competitiva, no como concesión cuando algo sale mal, se pone delante del equipo, no detrás 📊 Cómo trabajo yo #Mi enfoque es Scrum — pero Scrum hecho en serio, no la liturgia de los post-it.\nEl Scrum que funciona se basa en un pacto: transparencia radical, responsabilidad compartida y autonomía en el \u0026ldquo;cómo\u0026rdquo;. El PM define el qué y el por qué. El equipo decide el cómo. Porque quien escribe el código sabe mejor que nadie cómo escribirlo.\nY este pacto funciona aún mejor con el smart working. El daily standup? 15 minutos en una llamada. La sprint review? Pantalla compartida con el cliente, que ve el software — no las diapositivas. La retrospectiva? Una hora en la que el equipo dice la verdad, porque no tiene al PM a dos metros mirándolo fijamente.\nMido pocas cosas, pero las mido bien:\nMétrica Qué dice Velocity Cuánto entrega el equipo por sprint Lead time Cuánto pasa desde la solicitud hasta el lanzamiento Bug escape rate Cuántos defectos se escapan a producción Sprint goal success % de objetivos de sprint logrados Team happiness Cómo se siente el equipo — la métrica más importante La última — team happiness — es la que los PMs tradicionales nunca miden. Un equipo feliz no es un equipo que se divierte. Es un equipo que se siente respetado, escuchado y valorado. Y un equipo así produce más. No porque trabaje más horas. Porque trabaja mejor.\n📚 De qué hablo aquí #Historias reales, números concretos y lecciones aprendidas. Nada de teoría de manual. Solo lo que he visto funcionar — y lo que he visto fracasar.\nHablo de inteligencia artificial aplicada al workflow, de consultoría IT y sus costes ocultos, de smart working como ventaja competitiva. Cada artículo nace de una experiencia real — la mía.\nNo hacen falta revoluciones. Hacen falta decisiones precisas, implementadas con método.\nY la capacidad de decir \u0026ldquo;no\u0026rdquo; a quien te vende complejidad cuando la solución es simple.\n","date":null,"permalink":"https://ivanluminaria.com/es/posts/project-management/","section":"Database Strategy","summary":"\u003cp\u003eHe visto a project managers hacer llorar a desarrolladores senior en una reunión. He visto equipos brillantes destruidos por PMs que confundían la autoridad con el autoritarismo. He visto software entregado \u0026ldquo;a tiempo\u0026rdquo; que no funcionaba, y proyectos de millones de euros acabados en nada.\u003c/p\u003e\n\u003cp\u003eY he visto lo contrario: equipos pequeños, autónomos, respetados — que construían sistemas sólidos en una fracción del tiempo y del presupuesto.\u003c/p\u003e\n\u003cp\u003eLa diferencia nunca fue la tecnología. Siempre fue \u003cstrong\u003eel método\u003c/strong\u003e.\u003c/p\u003e","title":"Project Management"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/project-management/","section":"Tags","summary":"","title":"Project-Management"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/strategy/","section":"Tags","summary":"","title":"Strategy"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/consulting/","section":"Tags","summary":"","title":"Consulting"},{"content":"Un data warehouse no es una base de datos con tablas más grandes.\nEs una forma diferente de pensar los datos — orientada al análisis, a la historia, a las decisiones.\nLa diferencia entre un DWH que funciona y uno que se convierte en un problema está casi siempre en el modelo. Tablas de hechos con la granularidad equivocada, dimensiones mal diseñadas, jerarquías que no soportan las consultas de agregación. Problemas que no se ven en fase de desarrollo, pero explotan cuando el negocio pide reportes que el modelo no puede entregar.\nEn esta sección comparto casos reales de diseño y reestructuración de data warehouses: modelado dimensional, jerarquías balanceadas, slowly changing dimensions, estrategias de carga. No teoría del libro de Kimball, sino soluciones aplicadas en producción sobre sistemas que sirven decisiones empresariales reales.\nPorque un data warehouse no se construye para contener datos.\nSe construye para responder preguntas.\n","date":null,"permalink":"https://ivanluminaria.com/es/posts/data-warehouse/","section":"Database Strategy","summary":"\u003cp\u003eUn data warehouse no es una base de datos con tablas más grandes.\u003cbr\u003e\nEs una forma diferente de pensar los datos — orientada al análisis, a la historia, a las decisiones.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eLa diferencia entre un DWH que funciona y uno que se convierte en un problema está casi siempre en el modelo. Tablas de hechos con la granularidad equivocada, dimensiones mal diseñadas, jerarquías que no soportan las consultas de agregación. Problemas que no se ven en fase de desarrollo, pero explotan cuando el negocio pide reportes que el modelo no puede entregar.\u003cbr\u003e\u003c/p\u003e","title":"Data Warehouse"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/european-union/","section":"Tags","summary":"","title":"European-Union"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/freelance/","section":"Tags","summary":"","title":"Freelance"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/italy/","section":"Tags","summary":"","title":"Italy"},{"content":"Oracle es la base de datos que me formó profesionalmente.\nTrabajo con ella desde 1996, y en casi treinta años he visto pasar versiones, paradigmas y modas — pero el corazón del motor ha seguido siendo el mismo: sólido, complejo, despiadado con quien no lo conoce a fondo.\nHe gestionado instancias de unos pocos cientos de usuarios y data warehouses de miles de millones de filas. Configuré Data Guard cuando aún se llamaba standby database, escribí PL/SQL cuando depurar significaba DBMS_OUTPUT y paciencia, diseñé esquemas de particionamiento antes de que se convirtieran en una feature de marketing.\nOracle no es una base de datos que se aprende con tutoriales.\nSe aprende con incidentes, con migraciones a las tres de la madrugada, con planes de ejecución que cambian tras una actualización de estadísticas.\nEn esta sección cuento lo que he aprendido en el campo: arquitectura, seguridad, rendimiento y las decisiones de diseño que separan una instalación que funciona de una que simplemente sobrevive.\nPorque con Oracle no basta conocer la sintaxis.\nHay que entender cómo razona el motor.\n","date":null,"permalink":"https://ivanluminaria.com/es/posts/oracle/","section":"Database Strategy","summary":"\u003cp\u003eOracle es la base de datos que me formó profesionalmente.\u003cbr\u003e\nTrabajo con ella desde 1996, y en casi treinta años he visto pasar versiones, paradigmas y modas — pero el corazón del motor ha seguido siendo el mismo: sólido, complejo, despiadado con quien no lo conoce a fondo.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eHe gestionado instancias de unos pocos cientos de usuarios y data warehouses de miles de millones de filas. Configuré Data Guard cuando aún se llamaba standby database, escribí PL/SQL cuando depurar significaba DBMS_OUTPUT y paciencia, diseñé esquemas de particionamiento antes de que se convirtieran en una feature de marketing.\u003cbr\u003e\u003c/p\u003e","title":"Oracle"},{"content":"La primera vez que trabajé con un cliente internacional, me pasó algo extraño. Me pagaron a treinta días.\nNo treinta días desde fin de mes. No treinta días desde la fecha de recepción de la factura protocolizada y visada por el responsable administrativo. Treinta días desde la factura. Punto.\nRevisé el extracto bancario dos veces. Pensé que era un error.\nNo era un error. Era la normalidad — solo que no era la normalidad italiana.\n🇮🇹 La normalidad italiana: esperar es parte del trabajo #En Italia, si eres consultor IT como autónomo, el ciclo de pago funciona más o menos así:\nTrabajas en octubre. Facturas a finales de octubre. La factura entra en el ciclo administrativo del cliente en noviembre. El cliente paga a \u0026ldquo;60 días fin de mes\u0026rdquo; — que en la práctica significa finales de enero. Si todo va bien. Si no hay bloqueo de pagos de fin de año. Si la oficina administrativa no ha \u0026ldquo;perdido\u0026rdquo; la factura. Si el responsable ha firmado la aprobación. Resultado: trabajas en octubre, ves el dinero en febrero. Cuatro meses.\nY no estoy hablando de situaciones patológicas. Estoy hablando de la práctica contractual estándar en la consultoría IT italiana. Contratos que dicen negro sobre blanco \u0026ldquo;pago a 60 días fecha factura fin de mes\u0026rdquo; o, peor, \u0026ldquo;90 días fecha factura fin de mes.\u0026rdquo;\nHe visto contratos a 120 días. Ciento veinte días. Cuatro meses declarados por contrato, que en la realidad se convierten en cinco o seis. Firmados sin pestañear, porque \u0026ldquo;así funciona\u0026rdquo; y porque el consultor que protesta es el consultor al que no vuelven a llamar.\n🇪🇺 Qué dice Europa (y qué Italia finge no escuchar) #La Directiva Europea 2011/7/UE sobre la lucha contra la morosidad en las operaciones comerciales es clara. Cristalina, diría:\nRegla Qué prevé Plazo estándar 30 días desde la fecha de factura Plazo máximo entre empresas 60 días (solo con acuerdo explícito y si no es gravemente injusto) Plazo para la Administración Pública 30 días (ampliable a 60 solo en casos excepcionales) Intereses de demora automáticos Tipo BCE + 8% — sin necesidad de requerimiento formal Compensación fija por recuperación 40€ mínimo por cada factura pagada con retraso Treinta días. No noventa. No ciento veinte. Treinta.\nLa directiva fue transpuesta al derecho italiano con el Decreto Legislativo 231/2002 (modificado en 2012). Sobre el papel, las reglas existen. En la práctica, es como si no existieran.\n🇩🇪 Cómo funciona en el resto de Europa #Cuando les cuento a mis colegas alemanes, holandeses o escandinavos que en Italia los plazos de pago estándar son 60-90 días, la reacción es siempre la misma: primero asombro, luego una risa nerviosa.\nEn Alemania el plazo de pago medio es de 24 días. No porque los alemanes sean más generosos — porque el sistema lo impone. Un pago más allá de los 30 días genera automáticamente intereses de demora. Las empresas lo saben y pagan.\nEn los Países Bajos el plazo medio es de 27 días. La asociación empresarial MKB-Nederland publica estadísticas anuales sobre retrasos, y las empresas que no respetan los plazos acaban en listas públicas.\nEn los países nórdicos — Suecia, Dinamarca, Finlandia — pagar a 14 días es normal. A 30 ya se considera largo.\n¿Y Italia? El plazo medio efectivo de pago en Italia es de 80 días según el European Payment Report. Ochenta. Casi tres veces la media europea.\nPaís Plazo medio de pago (días) Suecia 27 Alemania 24 Países Bajos 27 Francia 44 España 56 Italia 80 Plazo máximo Directiva UE 60 Italia no solo está fuera de escala respecto al norte de Europa. Está fuera de escala respecto a su propia ley.\n💰 El impacto real sobre quien trabaja #Pongamos un ejemplo concreto. Un consultor IT senior que factura 250€ al día, 220 días laborables al año.\nFacturación anual bruta: 55.000€.\nCon pagos a 30 días, el flujo de caja es manejable. Cada mes entra el trabajo del mes anterior. El consultor puede planificar, invertir, pagar sus impuestos sin quedar en números rojos.\nCon pagos a 90 días fin de mes, el panorama cambia radicalmente:\nMes Trabajo realizado Cobrado Crédito pendiente Enero 5.500€ 0€ 5.500€ Febrero 5.500€ 0€ 11.000€ Marzo 5.500€ 0€ 16.500€ Abril 5.500€ 0€ 22.000€ Mayo 5.500€ 5.500€ 22.000€ Durante los primeros cuatro meses del año el consultor trabaja a crédito. Dieciséis a veinte mil euros de trabajo realizado y no cobrado. Mientras tanto, los impuestos no esperan. Las cotizaciones a la seguridad social no esperan. El alquiler no espera.\nEse consultor está financiando a su cliente. Gratis. Sin intereses. Sin garantías.\nSi lo piensas, es un préstamo. Solo que nadie lo llama así. Lo llaman \u0026ldquo;condiciones contractuales.\u0026rdquo;\n🏦 El mecanismo perverso: quien paga financia a quien cobra #La paradoja es estructural. Las grandes empresas de consultoría — las que tienen cientos de empleados y facturaciones de siete cifras — negocian plazos largos con los proveedores (es decir, los consultores) y plazos más cortos con los clientes finales. La diferencia entre cobro y pago se convierte en un float financiero que la empresa usa como liquidez a coste cero.\nEl consultor freelance es el eslabón más débil de la cadena. No tiene poder de negociación, no tiene departamento legal, no tiene alternativas inmediatas. Acepta los 90 días porque el mercado funciona así y porque rechazar significa quedarse sin proyectos.\nHe visto situaciones aún más creativas:\nContratos que prevén \u0026ldquo;90 días desde la fecha de aprobación del parte de horas\u0026rdquo; — donde la aprobación llega con semanas de retraso Facturas \u0026ldquo;bloqueadas\u0026rdquo; por errores formales inventados, para trasladar el pago al ciclo siguiente Pagos fraccionados sin razón aparente, con el saldo final que llega después de seis meses No son excepciones. Son tácticas consolidadas. Cada consultor italiano con algo de experiencia las reconoce al instante.\n⚖️ Por qué nadie hace valer la ley #La pregunta legítima es: si la ley prevé 30 días y los intereses de demora son automáticos, ¿por qué nadie los reclama?\nLa respuesta es simple y amarga: porque el coste reputacional es más alto que el coste financiero.\nUn consultor que envía una reclamación formal de intereses de demora a su cliente es un consultor al que no volverán a llamar. No porque esté equivocado — tiene razón, legal y moralmente. Pero porque el mercado de la consultoría IT en Italia es un mercado de relaciones, y en un mercado de relaciones, quien hace valer sus derechos es percibido como \u0026ldquo;difícil.\u0026rdquo;\nEs el mismo mecanismo por el que nadie pide las horas extra pagadas, nadie rechaza el viaje del viernes por la noche y nadie cuestiona la tarifa que baja con cada renovación de contrato.\nEl sistema se sostiene sobre la docilidad estructural del consultor. Y funciona, mientras funciona.\n🛠️ Qué se puede hacer concretamente #No tengo soluciones mágicas. Pero tengo estrategias que uso desde hace años y que funcionan — o al menos limitan los daños.\n1. Negociar los plazos ANTES de firmar #Parece obvio, pero la mayoría de los consultores firma el contrato sin leer la cláusula de pago. El momento de negociar es antes, no después. Un \u0026ldquo;pago a 30 días fecha factura\u0026rdquo; escrito en el contrato vale más que cualquier protesta posterior.\n2. Incluir una cláusula explícita de intereses de demora #Aunque la ley los prevé automáticamente, escribirlos en el contrato tiene un efecto disuasorio. El cliente sabe que no estás bromeando. Yo uso una fórmula sencilla: \u0026ldquo;En caso de pago tardío se aplicarán intereses de demora conforme al Decreto Legislativo 231/2002, equivalentes al tipo del BCE más 8 puntos porcentuales.\u0026rdquo;\n3. Diversificar clientes #El consultor con un solo cliente es el consultor más vulnerable. Si el 100% de tu facturación depende de quien te paga a 120 días, no tienes capacidad de negociación. Si tienes tres clientes y uno paga con retraso crónico, puedes permitirte dejarlo.\n4. Evaluar al cliente también por la puntualidad de pago #Antes de aceptar un encargo, pregunta a los colegas. El mundo de la consultoría IT es pequeño. Quién paga mal se sabe. Quién paga bien, también. Yo mantengo una lista mental — y no es corta.\n5. Considerar clientes internacionales #No por antipatriotismo, sino por pragmatismo. Los clientes del norte de Europa pagan mejor, pagan antes y tienen procesos administrativos más transparentes. Con el teletrabajo, trabajar para una empresa holandesa desde Roma ya no es ciencia ficción. Es mi martes.\n📊 Una comparación que hace reflexionar #Tomemos al mismo consultor IT — mismas competencias, misma experiencia, mismo tipo de proyecto. Solo cambia el país del cliente.\n🇮🇹 Cliente italiano 🇩🇪 Cliente alemán Tarifa diaria 250€ 450€ Plazo de pago contractual 90 días fin de mes 30 días Pago efectivo medio ~120 días ~28 días Intereses de demora reclamados nunca (por miedo) no hacen falta (pagan puntual) Proceso de aprobación de factura laberíntico un email de confirmación Renovación de contrato \u0026ldquo;ya te diremos\u0026rdquo; planificada con 3 meses de antelación No digo que trabajar con clientes italianos sea siempre peor. Digo que los números cuentan una historia precisa, e ignorarla por no crear problemas no es profesionalidad. Es resignación.\n💬 Una cuestión de respeto #El retraso crónico en los pagos no es solo un problema financiero. Es un problema de respeto profesional.\nCuando una empresa paga a un consultor a 120 días, le está diciendo: \u0026ldquo;Tu tiempo y tu trabajo pueden esperar. Nuestros plazos van antes que los tuyos.\u0026rdquo;\nEs el mismo mensaje que transmiten cuando te piden empezar \u0026ldquo;el lunes\u0026rdquo; pero el contrato llega tres semanas después. Cuando el parte de horas debe completarse al minuto pero la factura puede quedarse en un cajón durante meses. Cuando el proyecto es urgentísimo pero el pago no.\nLlevo treinta años de consultoría a mis espaldas. He trabajado con clientes que me han pagado a 14 días y clientes que han tardado ocho meses. La calidad de la relación profesional nunca ha sido una cuestión de presupuesto. Siempre ha sido una cuestión de cómo tratan a quien trabaja para ellos.\nLos mejores clientes que he tenido pagaban puntualmente. No por generosidad — por organización. Porque una empresa que sabe gestionar sus pagos es una empresa que sabe gestionar sus proyectos. Y viceversa.\nQuien paga mal, casi siempre, gestiona mal también todo lo demás.\nGlosario #DSO — Days Sales Outstanding — número medio de días que una empresa tarda en cobrar sus créditos. En Italia la media es de 80 días, casi tres veces la media europea.\nFloat Financiero — Liquidez a coste cero generada por la diferencia entre los tiempos de cobro de los clientes y los tiempos de pago a los proveedores.\nIntereses de Demora — Intereses automáticos previstos por ley (tipo BCE + 8%) que se devengan sobre cada factura pagada con retraso, sin necesidad de requerimiento formal.\nPartita IVA — Régimen fiscal italiano para trabajadores autónomos, que en la consultoría IT implica asumir directamente el riesgo de crédito hacia los clientes.\nDirectiva 2011/7/UE — Directiva europea sobre morosidad que fija el plazo estándar en 30 días, el máximo en 60, y prevé intereses de demora automáticos.\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/es/posts/project-management/pagamenti-60-90-120-giorni/","section":"Database Strategy","summary":"\u003cp\u003eLa primera vez que trabajé con un cliente internacional, me pasó algo extraño. Me pagaron a treinta días.\u003c/p\u003e\n\u003cp\u003eNo treinta días desde fin de mes. No treinta días desde la fecha de recepción de la factura protocolizada y visada por el responsable administrativo. Treinta días desde la factura. Punto.\u003c/p\u003e\n\u003cp\u003eRevisé el extracto bancario dos veces. Pensé que era un error.\u003c/p\u003e\n\u003cp\u003eNo era un error. Era la normalidad — solo que no era la normalidad italiana.\u003c/p\u003e","title":"Pagos a 60-90-120 días: la normalidad italiana que no existe en Europa"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/payments/","section":"Tags","summary":"","title":"Payments"},{"content":"Descargar PDF | Perfil LinkedIn\nPerfil Profesional #Data Warehouse Architect y profesional IT con casi 30 años de experiencia en el diseño, implementación y gestión de soluciones DWH complejas y de alto rendimiento en entornos Oracle y PostgreSQL. Experto en metodologías de modelado multidimensional de datos (Kimball, Inmon) y en la optimización de procesos ETL/ELT y consultas SQL sobre datasets que van de cientos de millones a miles de millones de filas. Capacidad demostrada para liderar proyectos DWH de principio a fin — desde el análisis de requisitos hasta el despliegue en producción — garantizando la integridad, calidad y disponibilidad de los datos para apoyar las decisiones de negocio. Liderazgo técnico y mentalidad orientada a la resolución de problemas en contextos internacionales y full-remote.\nCompetencias Técnicas # Metodologías DWH: Modelado Multidimensional de Datos (Kimball, Inmon), Star Schema, Snowflake Schema, Slowly Changing Dimensions (SCD Type 1/2/3), Bus Matrix design. Oracle Databases: Oracle Database (de 8i a 21c), Oracle Exadata, Oracle RAC, Oracle Data Guard, Oracle Autonomous Database (ADB), Performance Tuning (AWR, ADDM, SQL Tuning Advisor), Storage Management (ASM), Backup \u0026amp; Recovery (RMAN), Oracle TDE. PostgreSQL: PostgreSQL (14+), Query Optimization, Table Partitioning, pg_stat_statements, PgBouncer, Logical Replication, VACUUM/Autovacuum tuning. Cloud: Oracle Cloud Infrastructure (OCI). Herramientas ETL/ELT: Pipelines ETL basadas en PL/SQL, Unix Shell Scripting, Oracle Data Integrator (ODI), Oracle Warehouse Builder (OWB, proyectos legacy). Business Intelligence \u0026amp; Reporting: Oracle Analytics Cloud (OAC) — Semantic Model Designer, Reports, Dashboards. Lenguajes de Programación y Scripting: SQL (avanzado), PL/SQL, Unix Shell Scripting. Sistemas Operativos: Linux (RHEL, CentOS, Oracle Linux), Unix, Windows Server. Otros: Project Management (Agile/Scrum), Team Leadership (hasta 7 personas), Formación Técnica. Experiencia Profesional #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Data Warehouse Architect | Oracle \u0026amp; PostgreSQL Expert | Administrador Único | 2021 – Presente\nDWH Architect (para ATRADIUS) | 2022 – 2026:\nDiseño del Data Warehouse de la división Surety para la consolidación de datos procedentes de Italia, España, Francia y países del norte de Europa. Integración de fuentes heterogéneas — bases de datos Oracle, Microsoft SQL Server y archivos planos de sistemas externos — en un DWH unificado basado en Oracle. Modelado de los dominios de negocio principales: cartera de clientes, pólizas, contratos, facturación, siniestros y transacciones sobre siniestros. Desarrollo del modelo de datos completo y la capa ETL — más de 60.000 líneas de código PL/SQL — con un sistema de monitorización de cargas en tiempo real. La ingestión diaria completa desde las tres fuentes se completa en menos de 2 horas. DWH Architect (para FAI SERVICE) | 2021 – 2023:\nDiseño de un modelo de datos Snowflake Schema en Oracle Analytics Cloud con procesos ETL ejecutándose sobre Oracle 19c en OCI. Desarrollo de dashboards y reportes en OAC para estadísticas de facturación, segmentación de clientes, análisis del portafolio y seguimiento de costes/ingresos. Diseño y Arquitectura DWH (Banking, Telepass y otros clientes):\nDefinición e implementación de arquitecturas Data Warehouse para clientes del sector bancario y socios de Telepass, siguiendo las metodologías Kimball e Inmon. Aplicación del modelado multidimensional (Star Schema, Snowflake) para optimizar análisis y reporting sobre datasets superiores a 2.000 millones de filas. Diseño y desarrollo de flujos ETL/ELT para la integración de datos de más de 15 fuentes heterogéneas. Diseño e implementación de soluciones DWH sobre PostgreSQL como alternativas cost-effective a las arquitecturas Oracle, incluyendo estrategias de particionamiento y optimización del rendimiento de las consultas. Gestión y Optimización de Bases de Datos Oracle:\nAdministración avanzada, tuning y optimización del rendimiento de bases de datos Oracle, incluyendo entornos OCI y Autonomous Database. Optimización de consultas SQL complejas — reducción de tiempos de procesamiento batch de 4 horas a menos de 30 minutos en cargas de trabajo analíticas críticas. Liderazgo y Consultoría:\nOrientación técnica y formación para equipos internos y clientes sobre las mejores prácticas DWH y Oracle/PostgreSQL. Instalación y patching de bases de datos Oracle, gestión de Oracle OEM y RMAN. Desarrollo de reportes y dashboards con Oracle Analytics Cloud (OAC). NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Oracle DBA | DWH Architect | Oracle Performance \u0026amp; Tuning Expert (para TIM / HUAWEI) | 2020 – 2022\nAdministración de Proyectos DWH/DBA:\nGestión y administración de más de 30 bases de datos Oracle críticas (70+ instancias) en clusters Oracle Exadata (3 y 5 nodos) para un importante cliente Telco. Responsable de la disponibilidad 24/7 de los sistemas de bases de datos que soportan más de 20 millones de abonados móviles prepago. Gestión de tablas de hechos con ingestión de hasta 800 millones de registros de tráfico telefónico por día, requiriendo estrategias avanzadas de particionamiento y compresión. Performance Tuning Avanzado:\nAnálisis en profundidad del rendimiento mediante AWR, ADDM y tuning proactivo para garantizar SLAs por debajo de 500ms de tiempo de respuesta en consultas críticas. Implementación de estrategias de indexación, particionamiento y compresión para mejorar el rendimiento del sistema DWH. Gestión de la seguridad de los datos con Oracle TDE (Transparent Data Encryption). IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote) #PL/SQL Expert | Oracle DBA \u0026amp; Tuning Expert (para FINWAVE S.p.A.) | 2020 – 2022\nDesarrollo avanzado de PL/SQL y optimización de consultas para aplicaciones financieras que procesan millones de transacciones diarias. Consultoría sobre arquitecturas Oracle y mejores prácticas de performance tuning. PROFESIONAL INDEPENDIENTE / CONSULTOR — Roma, Italia (Full Remote Europa) #Oracle DBA | Oracle Performance \u0026amp; Tuning Expert | DWH Architect | 2013 – 2020\nDiseño y desarrollo de Data Warehouses para clientes de los sectores bancario, asegurador y telecomunicaciones, aplicando metodologías Kimball/Inmon sobre plataformas Oracle y PostgreSQL. Desarrollo de procesos ETL/ELT para la carga de datos DWH — construcción de pipelines que gestionan más de 500 millones de filas por ciclo de carga. Consultoría especializada en bases de datos Oracle y PostgreSQL, SQL performance tuning, arquitecturas DWH, PL/SQL y diseño ETL. Liderazgo de equipos (3-7 personas) en contextos multiculturales, gestión de actividades y prioridades con metodología Agile. Creación de reportes y análisis de datos con Oracle Analytics Cloud (OAC). AUSELDA AED GROUP S.P.A. — Roma, Italia #Data Warehouse Architect | Performance \u0026amp; Tuning Expert | Oracle Project DBA (para la Administración Pública) | 2009 – 2013\nDiseño y modelado Data Warehouse (Kimball/Inmon) para entidades de la Administración Pública. Desarrollo de procesos ETL/ELT y optimización de consultas SQL complejas. Especialista del producto Oracle Warehouse Builder (OWB). Gestión técnica de proyectos DWH y formación de usuarios. ORACLE ITALIA S.R.L. — Varias sedes, Italia \u0026amp; Madrid, España #Data Warehouse Architect | Oracle DBA | DWH Designer | SQL \u0026amp; PL/SQL Developer | Training Specialist | 1999 – 2009\nRoles Arquitecturales y de Desarrollo DWH (2001-2009):\nDiseño y desarrollo de Data Warehouses para clientes líderes en Telco (TIM, Vodafone, TRE), Finanzas (Banca d\u0026rsquo;Italia, Generali, RAS), Farmacéutico (Menarini) y otros sectores. Implementación de modelos de datos (Kimball/Inmon) y procesos ETL/ELT con Oracle Warehouse Builder. Consultoría en SQL Performance \u0026amp; Tuning, PL/SQL, BI Reports (Oracle Discoverer, HTMLDB), Oracle OLAP. Experiencia internacional con Vodafone España (Madrid). Training Specialist (2000-2001):\nImpartición de cursos Oracle: SQL (Básico y Avanzado), PL/SQL (Básico y Avanzado), Oracle Database Administration, Performance and Tuning, Oracle Discoverer, Forms, Reports. Web Developer | Oracle SQL \u0026amp; PL/SQL Developer (ETNOTEAM S.P.A. - 1999): Desarrollo de portales web y aplicaciones cliente-servidor.\nS.EL.DAT. S.P.A. — Roma, Italia #Software Developer (para Telecom, Rover Italia) | 1997 – 1999\nDesarrollo de aplicaciones cliente-servidor, Junior Oracle DBA, monitorización de BD. Formación # Facultad de Ingeniería Informática (Ingeniería del Software) | Università degli Studi Roma Tre, Roma | 1994 – 2000 Diploma de Bachillerato Científico (EQF Nivel 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Inglés Avanzado (C1/C2) | The British Council (Nivel 4A), Roma | 2003 – 2004 Cursos de Formación y Actualización Seleccionados:\nScrum Agile — Randstad/Forma.temp (Mayo 2024) Project Management — Randstad/Forma.temp (Mayo 2024) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Abril 2021) Data Science on Google Cloud Platform: Designing Data Warehouses — LinkedIn Learning (Septiembre 2020) Cursos de especialización Oracle 12c (Administration, Security, Backup and Recovery, Advanced SQL, Performance Optimization) — LinkedIn Learning (2020) MySQL Installation and Configuration — LinkedIn Learning (Agosto 2020) Learning Git and GitHub — LinkedIn Learning (Agosto 2020) Idiomas # Italiano: Lengua materna Inglés: C1/C2 (Fluido, profesional) Español: C1 (Fluido) Rumano: C1 (Fluido) Francés: A1/A2 (Básico) Competencias Transversales # Resolución de problemas analítica y creativa Trabajo en equipo y colaboración en contextos internacionales Project Management (Definición de requisitos, Priorización, Diagramas de Gantt, ERD) Comunicación eficaz y gestión de stakeholders Autorizo el tratamiento de mis datos personales conforme al Art. 13 del Reglamento UE 2016/679 (RGPD).\nRoma, Marzo 2026\nDescargar PDF | Perfil LinkedIn | Volver a la pagina anterior\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/es/resumes/dwh-architect/","section":"Know-How \u0026 Impact","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_DWH_Architect_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eDescargar PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003ePerfil LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"perfil-profesional\" class=\"relative group\"\u003ePerfil Profesional \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perfil-profesional\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eData Warehouse Architect y profesional IT con casi 30 años de experiencia en el diseño, implementación y gestión de soluciones DWH complejas y de alto rendimiento en entornos Oracle y PostgreSQL. Experto en metodologías de modelado multidimensional de datos (Kimball, Inmon) y en la optimización de procesos ETL/ELT y consultas SQL sobre datasets que van de cientos de millones a miles de millones de filas. Capacidad demostrada para liderar proyectos DWH de principio a fin — desde el análisis de requisitos hasta el despliegue en producción — garantizando la integridad, calidad y disponibilidad de los datos para apoyar las decisiones de negocio. Liderazgo técnico y mentalidad orientada a la resolución de problemas en contextos internacionales y full-remote.\u003c/p\u003e","title":"Data Warehouse Architect"},{"content":"Descargar PDF | Perfil LinkedIn\nPerfil Profesional #Senior Oracle DBA y Performance Tuning Expert con casi 30 anos de experiencia especializada en la administracion, optimizacion y gestion de bases de datos Oracle complejas y de mision critica, incluyendo entornos Exadata, RAC y Oracle Cloud (OCI, Autonomous Database). Profundo conocimiento en analisis de rendimiento (AWR, ADDM, ASH), optimizacion de consultas SQL complejas, tuning de instancias y resolucion de problemas de rendimiento. Conocimientos fundamentales en practicas relacionadas con backup \u0026amp; recovery (RMAN), seguridad (TDE), instalacion, patching, migraciones y gestion de almacenamiento (ASM), siendo el performance tuning el area de especializacion principal y en profundidad, crucial para la integridad, el rendimiento y la contribucion a la alta disponibilidad de los sistemas Oracle en entornos corporativos exigentes e internacionales.\nCompetencias Tecnicas — Oracle DBA \u0026amp; Performance Tuning # Administracion de Oracle Database: Oracle Database (desde 8i hasta 21c, Autonomous), Oracle Exadata, Oracle RAC (Real Application Clusters), Oracle Data Guard, Oracle GoldenGate (conocimiento basico). Performance Tuning Avanzado: Analisis y Diagnostico: AWR, ADDM, ASH, Statspack, SQL Trace, TKPROF, Explain Plan. SQL Tuning: Optimizacion de consultas complejas, Hints, SQL Profiles, SQL Plan Management (SPM). Instance Tuning: Memory Management (SGA, PGA), Initialization Parameters, Wait Events Analysis. Diseno de Base de Datos para el Rendimiento: Indexing (B-tree, Bitmap, Function-based), Partitioning (Range, List, Hash, Composite), Compression. Alta Disponibilidad y Disaster Recovery: RMAN (Backup, Recovery, Cloning), Oracle Data Guard, Flashback Technologies. Seguridad de Base de Datos: Oracle TDE (Transparent Data Encryption), Gestion de Usuarios y Privilegios, Auditing. Gestion de Almacenamiento: ASM (Automatic Storage Management), Tablespace Management. Instalacion, Patching y Migraciones: Instalacion de nuevas instancias, aplicacion de PSU/CPU/RU, actualizaciones de version, migraciones cross-platform. Herramientas Oracle: Oracle Enterprise Manager (OEM) Cloud Control, SQL Developer, SQL*Plus, Toad. Scripting: PL/SQL, SQL, Unix Shell Scripting (para automatizacion de tareas DBA). Cloud: Oracle Cloud Infrastructure (OCI) — Compute, Storage, Networking, Database Services (VM DB, Bare Metal, Exadata CS, Autonomous Database). Otras Tecnologias de Base de Datos: PostgreSQL (administracion, performance tuning, particionado, replicacion), MySQL (administracion, configuracion, replicacion, optimizacion InnoDB). Sistemas Operativos: Linux (Red Hat, Oracle Linux), Unix (AIX, Solaris), Windows Server. Experiencia Profesional #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Senior Oracle DBA \u0026amp; Performance Tuning Expert / DWH Architect | Administrador Unico | 2021 – Presente\nDBA MySQL \u0026amp; PostgreSQL (para POSTE ITALIANE) | Jul 2025 – Presente:\nAdministracion y gestion de aproximadamente 1.500 instancias MySQL y PostgreSQL en entornos de produccion, staging y desarrollo. Monitoreo del rendimiento, query tuning, gestion de replicacion y planificacion de capacidad a escala enterprise. Oracle DBA \u0026amp; Tuning Expert (para GENERALI Assicurazioni) | Feb 2024 – May 2025:\nAdministracion de bases de datos Oracle y performance tuning avanzado para aplicaciones del sector asegurador. Analisis AWR/ADDM, optimizacion SQL y resolucion proactiva de cuellos de botella en bases de datos de 500GB a 8TB. Oracle DBA (para ATRADIUS) | 2022 – 2026:\nAdministracion y performance tuning de bases de datos de soporte al Data Warehouse de la division Surety para la consolidacion de datos de Italia, Espana, Francia y paises del norte de Europa. Gestion de bases de datos Oracle en entornos OCI, soportando mas de 60.000 lineas de codigo PL/SQL ETL con ingestion diaria completa en menos de 2 horas. Oracle DBA (para FAI SERVICE) | 2021 – 2023:\nAdministracion y tuning de bases de datos Oracle 19c en OCI para procesos ETL y dashboards de Oracle Analytics Cloud. DBA \u0026amp; Performance Tuning (Banking, Telepass y otros clientes):\nOptimizacion de bases de datos Oracle en entornos OCI y Autonomous Database — reduccion de tiempos de procesamiento batch de 4 horas a menos de 30 minutos en cargas de trabajo analiticas criticas. Diseno y desarrollo de flujos ETL/ELT para la integracion de datos de mas de 15 fuentes heterogeneas en datasets superiores a 2.000 millones de filas. Gestion RMAN, monitoreo Oracle OEM, instalacion y patching de bases de datos Oracle. Diseno e implementacion de soluciones DWH sobre PostgreSQL como alternativas cost-effective a las arquitecturas Oracle. NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Senior Oracle DBA \u0026amp; Performance Tuning Expert (para TIM / HUAWEI) | 2020 – 2022\nAdministracion y gestion de mas de 30 bases de datos Oracle criticas (70+ instancias) en clusters Oracle Exadata (3/5 nodos) para un cliente Telco lider. Responsabilidad directa del performance tuning avanzado: analisis AWR/ADDM, optimizacion SQL, gestion de indices, partitioning y compression. Participacion en actividades de gestion de almacenamiento (ASM) e implementacion de Oracle TDE para la seguridad de los datos. Soporte \u0026ldquo;ON-CALL\u0026rdquo; 24/7 para la resolucion de incidencias criticas y el mantenimiento de la alta disponibilidad. PROFESIONAL INDEPENDIENTE / CONSULTOR — Roma, Italia (Full Remote Europa) #Senior Oracle DBA \u0026amp; Performance Tuning Expert / DWH Architect | 2013 – 2020\nPrestacion de servicios de consultoria como Oracle DBA y especialista en Performance Tuning para diversos clientes. Optimizacion de consultas SQL complejas y tuning de instancias Oracle para mejorar el rendimiento de aplicaciones criticas. Soporte en instalacion, configuracion, patching y actualizacion de bases de datos Oracle. Consultoria sobre estrategias de backup y recovery con RMAN. Diseno e implementacion de configuraciones Oracle Data Guard para alta disponibilidad y disaster recovery, incluyendo procedimientos de switchover/failover. Gestion de pequenos equipos tecnicos en proyectos de migracion y actualizacion. AUSELDA AED GROUP S.P.A. — Roma, Italia #Project Oracle DBA / Performance \u0026amp; Tuning Expert (para Administracion Publica) | 2009 – 2013\nAdministracion y optimizacion de bases de datos Oracle que soportan aplicaciones de la Administracion Publica. Tuning de consultas SQL y procesos ETL para sistemas de Data Warehousing. Participacion en actividades de instalacion, patching y gestion de la seguridad de bases de datos. ORACLE ITALIA S.R.L. — Diversas Localidades, Italia y Madrid, Espana #Oracle DBA / DWH Architect / SQL \u0026amp; PL/SQL Developer / Training Specialist | 1999 – 2009\nRoles de DBA y Performance (progresivamente crecientes): Administracion de bases de datos Oracle para clientes enterprise (TIM, Vodafone, Banca d\u0026rsquo;Italia, Generali). Participacion en actividades de SQL Performance \u0026amp; Tuning, troubleshooting y optimizacion. Soporte para la instalacion y configuracion de instancias Oracle, gestion de parches. Como Training Specialist (2000-2001): Imparticion de cursos sobre Oracle Database Administration y Performance \u0026amp; Tuning. S.EL.DAT. S.P.A. — Roma, Italia #Software Developer (para Telecom, Rover Italia) | 1997 – 1999\nDesarrollo de aplicaciones cliente-servidor, Junior Oracle DBA, monitorizacion de BD. Formacion Academica y Profesional # Facultad de Ingenieria Informatica (Ingenieria del Software) | Universidad Roma Tre, Roma | 1994 – 2000 Diploma de Bachillerato Cientifico (EQF Nivel 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Ingles Avanzado (C1/C2) | The British Council (Level 4A), Roma | 2003 – 2004 Cursos de Formacion Continua Seleccionados:\nAdvanced SQL for Query Tuning and Performance Optimization — LinkedIn Learning (Agosto 2020) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Abril 2021) Cursos de especializacion Oracle 12c (Administration, Security, Backup and Recovery, Advanced SQL, New Features) — LinkedIn Learning (2020) Idiomas # Italiano: Lengua materna Ingles: C1/C2 (Fluido, profesional) Espanol: C1 (Fluido) Rumano: C1 (Fluido) Frances: A1/A2 (Basico) Habilidades Interpersonales # Resolucion de Problemas de Forma Analitica y Metodica Gestion de Prioridades y Cumplimiento de Plazos Capacidad de Trabajo Bajo Presion Comunicacion Tecnica Clara y Eficaz Atencion al Detalle y Precision Aprendizaje Continuo y Adaptabilidad Tecnologica Autorizo el tratamiento de mis datos personales conforme al Art. 13 del Reglamento UE 2016/679 (RGPD).\nRoma, Marzo 2026\nDescargar PDF | Perfil LinkedIn | Volver a la pagina anterior\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/es/resumes/oracle-dba/","section":"Know-How \u0026 Impact","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_Oracle_DBA_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eDescargar PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003ePerfil LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"perfil-profesional\" class=\"relative group\"\u003ePerfil Profesional \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perfil-profesional\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSenior Oracle DBA y Performance Tuning Expert con casi 30 anos de experiencia especializada en la administracion, optimizacion y gestion de bases de datos Oracle complejas y de mision critica, incluyendo entornos Exadata, RAC y Oracle Cloud (OCI, Autonomous Database). Profundo conocimiento en analisis de rendimiento (AWR, ADDM, ASH), optimizacion de consultas SQL complejas, tuning de instancias y resolucion de problemas de rendimiento. Conocimientos fundamentales en practicas relacionadas con backup \u0026amp; recovery (RMAN), seguridad (TDE), instalacion, patching, migraciones y gestion de almacenamiento (ASM), siendo el performance tuning el area de especializacion principal y en profundidad, crucial para la integridad, el rendimiento y la contribucion a la alta disponibilidad de los sistemas Oracle en entornos corporativos exigentes e internacionales.\u003c/p\u003e","title":"Oracle DBA \u0026 Performance Tuning Expert"},{"content":"Descargar PDF | Perfil LinkedIn\nPerfil Profesional #Senior Oracle PL/SQL Developer con casi 30 anos de experiencia en el diseno, desarrollo, testing y optimizacion de codigo PL/SQL robusto y eficiente para aplicaciones intensivas en datos y sistemas de Data Warehouse. Profundo conocimiento en la creacion de packages, procedures, functions, triggers y types complejos, con un enfoque constante en el rendimiento, la mantenibilidad y la calidad del codigo. Experto en la optimizacion de consultas SQL complejas y en la gestion de grandes volumenes de datos. Habil en la traduccion de requisitos de negocio en logica de aplicacion de alto rendimiento y escalable dentro de la base de datos Oracle. Solida trayectoria tambien como Oracle DBA y DWH Architect, proporcionando una vision integral del ciclo de vida de los datos.\nCompetencias Tecnicas — Desarrollo Oracle PL/SQL # Lenguajes: PL/SQL (Avanzado), SQL (Avanzado, incluyendo Dynamic SQL, Analytic Functions, CTEs). Desarrollo PL/SQL: Packages, Procedures, Functions, Triggers. PL/SQL Data Types (Records, Collections, Object Types). Gestion de Errores y Excepciones. Bulk Processing (FORALL, BULK COLLECT). Dynamic SQL (DBMS_SQL, Execute Immediate). Optimizacion de Codigo PL/SQL (incl. uso de PL/SQL Hierarchical Profiler). Interaccion con Objetos de Base de Datos (Tables, Views, Sequences, Synonyms). Optimizacion SQL \u0026amp; Rendimiento: Analisis de Planes de Ejecucion (Explain Plan), SQL Trace, TKPROF. Tecnicas de SQL Tuning (Hints, Query Rewriting, Indexes). Comprension del impacto del diseno de base de datos en el rendimiento PL/SQL. Herramientas de Desarrollo: SQL Developer, Toad, SQL*Plus. Oracle Database: Oracle Database (desde 8i hasta 21c, Autonomous Database). Conceptos Relacionados: Data Warehousing (desarrollo de logica ETL/ELT), Data Integration, Modelado de Datos Relacional y Multidimensional. Control de Versiones: Git, GitHub. Scripting: Unix Shell Scripting (para automatizacion de despliegues y gestion de scripts). Cloud: Oracle Cloud Infrastructure (OCI) — conocimiento de servicios de base de datos. Experiencia Profesional #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Senior Oracle PL/SQL Developer \u0026amp; DWH Architect | 2022 – Presente\nPL/SQL Developer (para ATRADIUS) | 2022 – 2026:\nDesarrollo y mantenimiento de mas de 60.000 lineas de codigo PL/SQL (packages, procedures, functions) para el Data Warehouse de la division Surety, consolidando datos de seguros y creditos de Italia, Espana, Francia y paises del Norte de Europa. Diseno de templates PL/SQL reutilizables para procedimientos de carga de datos — estandarizacion del workflow ETL interno con checkpoints integrados para el seguimiento y monitorizacion en tiempo real de los flujos de carga, permitiendo a desarrolladores junior seguir un patron consistente y repetible. Implementacion de monitorizacion en tiempo real de las cargas mediante packages PL/SQL de logging personalizados, con visibilidad inmediata sobre el estado de las pipelines ETL y gestion de errores en todas las fases de carga. Optimizacion del rendimiento batch: reduccion del ciclo de ingestion diaria completa de 4+ horas a menos de 2 horas mediante reescritura de consultas, patrones BULK COLLECT/FORALL y DML partition-aware. PL/SQL Developer (para FINWAVE S.p.A.) | 2020 – 2022:\nDesarrollo de packages PL/SQL para aplicaciones de procesamiento de transacciones financieras que gestionan millones de operaciones diarias para clientes bancarios y de seguros. Optimizacion avanzada de consultas y tuning de codigo PL/SQL para pipelines de datos financieros de alto volumen. PL/SQL Developer (para FAI SERVICE) | 2021 – 2023:\nDesarrollo de procedimientos ETL en PL/SQL sobre Oracle 19c/OCI para flujos de datos de estadisticas de facturacion, segmentacion de clientes y seguimiento de costes/ingresos. Construccion de modulos PL/SQL que alimentan dashboards de Oracle Analytics Cloud con KPIs financieros agregados. Desarrollo PL/SQL (Banking, Telepass y otros clientes):\nDesarrollo de packages PL/SQL para logica de negocio en aplicaciones DWH del sector bancario, procesando datasets superiores a 2.000 millones de filas. Optimizacion de codigo PL/SQL y consultas SQL existentes — aplicacion de Hierarchical Profiler para identificar cuellos de botella y mejorar tiempos de ejecucion en rutas criticas. Colaboracion con equipos de desarrollo y analistas funcionales para la definicion de requisitos y el diseno de soluciones basadas en PL/SQL. NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Senior Oracle DBA \u0026amp; Performance Expert con Enfoque en Desarrollo (para TIM / HUAWEI) | 2020 – 2022\nSoporte especializado a equipos de desarrollo en la optimizacion de codigo PL/SQL y consultas SQL para aplicaciones criticas en bases de datos Exadata. Analisis y tuning de procesos batch PL/SQL de alto volumen. Desarrollo de scripts PL/SQL para tareas de monitorizacion y administracion. PROFESIONAL INDEPENDIENTE / CONSULTOR — Roma, Italia (Full Remote Europa) #Senior Oracle PL/SQL Developer \u0026amp; DBA / DWH Architect | 2013 – 2020\nDiseno y desarrollo de soluciones PL/SQL personalizadas para diversos clientes, incluyendo packages para logica ETL, procedimientos de procesamiento de datos y APIs PL/SQL. Optimizacion intensiva de codigo PL/SQL y SQL para mejorar el rendimiento de sistemas existentes. Desarrollo de modulos PL/SQL para la extraccion, transformacion y carga (ETL) de datos en sistemas DWH. Formacion y mentoring de desarrolladores junior en buenas practicas de desarrollo PL/SQL. AUSELDA AED GROUP S.P.A. — Roma, Italia #Oracle PL/SQL Developer \u0026amp; DWH Specialist (para Administracion Publica) | 2009 – 2013\nDesarrollo de componentes PL/SQL para sistemas de Data Warehousing y aplicaciones de gestion para la Administracion Publica. Mantenimiento evolutivo y correctivo de codigo PL/SQL. Optimizacion de procesos ETL basados en PL/SQL y OWB. ORACLE ITALIA S.R.L. — Diversas Localidades, Italia y Madrid, Espana #SQL \u0026amp; PL/SQL Developer / DWH Architect / DBA / Training Specialist | 1999 – 2009\nRoles de Desarrollo PL/SQL (significativos y crecientes): Desarrollo intensivo de codigo PL/SQL para proyectos de DWH, BI y aplicaciones personalizadas para clientes enterprise en diversos sectores (Telco, Finanzas, Farmaceutico). Creacion de packages PL/SQL para logica de negocio compleja, procedimientos de carga de datos (ETL) con Oracle Warehouse Builder y PL/SQL. Desarrollo de BI Reports e interfaces HTMLDB (Apex) con logica PL/SQL. Como Training Specialist (2000-2001): Imparticion de cursos Oracle SQL (Basico y Avanzado) y PL/SQL (Basico y Avanzado). ETNOTEAM S.P.A. — Roma, Italia #Web Developer / Oracle SQL \u0026amp; PL/SQL Developer | 1999\nDesarrollo de portales web y aplicaciones cliente-servidor con fuerte interaccion con bases de datos Oracle, utilizando SQL y PL/SQL para la logica backend. S.EL.DAT. S.P.A. — Roma, Italia #Software Developer / Junior DBA | 1997 – 1999\nDesarrollo de aplicaciones cliente-servidor con backend Oracle; primeras experiencias con SQL y PL/SQL. Formacion Academica y Profesional # Facultad de Ingenieria Informatica (Ingenieria del Software) | Universidad Roma Tre, Roma | 1994 – 2000 Diploma de Bachillerato Cientifico (EQF Nivel 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Ingles Avanzado (C1/C2) | The British Council (Level 4A), Roma | 2003 – 2004 Cursos de Formacion Continua Seleccionados:\nScrum Agile — Randstad/Forma.temp (Mayo 2024) Project Management — Randstad/Forma.temp (Mayo 2024) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Abril 2021) Advanced SQL for Query Tuning and Performance Optimization — LinkedIn Learning (Agosto 2020) Cursos de especializacion Oracle 12c (Advanced SQL, New Features) — LinkedIn Learning (2020) Learning Git and GitHub — LinkedIn Learning (Agosto 2020) Idiomas # Italiano: Lengua materna Ingles: C1/C2 (Fluido, profesional) Espanol: C1 (Fluido) Rumano: C1 (Fluido) Frances: A1/A2 (Basico) Habilidades Interpersonales # Enfoque Analitico y Orientacion a la Resolucion de Problemas Complejos Escritura de Codigo Claro, Eficiente y Mantenible Habilidades Avanzadas de Debugging y Troubleshooting Excelente Comprension de Requisitos Funcionales y Tecnicos Colaboracion Eficaz en Equipos de Desarrollo Atencion al Detalle y Calidad del Software Autorizo el tratamiento de mis datos personales conforme al Art. 13 del Reglamento UE 2016/679 (RGPD).\nRoma, Marzo 2026\nDescargar PDF | Perfil LinkedIn | Volver a la pagina anterior\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/es/resumes/oracle-plsql/","section":"Know-How \u0026 Impact","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_Oracle_PLSQL_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eDescargar PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003ePerfil LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"perfil-profesional\" class=\"relative group\"\u003ePerfil Profesional \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perfil-profesional\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSenior Oracle PL/SQL Developer con casi 30 anos de experiencia en el diseno, desarrollo, testing y optimizacion de codigo PL/SQL robusto y eficiente para aplicaciones intensivas en datos y sistemas de Data Warehouse. Profundo conocimiento en la creacion de packages, procedures, functions, triggers y types complejos, con un enfoque constante en el rendimiento, la mantenibilidad y la calidad del codigo. Experto en la optimizacion de consultas SQL complejas y en la gestion de grandes volumenes de datos. Habil en la traduccion de requisitos de negocio en logica de aplicacion de alto rendimiento y escalable dentro de la base de datos Oracle. Solida trayectoria tambien como Oracle DBA y DWH Architect, proporcionando una vision integral del ciclo de vida de los datos.\u003c/p\u003e","title":"Oracle PL/SQL Developer"},{"content":"Descargar PDF | Perfil LinkedIn\nPerfil Profesional #Project Manager con casi 30 anos de experiencia en TI y una solida base tecnica en entornos Data Warehouse y Oracle. Mas de 10 proyectos entregados con un excelente historial de cumplimiento de plazos, gestionando equipos de 3-7 personas en contextos multiculturales y remotos, en proyectos con presupuestos en el rango de €100K-€500K. Competencias concretas en planificacion, gestion de riesgos, coordinacion de recursos e interlocucion con stakeholders — desarrolladas en el campo coordinando actividades de desarrollo, release y mantenimiento para clientes en los sectores Bancario, Telco, Seguros y Administracion Publica. Metodologias Agile (Scrum) aplicadas en la gestion diaria de proyectos, con formacion certificada. Profunda base tecnica (arquitectura DWH, Oracle DBA, PL/SQL, ETL/ELT) que permite comunicarse eficazmente con los equipos de desarrollo, evaluar la viabilidad de las soluciones e identificar los riesgos tecnicos antes de que se conviertan en problemas.\nCompetencias Clave # Gestion de Proyectos y Metodologias: Planificacion de proyectos, definicion de hitos y seguimiento del avance. Gestion de riesgos y criticidades — identificacion proactiva y planes de mitigacion. Metodologias Agile y Scrum (Sprint Planning, Daily Stand-up, Retrospective, Backlog Refinement) — Formacion certificada. Definicion de requisitos, gestion del alcance e interlocucion con stakeholders. Planificacion de releases y coordinacion de entregas. Herramientas de Gestion de Proyectos y Productividad: Microsoft Project y Jira (planificacion, tracking, gestion de backlog). Microsoft Excel y Google Sheets (reporting, dashboards de proyecto, analisis de datos — uso diario). Git y GitHub (gestion de codigo, issue tracking, CI/CD, workflows colaborativos). Competencias Tecnicas de Soporte al PM: Arquitectura Data Warehouse (Kimball, Inmon, Google Cloud Platform). Oracle Database: DBA, Performance Tuning, PL/SQL. SQL avanzado, procesos ETL/ELT, Business Intelligence. Evaluacion de viabilidad tecnica y estimacion del esfuerzo de desarrollo. Liderazgo y Comunicacion: Coordinacion de equipos tecnicos distribuidos (3-7 personas, multi-pais). Comunicacion eficaz con equipos tecnicos, stakeholders de negocio y direccion. Mentoring y desarrollo de competencias del equipo. Facilitacion de reuniones y gestion de conflictos. Experiencia Profesional #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Project Manager \u0026amp; Senior DWH Architect | 2022 – Presente\nPM \u0026amp; DWH Lead (para GENERALI Seguros) | Feb 2024 – May 2025:\nCoordinacion de actividades de proyecto y gestion de prioridades para el equipo de desarrollo en bases de datos Oracle del sector asegurador. Interlocucion directa con el cliente para la recopilacion de requisitos, definicion del alcance y presentacion de soluciones. Monitorizacion del avance y gestion de criticidades en bases de datos de 500GB a 8TB. PM \u0026amp; DWH Lead (para ATRADIUS) | 2022 – 2026:\nGestion del proyecto de consolidacion de datos para la division Surety — coordinacion de la integracion de datos de 4 paises europeos (Italia, Espana, Francia, Norte de Europa). Planificacion de releases y gestion del backlog de desarrollo sobre mas de 60.000 lineas de codigo PL/SQL ETL. Tracking de actividades, reporting al stakeholder y gestion de dependencias entre equipos. Project Coordinator (Banking, Telepass y otros clientes):\nCoordinacion de proyectos con reduccion de tiempos de procesamiento batch de 4 horas a menos de 30 minutos. Gestion de la integracion de datos de mas de 15 fuentes heterogeneas en datasets superiores a 2.000 millones de filas. Planificacion y supervision de releases en entornos Oracle OCI y Autonomous Database. NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Senior Oracle DBA \u0026amp; Performance Tuning Expert (para TIM / HUAWEI) | 2020 – 2022\nPlanificacion y ejecucion de actividades de mantenimiento y patching en mas de 30 bases de datos Oracle criticas (70+ instancias) en clusters Exadata. Coordinacion con el equipo de desarrollo para optimizar las interacciones con la base de datos y resolver problemas de rendimiento — soporte tecnico especializado y priorizacion de intervenciones. Gestion autonoma de la carga de trabajo y actividades de tuning, con reporting al responsable de proyecto. PROFESIONAL INDEPENDIENTE / CONSULTOR — Roma, Italia (Full Remote Europa) #Project Manager \u0026amp; Senior DWH Consultant | 2013 – 2020\nGestion de aproximadamente 10 proyectos en 7 anos para clientes de los sectores Bancario, Telco y servicios, con presupuestos en el rango de €100K-€500K y un excelente historial de entregas puntuales. Coordinacion de equipos de 3-7 personas en contextos multiculturales y distribuidos — asignacion de tareas, facilitacion de la colaboracion y gestion de prioridades con enfoque iterativo Agile. Interlocucion directa con los clientes para la recopilacion de requisitos, definicion del alcance, presentacion de avances y gestion de expectativas. Formacion tecnica y mentoring para miembros del equipo — desarrollo de competencias y onboarding de nuevos consultores. AUSELDA AED GROUP S.P.A. — Roma, Italia #Senior Data Warehouse Specialist \u0026amp; Oracle DBA (para Administracion Publica) | 2009 – 2013\nColaboracion con los responsables de proyecto para la definicion de requisitos tecnicos, planificacion de actividades y validacion de soluciones. Coordinacion de actividades de desarrollo y optimizacion de Data Warehouses para entidades de la Administracion Publica. Soporte tecnico y formacion a usuarios sobre plataformas DWH. ORACLE ITALIA S.R.L. — Diversas Localidades, Italia y Madrid, Espana #Senior Consultant / DWH Specialist / Training Specialist | 1999 – 2009\nParticipacion en proyectos complejos de implementacion de DWH y BI para clientes principales (Telco, Finanzas, Farmaceutico), con responsabilidades crecientes en la coordinacion de actividades y el soporte a consultores junior. Gestion de relaciones con los referentes tecnicos del cliente y reporting sobre el avance de las actividades. Como Training Specialist (2000-2001): Imparticion de cursos tecnicos Oracle, gestion del aula y adaptacion de contenidos — competencias de presentacion y formacion directamente aplicables al rol de PM. Formacion Academica y Profesional # Facultad de Ingenieria Informatica (Ingenieria del Software) | Universidad Roma Tre, Roma | 1994 – 2000 Diploma de Bachillerato Cientifico (EQF Nivel 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Ingles Avanzado (C1/C2) | The British Council (Level 4A), Roma | 2003 – 2004 Cursos de Formacion Continua Seleccionados:\nProject Management — Randstad/Forma.temp (Mayo 2024) Scrum Agile — Randstad/Forma.temp (Mayo 2024) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Abril 2021) Data Science on Google Cloud Platform: Designing Data Warehouses — LinkedIn Learning (Septiembre 2020) Cursos de especializacion Oracle 12c (Administration, Security, Backup and Recovery, Advanced SQL, Performance Optimization) — LinkedIn Learning (2020) Learning Excel 2016 — LinkedIn Learning (Agosto 2020) Learning Git and GitHub — LinkedIn Learning (Agosto 2020) Idiomas # Italiano: Lengua materna Ingles: C1/C2 (Fluido, profesional) Espanol: C1 (Fluido) Rumano: C1 (Fluido) Frances: A1/A2 (Basico) Habilidades Interpersonales # Capacidad de traducir requisitos tecnicos en planes de proyecto concretos y gestionables Gestion simultanea de multiples proyectos con prioridades concurrentes Comunicacion eficaz a todos los niveles (equipo tecnico, stakeholders, direccion) Resolucion Analitica de Problemas y gestion proactiva de riesgos Experiencia de trabajo en equipos distribuidos, multiculturales y full-remote Mentoring y desarrollo de competencias del equipo Autorizo el tratamiento de mis datos personales conforme al Art. 13 del Reglamento UE 2016/679 (RGPD).\nRoma, Marzo 2026\nDescargar PDF | Perfil LinkedIn | Volver a la pagina anterior\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/es/resumes/project-manager/","section":"Know-How \u0026 Impact","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_Project_Manager_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eDescargar PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003ePerfil LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"perfil-profesional\" class=\"relative group\"\u003ePerfil Profesional \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perfil-profesional\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eProject Manager con casi 30 anos de experiencia en TI y una solida base tecnica en entornos Data Warehouse y Oracle. Mas de 10 proyectos entregados con un excelente historial de cumplimiento de plazos, gestionando equipos de 3-7 personas en contextos multiculturales y remotos, en proyectos con presupuestos en el rango de €100K-€500K. Competencias concretas en planificacion, gestion de riesgos, coordinacion de recursos e interlocucion con stakeholders — desarrolladas en el campo coordinando actividades de desarrollo, release y mantenimiento para clientes en los sectores Bancario, Telco, Seguros y Administracion Publica. Metodologias Agile (Scrum) aplicadas en la gestion diaria de proyectos, con formacion certificada. Profunda base tecnica (arquitectura DWH, Oracle DBA, PL/SQL, ETL/ELT) que permite comunicarse eficazmente con los equipos de desarrollo, evaluar la viabilidad de las soluciones e identificar los riesgos tecnicos antes de que se conviertan en problemas.\u003c/p\u003e","title":"Project Manager"},{"content":"Lunes por la mañana. Despertador a las 6:40. Ducha, desayuno rápido, llaves del coche en la mesa. Salgo de casa a las 7:15.\nVivo en la zona de Appio Latino. La oficina está en Via Crescenzio, en Prati. Ocho kilómetros en línea recta. Deberían ser quince minutos. En Roma, es otra historia.\n🚗 La mañana en coche #Via Appia Nuova ya es un aparcamiento. Porta San Giovanni, un embudo. Lungotevere, una procesión fúnebre con bocinas.\nCincuenta minutos para recorrer ocho kilómetros. Cincuenta minutos de embrague, semáforos, doble fila, motos que te cortan y autobuses que paran en segunda fila.\nPero lo mejor está por venir.\nLlego a Prati y empieza la caza del aparcamiento. Via Crescenzio, llena. Via Tacito, llena. Las calles laterales, llenas. Doy vueltas durante una hora y media. Una hora y media. Arrastrándome por las calles de Prati con el motor encendido y la paciencia bajo cero.\nAl final, agotado, me rindo. Aparcamiento de varios pisos de Piazza Cavour. \u0026ldquo;Al menos aquí encontraré sitio\u0026rdquo;, pienso.\nEncuentro sitio. También encuentro la cuenta: por la tarde, cuando salgo, el ticket dice 35 euros.\nTreinta y cinco euros por el privilegio de dejar el coche parado todo el día.\nHagamos balance de esa mañana:\nConcepto Valor Hora de salida de casa 7:15 Tiempo en el tráfico 50 minutos Tiempo buscando aparcamiento 1 hora y 30 minutos Hora de llegada al escritorio 9:35 Coste del aparcamiento 35€ Nivel de estrés ████████████ 200% Productividad de la primera hora cercana a cero Dos horas y veinte minutos. Para recorrer ocho kilómetros. Y 35 euros menos en la cartera.\nEsa noche vuelvo a casa pensando: \u0026ldquo;Tiene que haber otra forma.\u0026rdquo;\n🚲 La semana siguiente: la Brompton eléctrica #El lunes siguiente cambio todo.\nSalgo de casa a las 7:30 — quince minutos más tarde que la semana anterior. Bajo con mi Brompton eléctrica. La despliego en diez segundos en la acera. Casco, mochila, en marcha.\nMismo recorrido. Appio Latino → San Giovanni → Celio → Lungotevere → Prati.\nPero esta vez todo es diferente.\nMientras los coches están parados en cola, yo paso. Mientras las motos hacen eslálom entre parachoques, pedaleo tranquilo por el carril bici. No sudo — es una bici eléctrica, la asistencia hace su trabajo. No me estreso — nadie me toca el claxon. No busco aparcamiento — pliego la Brompton y me la llevo a la oficina.\nDieciocho minutos. Puerta a puerta.\nConcepto Valor Hora de salida de casa 7:30 Tiempo en bici 18 minutos Tiempo buscando aparcamiento 0 minutos Hora de llegada al escritorio 7:50 Coste 0€ Nivel de estrés ░░░░░░░░░░░░ 0% Productividad de la primera hora máxima A las 7:50 estaba sentado en el escritorio. Fresco. Despierto. Con el café en la mano y la cabeza ya en la primera tarea del día.\nUna hora y cuarenta y cinco minutos antes que la semana anterior.\nTreinta y cinco euros ahorrados.\nY sobre todo: cero estrés.\n📊 Los números en un año entero #Hagamos las cuentas en serio. Sobre 220 días laborables:\n🚗 Coche 🚲 Brompton Tiempo medio puerta a puerta (ida) 50 min + 30 min aparcamiento 18 min Tiempo diario (ida y vuelta) ~2h 40min ~36 min Tiempo anual en desplazamientos ~587 horas ~132 horas Horas ahorradas con la bici ~455 horas Coste anual de combustible ~1.800€ 0€ Aparcamiento/ZTL/multas ~1.200€ (estimación conservadora) 0€ Seguro + impuesto + desgaste ~2.500€ 0€ Coste anual de movilidad ~5.500€ ~50€ (mantenimiento) Ahorro anual ~5.450€ 455 horas ahorradas. Son 57 jornadas laborales. Dos meses y medio de vida devueltos.\n¿Y esos 5.450 euros ahorrados? Son unas vacaciones. Una aportación al plan de pensiones. El coste de la propia Brompton, amortizada en menos de un año.\n💪 Los beneficios que no se miden en euros #Pero los números económicos son solo una parte de la historia. Los que realmente importan son los otros.\nSalud cardiovascular #Pedalear 36 minutos al día, incluso con asistencia eléctrica, es actividad física moderada. La Organización Mundial de la Salud recomienda al menos 150 minutos de actividad aeróbica por semana. Yendo al trabajo en bici, haces 180 sin ni siquiera pensarlo.\nEstudios publicados en el British Medical Journal demuestran que quienes van al trabajo en bici tienen:\n41% menos riesgo de muerte por cualquier causa 52% menos riesgo de muerte por enfermedades cardiovasculares 45% menos riesgo de desarrollar cáncer No son mis números. Son números de la ciencia, sobre una muestra de más de 250.000 trabajadores británicos seguidos durante cinco años.\nSalud mental #El tráfico de Roma no es solo aburrido. Es tóxico para la mente. El estrés crónico del desplazamiento está correlacionado con:\naumento de los niveles de cortisol trastornos del sueño mayor irritabilidad y ansiedad reducción de la capacidad de concentración Pedalear, en cambio, libera endorfinas. Llegas al trabajo con el cerebro oxigenado, buen humor y una sensación de autonomía que el asiento de un coche en el tráfico nunca te dará.\nCalidad del aire #Un coche parado en el tráfico de Roma produce de media 120-150 g de CO₂ por kilómetro. En tráfico congestionado, incluso más — porque el motor funciona al ralentí, consumiendo sin moverse.\nUna bici produce cero emisiones.\nSi solo el 10% de los trabajadores romanos pasara al uso diario de la bici, se ahorrarían unas 150.000 toneladas de CO₂ al año. Es el equivalente a plantar 7 millones de árboles.\nNo es idealismo. Es aritmética.\n🤔 \u0026ldquo;Pero llueve, hace calor, es peligroso\u0026hellip;\u0026rdquo; #Lo sé. Conozco todas las objeciones. Me las he hecho yo también.\n\u0026quot;¿Y cuando llueve?\u0026quot;\nLlueve unos 75 días al año en Roma. En los días de lluvia fuerte, cojo el metro de San Giovanni a Lepanto. Quince minutos. Sin coche ni bajo el diluvio. La Brompton se pliega y sube al metro conmigo.\n\u0026ldquo;En verano hace demasiado calor.\u0026rdquo;\nCon la asistencia eléctrica no sudas. Y aunque sudaras un poco, mejor 18 minutos al aire libre que 50 minutos en un habitáculo ardiente con el aire acondicionado secándote la garganta.\n\u0026ldquo;Las calles de Roma no son seguras.\u0026rdquo;\nEsto es cierto, y no lo minimizo. Roma necesita más infraestructura ciclista. Pero mi recorrido — Appio Latino, Celio, Lungotevere — es razonablemente seguro, especialmente en hora punta cuando el tráfico es tan lento que los coches van más despacio que la bici.\n\u0026ldquo;No puedo llevar la bici a la oficina.\u0026rdquo;\nLa Brompton se pliega en 20 segundos y se convierte en un bulto que cabe bajo el escritorio. Ese es su superpoder: elimina completamente el problema del aparcamiento.\n🌍 No es solo una elección personal #Cada persona que deja el coche en casa y coge la bici:\nlibera una plaza de aparcamiento para quien realmente la necesita reduce el tráfico para quienes deben conducir mejora la calidad del aire para todos reduce la contaminación acústica del barrio demuestra que otro modelo es posible No estoy pidiendo a nadie que venda su coche. Estoy diciendo que para muchos trayectos urbanos — los de menos de 10 km — la bici es objetivamente superior al coche. Más rápida, más económica, más saludable, más sostenible.\nY con una plegable eléctrica, las últimas excusas caen una tras otra.\n🇪🇺 En Europa ya lo hacen — y funciona #Mientras en Roma debatimos si es posible ir al trabajo en bici, media Europa lo hace desde hace décadas.\nÁmsterdam tiene más bicicletas que habitantes — 881.000 bicis para 872.000 residentes. El problema no es convencer a la gente de que pedalee, sino dónde aparcar tantas bicis. En la Estación Central construyeron el aparcamiento de bicicletas más grande del mundo: 12.500 plazas en tres niveles subterráneos. Doce mil quinientas. No plazas de coche. Plazas de bici.\nCopenhague ha alcanzado un hito histórico: más del 60% de los residentes va al trabajo en bici. No por ideología, sino por practicidad. El trayecto medio dura 13 minutos. Intentad hacer lo mismo en coche.\nMúnich, Berlín, Viena — ciudades con inviernos mucho más duros que Roma — tienen redes ciclistas capilares y porcentajes de ciclistas urbanos que en Roma solo soñamos.\nY no hace falta mirar más allá de los Alpes. Milán, Bolonia, Ferrara, Padua — en el norte de Italia, ir al trabajo en bici es normal. No es heroísmo. No es excentricidad. Es sentido común.\n¿Las siete colinas? Con la eléctrica ya no son excusa #Sé lo que estáis pensando. \u0026ldquo;Sí, pero esas son ciudades llanas. Roma tiene siete colinas.\u0026rdquo;\nEs verdad. Roma tiene cuestas. El Celio, el Aventino, el Janículo — no son exactamente la llanura padana.\nPero esa objeción tenía sentido hace diez años. Hoy, con una bici eléctrica, las siete colinas ya no existen. El motor te asiste en la subida, llegas arriba sin jadear, sin sudar, sin echar de menos el coche.\nMi Brompton eléctrica afronta la subida del Celio como si fuera un ligero badén. El Lungotevere es llano. Y el tramo final hacia Prati es en bajada.\nRoma tiene 300 días de sol al año, un clima templado incluso en invierno, y distancias urbanas contenidas. Es — paradójicamente — una de las ciudades italianas más aptas para la bicicleta. Solo nos faltan las infraestructuras. Y el valor de cambiar costumbres.\n🏠 Bici y smart working: la combinación perfecta #Hay un vínculo profundo entre elegir la bici y la filosofía del smart working. Ambos parten de la misma pregunta: \u0026quot;¿Tiene sentido lo que estoy haciendo, o lo hago solo porque siempre se ha hecho así?\u0026quot;\nEl smart working elimina el desplazamiento los días en que no es necesario estar en la oficina. La bici convierte el desplazamiento en inteligente los días en que sí lo es.\n¿El modelo ideal? 3 días en remoto, 2 en la oficina — en bicicleta.\nModelo Horas semanales en viaje Estrés Coste 5 días en coche ~13 horas alto ~110€/semana 5 días coche + smart working (3+2) ~5 horas medio ~44€/semana 2 días bici + 3 smart working ~1,2 horas cero ~0€ De 13 horas a 1 hora y 12 minutos. De 110 euros a cero.\nNo es utopía. Es organización.\nNo es pereza. Es inteligencia.\nSi las empresas combinaran smart working con incentivos a la movilidad sostenible, el resultado sería triple: empleados más sanos, más productivos y ciudades más habitables. Pero para llegar ahí, hay que dejar de pensar que \u0026ldquo;trabajar\u0026rdquo; significa \u0026ldquo;estar sentado en una oficina de 9 a 18 después de una hora en el coche.\u0026rdquo;\n🎯 Mi balance personal #Desde que hice el cambio, mi mañana es así:\nHora Actividad 7:00 Despertar 7:00 — 7:25 Desayuno tranquilo, noticias 7:30 Salida de casa en Brompton 7:48 Llegada a la oficina, bici plegada bajo el escritorio 7:50 Operativo Sin estrés. Sin costes. Sin sorpresas de 35 euros.\nY por la tarde, lo mismo a la inversa: 18 minutos y estoy en casa. No una hora. No \u0026ldquo;depende del tráfico\u0026rdquo;. Dieciocho minutos, siempre.\nHe recuperado tiempo. He recuperado dinero. He recuperado energía mental.\nPero sobre todo, he recuperado el placer de moverme por la ciudad en vez de sufrirla.\n💬 A quienes siguen atrapados en el tráfico #Si cada mañana pasas una hora en el coche para un trayecto que en bici harías en veinte minutos.\nSi cada tarde vuelves a casa agotado, no por el trabajo, sino por el viaje para llegar.\nSi alguna vez has calculado cuánto gastas en gasolina, aparcamiento y salud mental.\nPrueba. Aunque solo sea una semana.\nCoge una bici — plegable, eléctrica, la que prefieras — y haz el mismo recorrido.\nMira el reloj cuando llegues. Mira cómo te sientes. Mira la cartera a final de mes.\nLos números hablan por sí solos.\nPero la sonrisa con la que llegas al escritorio, esa, no tiene precio.\nGlosario #Brompton — Bicicleta plegable británica considerada la referencia mundial por calidad constructiva, compacidad plegada y practicidad en el pendularismo urbano.\nPedaleo Asistido — Sistema de propulsión eléctrica que amplifica la fuerza del pedaleo, eliminando el problema de las cuestas y el sudor en los trayectos urbanos.\nBicicleta Plegable — Bicicleta que se pliega en 10-20 segundos convirtiéndose en un equipaje transportable a la oficina, al metro o al tren.\nPendularismo — Desplazamiento diario casa-trabajo y vuelta, que en las grandes ciudades puede absorber 2-4 horas al día y cientos de euros al mes.\nCarbon Footprint — Cantidad total de gases de efecto invernadero emitidos por una actividad — un coche en el tráfico romano produce 120-150 g de CO₂ por km, una bici cero.\nMovilidad Sostenible — Enfoque del transporte urbano que privilegia medios de bajo impacto ambiental, reduciendo emisiones, tráfico y costes.\n","date":"3 marzo 2026","permalink":"https://ivanluminaria.com/es/posts/project-management/bici-vs-auto-roma/","section":"Database Strategy","summary":"\u003cp\u003eLunes por la mañana. Despertador a las 6:40. Ducha, desayuno rápido, llaves del coche en la mesa. Salgo de casa a las 7:15.\u003c/p\u003e\n\u003cp\u003eVivo en la zona de Appio Latino. La oficina está en Via Crescenzio, en Prati. Ocho kilómetros en línea recta. Deberían ser quince minutos. En Roma, es otra historia.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-la-mañana-en-coche\" class=\"relative group\"\u003e🚗 La mañana en coche \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-la-ma%c3%b1ana-en-coche\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eVia Appia Nuova ya es un aparcamiento. Porta San Giovanni, un embudo. Lungotevere, una procesión fúnebre con bocinas.\u003c/p\u003e","title":"Bici vs Coche en Roma: la mañana que me abrió los ojos"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/cycling/","section":"Tags","summary":"","title":"Cycling"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/health/","section":"Tags","summary":"","title":"Health"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/smart-working/","section":"Tags","summary":"","title":"Smart-Working"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/sustainability/","section":"Tags","summary":"","title":"Sustainability"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/urban-mobility/","section":"Tags","summary":"","title":"Urban-Mobility"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/hugepages/","section":"Tags","summary":"","title":"Hugepages"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/kernel/","section":"Tags","summary":"","title":"Kernel"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/linux/","section":"Tags","summary":"","title":"Linux"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/categories/oracle/","section":"Categories","summary":"","title":"Oracle"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/oracle/","section":"Tags","summary":"","title":"Oracle"},{"content":"El cliente era una empresa de logística con Oracle 19c Enterprise Edition sobre Oracle Linux 8. Sesenta usuarios concurrentes, un ERP a medida, unos 400 GB de datos. El servidor era un Dell PowerEdge con 128 GB de RAM y 32 cores.\nLas quejas eran vagas pero persistentes: \u0026ldquo;El sistema va lento.\u0026rdquo; \u0026ldquo;Las queries de la mañana tardan el doble que hace dos meses.\u0026rdquo; \u0026ldquo;De vez en cuando se congela todo unos segundos.\u0026rdquo;\nCuando entré al servidor, lo primero que verifiqué no fue la base de datos. Fue el sistema operativo.\ncat /proc/meminfo | grep -i huge sysctl vm.nr_hugepages cat /sys/kernel/mm/transparent_hugepage/enabled Resultado: cero Huge Pages configuradas, Transparent Huge Pages activas, parámetros del kernel en sus valores por defecto. La instalación de Oracle se había hecho con el asistente, el sistema operativo no se había tocado.\nAhí estaba el problema. No era Oracle. Era Linux que no había sido preparado para Oracle.\n🔍 El diagnóstico #Antes de cambiar nada, medí el estado actual. Se necesitan números, no impresiones.\n# Estado de la SGA sqlplus -s / as sysdba \u0026lt;\u0026lt;SQL SELECT name, value/1024/1024 AS mb FROM v$sgainfo WHERE name IN (\u0026#39;Maximum SGA Size\u0026#39;, \u0026#39;Free SGA Memory Available\u0026#39;); SQL # Uso de memoria del sistema free -h # Parámetros kernel actuales sysctl -a | grep -E \u0026#34;kernel.sem|kernel.shm|vm.nr_hugepages|vm.swappiness\u0026#34; # I/O scheduler en uso cat /sys/block/sda/queue/scheduler # Límites del usuario oracle su - oracle -c \u0026#34;ulimit -a\u0026#34; Esto fue lo que encontré:\nParámetro Valor actual Valor recomendado SGA Target 64 GB 64 GB (ok) vm.nr_hugepages 0 33280 Transparent Huge Pages always never vm.swappiness 60 1 kernel.shmmax 33554432 (32 MB) 68719476736 (64 GB) kernel.shmall 2097152 16777216 kernel.sem 250 32000 100 128 250 32000 100 256 I/O scheduler mq-deadline deadline (ok) oracle nofile 1024 65536 oracle nproc 4096 16384 oracle memlock 65536 KB unlimited Casi todo estaba mal. No por error — por omisión. Nadie se había molestado en configurar el sistema operativo después de la instalación.\n📦 Huge Pages: el parámetro que lo cambia todo #Las Huge Pages son el parámetro individual más impactante para Oracle en Linux. Y también son el que se ignora con más frecuencia.\nPor qué importan #Por defecto, Linux gestiona la memoria en páginas de 4 KB. Una SGA de 64 GB significa aproximadamente 16,7 millones de páginas. Cada página tiene una entrada en la Page Table, y el sistema debe traducir direcciones virtuales a físicas para cada una. El TLB (Translation Lookaside Buffer) de la CPU puede almacenar solo unos pocos miles de traducciones — el resto lo gestiona la MMU, que es lenta.\nLas Huge Pages son páginas de 2 MB. La misma SGA de 64 GB se convierte en 32.768 páginas. El TLB aguanta, la presión sobre la MMU cae, el rendimiento mejora.\nCómo configurarlas #Calculé el número de Huge Pages necesarias:\n# SGA = 64 GB = 65536 MB # Cada Huge Page = 2 MB # Páginas necesarias = 65536 / 2 = 32768 # Añado un 1,5% de margen → 33280 echo \u0026#34;vm.nr_hugepages = 33280\u0026#34; \u0026gt;\u0026gt; /etc/sysctl.d/99-oracle.conf sysctl -p /etc/sysctl.d/99-oracle.conf Verificación:\ngrep -i huge /proc/meminfo Salida esperada:\nHugePages_Total: 33280 HugePages_Free: 33280 HugePages_Rsvd: 0 Hugepagesize: 2048 kB Después de reiniciar la instancia Oracle, la SGA se asigna en Huge Pages:\nHugePages_Total: 33280 HugePages_Free: 512 HugePages_Rsvd: 480 La diferencia es medible: los latch free waits y la library cache contention se reducen drásticamente.\n🧱 Memoria compartida y semáforos #Oracle usa la memoria compartida del kernel para la SGA. Si los límites son demasiado bajos, la instancia no puede asignar la memoria solicitada — o peor, fragmenta la asignación.\ncat \u0026gt;\u0026gt; /etc/sysctl.d/99-oracle.conf \u0026lt;\u0026lt; \u0026#39;SYSCTL\u0026#39; # Shared memory kernel.shmmax = 68719476736 kernel.shmall = 16777216 kernel.shmmni = 4096 # Semaphores: SEMMSL SEMMNS SEMOPM SEMMNI kernel.sem = 250 32000 100 256 SYSCTL sysctl -p /etc/sysctl.d/99-oracle.conf Parámetro Significado Valor shmmax Tamaño máximo de un segmento de memoria compartida 64 GB shmall Páginas totales de memoria compartida asignables 64 GB en páginas de 4K shmmni Número máximo de segmentos de memoria compartida 4096 sem SEMMSL, SEMMNS, SEMOPM, SEMMNI 250 32000 100 256 No son valores mágicos. Están dimensionados para la SGA de la base de datos. Si la SGA cambia, los parámetros deben recalcularse.\n💾 I/O Scheduler #El default en RHEL/Oracle Linux 8 con dispositivos NVMe es none o mq-deadline. Para discos SAS/SATA tradicionales, el default puede ser bfq o cfq.\nPara Oracle, la recomendación es deadline (o mq-deadline en kernels más recientes):\n# Verificar configuración actual cat /sys/block/sda/queue/scheduler # Si no es deadline/mq-deadline, configurarlo echo \u0026#34;deadline\u0026#34; \u0026gt; /sys/block/sda/queue/scheduler # Hacerlo permanente vía GRUB grubby --update-kernel=ALL --args=\u0026#34;elevator=deadline\u0026#34; cfq (Completely Fair Queuing) está diseñado para cargas de trabajo de escritorio — distribuye el I/O equitativamente entre procesos. Pero Oracle no necesita equidad: necesita que las solicitudes de I/O se atiendan en el orden que minimiza los seeks. deadline hace exactamente eso.\n🚫 Deshabilitar Transparent Huge Pages #Este es el parámetro más insidioso. Las Transparent Huge Pages (THP) son una función del kernel que parece buena idea: el kernel promueve automáticamente las páginas normales a páginas grandes.\nPara Oracle es un desastre. El proceso khugepaged trabaja en segundo plano para compactar páginas, causando picos de latencia impredecibles — esos \u0026ldquo;bloqueos de unos segundos\u0026rdquo; que el cliente reportaba.\nOracle lo dice explícitamente en la documentación: deshabilitar THP.\n# Verificar estado actual cat /sys/kernel/mm/transparent_hugepage/enabled # Salida típica: [always] madvise never # Deshabilitar en tiempo de ejecución echo never \u0026gt; /sys/kernel/mm/transparent_hugepage/enabled echo never \u0026gt; /sys/kernel/mm/transparent_hugepage/defrag # Hacerlo permanente vía GRUB grubby --update-kernel=ALL --args=\u0026#34;transparent_hugepage=never\u0026#34; Después del reinicio, verificar:\ncat /sys/kernel/mm/transparent_hugepage/enabled # Salida esperada: always madvise [never] La diferencia es nítida: los micro-bloqueos aleatorios desaparecen.\n🔒 Límites de seguridad #El usuario oracle necesita límites elevados en descriptores de archivo abiertos, procesos y memoria bloqueable. Los defaults de Linux están pensados para usuarios interactivos, no para software que gestiona cientos de conexiones simultáneas.\ncat \u0026gt;\u0026gt; /etc/security/limits.d/99-oracle.conf \u0026lt;\u0026lt; \u0026#39;LIMITS\u0026#39; oracle soft nofile 65536 oracle hard nofile 65536 oracle soft nproc 16384 oracle hard nproc 16384 oracle soft stack 10240 oracle hard stack 32768 oracle soft memlock unlimited oracle hard memlock unlimited LIMITS Límite Default Recomendado Por qué nofile 1024 65536 Oracle abre un descriptor por cada datafile, redo log, archive log nproc 4096 16384 Cada proceso Oracle es un proceso OS separado memlock 65536 KB unlimited Necesario para bloquear la SGA en Huge Pages stack 8192 KB 10240-32768 KB PL/SQL recursivo profundo puede agotar el stack El memlock unlimited es fundamental: sin él, Oracle no puede bloquear la SGA en Huge Pages, haciendo inútil la configuración anterior.\n⚡ Swappiness #El valor por defecto de vm.swappiness es 60. Significa que Linux empieza a hacer swap cuando la presión sobre la memoria es aún baja. Para un servidor de base de datos dedicado, esto es inaceptable: quieres que la SGA permanezca en RAM, siempre.\necho \u0026#34;vm.swappiness = 1\u0026#34; \u0026gt;\u0026gt; /etc/sysctl.d/99-oracle.conf sysctl -p /etc/sysctl.d/99-oracle.conf No cero — uno. Un valor de cero deshabilita completamente el swap, lo que puede provocar el OOM killer en situaciones de presión extrema. Un valor de uno le dice al kernel: \u0026ldquo;Solo haz swap cuando realmente no haya alternativa.\u0026rdquo;\n📊 Antes y después #Después de aplicar todas las configuraciones y reiniciar la instancia Oracle, repetí las mediciones.\nMétrica Antes Después Variación SGA en Huge Pages No Sí — Library cache hit ratio 92,3% 99,7% +7,4% Buffer cache hit ratio 94,1% 99,2% +5,1% Tiempo medio de espera (db file sequential read) 8,2 ms 1,4 ms -83% Micro-bloqueos aleatorios (\u0026gt;1s) 5-8 al día 0 -100% Tiempo medio batch matutino 47 min 22 min -53% Utilización CPU media 78% 41% -47% Swap utilizado 3,2 GB 0 MB -100% Los números hablan por sí mismos. La misma máquina, la misma base de datos, la misma carga de trabajo. La única diferencia: el sistema operativo fue configurado para hacer su trabajo.\n📋 Checklist final #Para quien quiera un resumen operativo, aquí está la checklist completa:\n# /etc/sysctl.d/99-oracle.conf vm.nr_hugepages = 33280 vm.swappiness = 1 kernel.shmmax = 68719476736 kernel.shmall = 16777216 kernel.shmmni = 4096 kernel.sem = 250 32000 100 256 # /etc/security/limits.d/99-oracle.conf oracle soft nofile 65536 oracle hard nofile 65536 oracle soft nproc 16384 oracle hard nproc 16384 oracle soft stack 10240 oracle hard stack 32768 oracle soft memlock unlimited oracle hard memlock unlimited # GRUB grubby --update-kernel=ALL --args=\u0026#34;transparent_hugepage=never elevator=deadline\u0026#34; Diez minutos de configuración. Sin coste de hardware. Sin licencias adicionales.\nPero nadie lo hace, porque el asistente no lo pide, la documentación está enterrada en una nota MOS, y el sistema \u0026ldquo;funciona sin ello.\u0026rdquo; Funciona. Mal. Y la culpa siempre recae en Oracle, nunca en que nadie preparó el terreno.\nUna base de datos es tan buena como el sistema operativo sobre el que corre. Y un sistema operativo dejado en sus valores por defecto es un sistema operativo que trabaja en tu contra.\nGlosario #Huge Pages — Páginas de memoria de 2 MB (en lugar de los 4 KB estándar) que reducen drásticamente la presión sobre la MMU y el TLB, mejorando el rendimiento de Oracle en Linux.\nTHP — Transparent Huge Pages — función del kernel Linux que promueve automáticamente las páginas normales a páginas grandes, pero que causa latencias impredecibles y debe deshabilitarse para Oracle.\nSGA — System Global Area — área de memoria compartida de Oracle Database que contiene buffer cache, shared pool, redo log buffer y otras estructuras críticas para el rendimiento.\nI/O Scheduler — Componente del kernel Linux que decide el orden en que las solicitudes de I/O se envían al disco, con impacto directo en el rendimiento de la base de datos.\nSwappiness — Parámetro del kernel Linux (vm.swappiness) que controla la propensión del sistema a mover páginas de memoria al swap, crítico para servidores de base de datos.\n","date":"24 febrero 2026","permalink":"https://ivanluminaria.com/es/posts/oracle/oracle-linux-kernel/","section":"Database Strategy","summary":"\u003cp\u003eEl cliente era una empresa de logística con Oracle 19c Enterprise Edition sobre Oracle Linux 8. Sesenta usuarios concurrentes, un ERP a medida, unos 400 GB de datos. El servidor era un Dell PowerEdge con 128 GB de RAM y 32 cores.\u003c/p\u003e\n\u003cp\u003eLas quejas eran vagas pero persistentes: \u0026ldquo;El sistema va lento.\u0026rdquo; \u0026ldquo;Las queries de la mañana tardan el doble que hace dos meses.\u0026rdquo; \u0026ldquo;De vez en cuando se congela todo unos segundos.\u0026rdquo;\u003c/p\u003e","title":"Oracle en Linux: los parámetros del kernel que nadie configura"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/productivity/","section":"Tags","summary":"","title":"Productivity"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/remote-work/","section":"Tags","summary":"","title":"Remote-Work"},{"content":"6:47 de un martes cualquiera. Estoy en el parque cerca de casa, equipado para correr. El aire es fresco, el sol apenas asoma. Ya he hecho cuatro kilómetros. Me siento vivo.\nA las 7:00 estoy en la ducha. A las 7:20 desayuno con calma. A las 7:45 estoy en mi escritorio, fresco, concentrado, listo para trabajar.\nA esa misma hora, un colega mío sigue atascado en la Pontina. O en el raccordo, entre la Casilina y la Tuscolana. Ya tiene el teléfono en la mano — no para trabajar, sino para enviar el clásico mensaje: \u0026ldquo;Perdona, llego tarde, ha habido un accidente.\u0026rdquo;\nDos personas. Mismo trabajo. Mismo contrato.\nUno ya es productivo. El otro está quemando sus mejores energías en un habitáculo.\nEsto no es una opinión. Son hechos.\nY los hechos tienen números.\n🚗 El coste invisible del pendularismo en Roma #Hablemos claro: Roma no es una ciudad. Es un organismo caótico que se mueve a trompicones.\nPara quien trabaja en consultoría IT y vive fuera del centro — y en Roma \u0026ldquo;fuera del centro\u0026rdquo; significa prácticamente todo — el trayecto casa-oficina es una odisea diaria.\nHagamos cuentas con un escenario real:\nConcepto Valor Distancia casa-oficina ~30 km (un cuarto del raccordo) Tiempo medio ida 1h 15min — 2h 30min Tiempo medio vuelta 1h — 1h 45min Tiempo total diario en coche 2h 15min — 4h 15min Días laborables al mes 21 Horas perdidas al mes en coche 47 — 89 horas Coste combustible mensual (~30km x 2 x 21 días) ~250-300€ Desgaste coche, seguro, aparcamiento ~150-200€/mes Coste total mensual pendularismo ~400-500€ Casi 90 horas al mes en el peor caso. Son más de dos semanas laborales completas dentro de un coche. Sin trabajar. Sin pensar. Maldiciendo el tráfico.\nY aún no he contado el estrés. La frustración. La energía mental que se quema antes siquiera de encender el ordenador.\n🏃 La otra cara de la moneda: la mañana de quien trabaja desde casa #Esta es mi jornada tipo:\nHora Actividad 6:00 Despertador 6:10 — 6:45 Carrera en el parque (4-5 km) 6:50 — 7:10 Ducha 7:10 — 7:30 Desayuno con calma 7:30 — 7:45 Preparar puesto de trabajo, café, revisar agenda 7:45 Inicio del trabajo Llego al escritorio después de hacer deporte, de respirar aire libre, de haber tenido tiempo para pensar. No llego después de haber librado una guerra.\nLa diferencia no es solo física. Es cognitiva.\nUn consultor IT trabaja con la cabeza. Analiza sistemas, escribe código, diseña arquitecturas, resuelve problemas complejos. Si esa cabeza llega a la oficina ya descargada, ya frustrada, ya cansada — ¿cuánto vale realmente esa jornada de trabajo?\nHe trabajado con equipos distribuidos en tres husos horarios. He gestionado bases de datos críticas conectándome desde casa a las 3 de la madrugada por una emergencia. Nunca he necesitado una oficina para hacer mi trabajo. He necesitado una conexión estable, un entorno silencioso y una mente lúcida.\n📊 Los números para la empresa: lo que los CFO no quieren ver #Las empresas de consultoría IT en Roma tienen un problema estructural que fingen no tener.\nTomemos una empresa con 50 consultores. Hagamos las cuentas:\nCoste del pendularismo empresarial # Concepto Cálculo Total anual Horas perdidas en coche (media 3h/día x 50 personas) 150 horas/día x 220 días 33.000 horas/año Valor hora consultor (coste empresa medio) 33.000 x 35€/hora ~1.155.000€/año Alquiler oficina Roma (50 puestos) ~800€/puesto/mes ~480.000€/año Suministros, limpieza, mantenimiento ~60.000€/año Coste total estimado ~1.695.000€/año Un millón setecientos mil euros. Cada año. Para tener a cincuenta personas sentadas en el mismo sitio.\nEscenario smart working (80% remoto) # Concepto Cálculo Total anual Horas recuperadas (80% de las 33.000) 26.400 horas convertidas en trabajo productivo Oficina redimensionada (15 puestos hot-desk) ~800€ x 15 ~144.000€/año Contribución conectividad empleados 50€/mes x 50 ~30.000€/año Presupuesto equipamiento home office (pago único) 1.000€ x 50 50.000€ (año 1) Coste total estimado (año 1) ~224.000€ Coste total estimado (desde año 2) ~174.000€ Ahorro anual: más de 1.400.000€.\nY estoy haciendo estimaciones conservadoras.\nPero el número más importante no es el económico.\nEl número más importante son esas 26.400 horas devueltas a la productividad.\nHoras en las que las personas trabajan lúcidas, descansadas, concentradas.\nNo horas mirando un parachoques en la Cristoforo Colombo.\n🧠 El argumento que nadie se atreve a plantear #Lo digo claramente: el presentismo en la oficina en consultoría IT es un vestigio cultural, no una necesidad operativa.\nEl consultor informático no trabaja en una cadena de montaje. No necesita estar físicamente presente junto a una máquina. Necesita:\nuna conexión a internet rápida un entorno silencioso herramientas digitales adecuadas comunicación clara con el equipo objetivos medibles Todo esto se hace mejor desde casa que en un open space ruidoso donde el teléfono suena cada cinco minutos y alguien te interrumpe para preguntarte \u0026ldquo;¿tienes un momento?\u0026rdquo; (que nunca es solo un momento).\nEl verdadero problema es el control. Algunas empresas no saben gestionar el trabajo por objetivos. Solo saben gestionar la presencia. Y confunden las dos cosas.\nSi un consultor cierra 20 tickets en una semana trabajando desde casa en pantalones cortos, es más productivo que uno que cierra 8 en traje y corbata en la oficina de 9 a 18.\nLos números no mienten. Las sillas de oficina sí.\n🏢 \u0026ldquo;¿Pero la cultura de empresa? ¿El espíritu de equipo?\u0026rdquo; #Lo oigo a menudo. Lo entiendo. No lo comparto, pero lo entiendo.\nLa cultura empresarial no se construye sentando a las personas juntas. Se construye con:\nobjetivos compartidos que todos entienden comunicación transparente que nadie sufre momentos de encuentro que tengan sentido — no la reunión semanal donde todos miran el móvil debajo de la mesa confianza mutua — que es exactamente lo que falta cuando impones la presencia Un equipo que trabaja bien en remoto es un equipo que ha aprendido a comunicarse de verdad. No por proximidad física, sino por claridad.\nHe visto equipos en oficina que no se hablaban. Y equipos distribuidos en tres países que funcionaban como relojes suizos.\nLa diferencia no es el lugar. Es el método.\n🎯 La propuesta concreta #Si gestionas una empresa de consultoría IT en Roma — o en cualquier gran ciudad con problemas de movilidad — esto es lo que te sugiero:\n1. Adopta un modelo 80/20\n80% remoto, 20% presencial. Los días en oficina sirven para workshops, revisiones de proyecto, momentos de team building reales — no para calentar la silla.\n2. Invierte en el puesto de trabajo doméstico\n1.000€ de pago único por empleado: monitor, silla ergonómica, auriculares con micrófono. Es una inversión que se amortiza en dos semanas de ahorro de alquiler.\n3. Mide resultados, no horas\nDefine KPI claros: tickets cerrados, código desplegado, SLA cumplidos, clientes satisfechos. Quien produce, produce — independientemente de dónde esté.\n4. Reduce los espacios físicos\nPasa de 50 puestos fijos a 15 hot desks. Usa el espacio ahorrado para una sala de reuniones digna y una zona de descanso real.\n5. Confía en tu gente\nSi has contratado profesionales, trátalos como profesionales. Si no confías en ellos sin verlos, el problema no es el smart working. Es tu proceso de selección.\n💬 A quien se reconoce en esta historia #Si cada mañana te levantas una hora antes de lo necesario para \u0026ldquo;ganarle al tráfico\u0026rdquo; — y aun así llegas tarde.\nSi gastas 500€ al mes por el privilegio de estar sentado en una cola.\nSi llegas al escritorio ya cansado, ya nervioso, ya con la jornada comprometida.\nSabe que no tiene por qué ser así.\nExiste una forma diferente de trabajar. Más inteligente. Más humana. Más productiva.\nY los números lo demuestran.\nNo hacen falta revoluciones. Hace falta el coraje de mirar esos números.\nY de actuar en consecuencia.\nYo, mientras tanto, mañana me levanto a las 6, voy a correr, y a las 7:45 estoy operativo.\nCon una sonrisa. Sin tráfico. Sin estrés.\nY con la cabeza ya en el primer problema que resolver.\nGlosario #Smart Working — Modelo de trabajo flexible que combina trabajo remoto y presencia en oficina, basado en objetivos medibles en lugar de horarios y presencia física.\nPendularismo — Desplazamiento diario casa-trabajo y vuelta, que en las grandes ciudades puede absorber 2-4 horas al día y cientos de euros al mes.\nPresentismo — Cultura organizativa que equipara la presencia física en la oficina con la productividad, independientemente de los resultados producidos.\nKPI — Key Performance Indicator — métrica medible que evalúa la eficacia de una actividad respecto a un objetivo definido, usada para medir resultados concretos en lugar de horas de presencia.\nHot Desk — Modelo de organización de espacios de oficina en el que los puestos no están asignados: quien va a la oficina ocupa un escritorio libre.\n","date":"24 febrero 2026","permalink":"https://ivanluminaria.com/es/posts/project-management/smartworking-consulenza-it/","section":"Database Strategy","summary":"\u003cp\u003e6:47 de un martes cualquiera. Estoy en el parque cerca de casa, equipado para correr. El aire es fresco, el sol apenas asoma. Ya he hecho cuatro kilómetros. Me siento vivo.\u003c/p\u003e\n\u003cp\u003eA las 7:00 estoy en la ducha. A las 7:20 desayuno con calma. A las 7:45 estoy en mi escritorio, fresco, concentrado, listo para trabajar.\u003c/p\u003e\n\u003cp\u003eA esa misma hora, un colega mío sigue atascado en la Pontina. O en el raccordo, entre la Casilina y la Tuscolana. Ya tiene el teléfono en la mano — no para trabajar, sino para enviar el clásico mensaje: \u0026ldquo;Perdona, llego tarde, ha habido un accidente.\u0026rdquo;\u003c/p\u003e","title":"Smart working en consultoría IT: los números que nadie quiere mirar"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/tuning/","section":"Tags","summary":"","title":"Tuning"},{"content":"En casi treinta años de trabajo no he cambiado de profesión.\nHe cambiado de profundidad.\nCada rol que he asumido no ha sido un movimiento lateral.\nHa sido una profundización vertical.\nLo que hoy ofrezco no es una lista de competencias.\nEs la suma de las consecuencias que esas competencias generan.\nData Warehouse Architect #Mi experiencia en Data Warehouse se ha desarrollado en entornos donde el dato es infraestructura crítica.\nHe trabajado para grandes operadores Telco como TIM, Wind, Vodafone y 3, en proyectos internacionales con Huawei,\nen el sector asegurador con Generali,\nen entornos institucionales como el Banco de Italia, la Oficina Italiana de Cambios y Cassa Depositi e Prestiti,\nen el sector farmacéutico,\ny en el sector automotriz con Rover y Alfa Romeo.\nSectores distintos. Una misma exigencia: fiabilidad.\nEn Telco importa la escala.\nEn banca e instituciones públicas importa la precisión normativa.\nEn seguros importa la coherencia del riesgo.\nEn el sector farmacéutico importa el cumplimiento regulatorio.\nEn automoción importa la sincronización de procesos y la calidad del dato a lo largo de la cadena de suministro.\nHe diseñado arquitecturas de datos en entornos donde el margen de error no existe.\n👉 Lee la roadmap de mis competencias y experiencia como Data Warehouse Architect | Descargar PDF\nProject Manager con background técnico #Mi experiencia en gestión de proyectos ha madurado coordinando iniciativas en entornos complejos:\nTelecomunicaciones internacionales, Instituciones financieras centrales, Seguros, Farmacéutico, Automoción y Administración Pública.\nEn estos sectores, el error tiene un coste real.\nUn Project Manager técnico comprende el impacto de las decisiones. Sabe cuándo un compromiso es aceptable. Y cuándo no lo es.\nConecto visión estratégica con detalle técnico. Roadmaps con implementación. Decisiones con consecuencias.\n👉 Lee la roadmap de mis competencias y experiencia como Project Manager | Descargar PDF\nOracle DBA \u0026amp; Performance Tuning Expert #Mi actividad como Oracle DBA se ha consolidado en entornos mission-critical para operadores como TIM, Wind, Vodafone y 3, en contextos tecnológicos complejos como Huawei, para instituciones financieras como el Banco de Italia, la Oficina Italiana de Cambios y Cassa Depositi e Prestiti, para organizaciones aseguradoras como Generali, y en proyectos industriales en el sector automotriz.\nSistemas de alta disponibilidad. Cargas elevadas. Responsabilidad real de guardia.\nAquí el tuning no es una mejora estética. Es protección operativa.\n👉 Lee la roadmap de mis competencias y experiencia como Oracle DBA | Descargar PDF\nOracle PL/SQL – Senior \u0026amp; Mentor #He desarrollado PL/SQL en entornos Telco, Banca, Seguros, Automoción, Farmacéutico y Administración Pública.\nEn contextos como Generali o el Banco de Italia, la lógica en base de datos es parte de la estabilidad del sistema. En automoción, la coherencia del dato impacta directamente en los procesos productivos y en la cadena de suministro.\nDurante años he enseñado SQL y PL/SQL, contribuyendo al crecimiento técnico de desarrolladores que hoy trabajan sobre sistemas complejos.\nHoy no me limito a escribir código. Puedo liderar. Puedo hacer mentoring. Puedo ayudar a desarrolladores a crecer en profundidad técnica y arquitectónica.\n👉 Lee la roadmap de mis competencias y experiencia como Oracle PL/SQL Developer | Descargar PDF\n","date":null,"permalink":"https://ivanluminaria.com/es/resumes/","section":"Know-How \u0026 Impact","summary":"\u003cp\u003eEn casi treinta años de trabajo no he cambiado de profesión.\u003c/p\u003e\n\u003cp\u003eHe cambiado de profundidad.\u003c/p\u003e\n\u003cp\u003eCada rol que he asumido no ha sido un movimiento lateral.\u003cbr\u003e\nHa sido una profundización vertical.\u003c/p\u003e\n\u003cp\u003eLo que hoy ofrezco no es una lista de competencias.\u003cbr\u003e\nEs la suma de las consecuencias que esas competencias generan.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"data-warehouse-architect\" class=\"relative group\"\u003eData Warehouse Architect \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#data-warehouse-architect\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eMi experiencia en Data Warehouse se ha desarrollado en entornos donde el dato es infraestructura crítica.\u003c/p\u003e","title":"Know-How \u0026 Impact"},{"content":" IVAN LUMINARIA Oracle, PostgreSQL \u0026 MySQL Expert | DWH Architect | Project Manager Profesional IT con aproximadamente 30 años de experiencia en el diseño, implementación y gestión de soluciones de bases de datos y Data Warehouse en entornos Oracle, PostgreSQL y MySQL. LinkedIn: ivanluminaria\nEmail: ivan (dot) luminaria (at) gmail (dot) com Trabajo con bases de datos desde hace unos treinta años.\nEl tiempo suficiente para haber visto cambiar motores, lenguajes, tendencias y palabras de moda.\nEl tiempo suficiente para saber que, debajo de la superficie, las reglas no cambian.\nUna base de datos no es un contenedor.\nEs un organismo.\nRespira.\nSe fatiga.\nSe bloquea.\nO escala.\nEmpecé en entornos Oracle mission-critical, cuando “mission-critical” no era una frase de presentación.\nEra la diferencia entre un sistema que resiste y uno que cae a las tres de la mañana.\nHe pasado incontables horas sobre AWR, ASH y planes de ejecución.\nHe visto sistemas ralentizarse “sin motivo aparente”.\nY aprendí que siempre hay un motivo.\nSolo hay que buscarlo con método.\nDespués llegaron PostgreSQL y MySQL.\nHerramientas distintas.\nFilosofías distintas.\nLa misma disciplina.\nEntender el motor.\nNo luchar contra él.\nNo creo en la optimización milagrosa.\nCreo en estadísticas actualizadas.\nEn un modelo de datos correcto.\nEn la diferencia entre “funciona” y “resiste”.\nPorque una base de datos lenta no es un problema técnico.\nEs un problema de negocio.\nEs un informe que no llega.\nUn cliente que espera.\nUna decisión tomada demasiado tarde.\nY ahí es exactamente donde me gusta estar —\ndonde la tecnología se convierte en impacto real.\nCómo trabajo #No me limito a “administrar” bases de datos.\nLas observo.\nLas mido.\nLas pongo a prueba.\nLas protejo.\nTrabajo en performance tuning en entornos complejos — Oracle, RAC, Exadata — y también en PostgreSQL y MySQL en contextos modernos, a menudo open source, donde la ausencia de “magia propietaria” obliga a entender realmente lo que ocurre bajo el capó.\nDiseño arquitecturas de Data Warehouse porque los datos no están para almacenarse.\nEstán para comprenderse.\nHe trabajado con modelos multidimensionales, procesos ETL/ELT y flujos que deben ser fiables antes que rápidos.\nPorque un dato incorrecto, aunque llegue en milisegundos, sigue siendo incorrecto.\nEscribo PL/SQL cuando es necesario.\nOptimizo cuando hace falta.\nRefactorizo cuando es inevitable.\nNo me interesan los efectos especiales.\nMe interesa la solidez.\nVisión #Con los años he integrado profundidad técnica con perspectiva estratégica.\nHe coordinado pequeños equipos internacionales.\nHe traducido necesidades de negocio en decisiones técnicas sostenibles.\nHe aprendido que la complejidad no se elimina.\nSe gestiona.\nAgile, Scrum, procesos estructurados: herramientas útiles.\nPero sin competencia real, son solo etiquetas.\nPara mí, liderazgo significa algo simple:\ntomar decisiones técnicas que resistan el paso del tiempo.\nMás allá del trabajo #Fuera del trabajo cultivo pasiones que, en el fondo, hablan el mismo idioma.\nLa fotografía me enseñó que la luz adecuada cambia la historia.\nLa música — estoy aprendiendo saxofón y toco la guitarra — me recuerda que la técnica sin sensibilidad es solo ruido.\nLa cocina es arquitectura comestible: equilibrio, tiempos, proporción.\nEl ajedrez es estrategia pura: cada movimiento es una decisión, cada decisión tiene consecuencias.\nQuizás por eso me siento cómodo en sistemas complejos.\nNo me intimidan.\nMe despiertan curiosidad.\nMe gusta profundizar en los detalles.\nPero solo para hacer que el conjunto funcione mejor.\nNo construyo bases de datos.\nConstruyo solidez.\n\u0026ldquo;Transformo la complejidad de los datos en valor estratégico para el negocio.\u0026rdquo;\n","date":"20 febrero 2026","permalink":"https://ivanluminaria.com/es/about/","section":"Ivan Luminaria","summary":"\u003cdiv class=\"profile-header flex flex-col sm:flex-row sm:items-center items-start\"\u003e\n  \u003cdiv class=\"flex-none\"\u003e\n    \u003cimg\n      src='https://ivanluminaria.com/img/ivan_luminaria_avatar.png'\n      alt=\"Ivan Luminaria\"\n      class=\"profile-avatar rounded-full shadow-xl border-4 border-slate-100\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"profile-text text-left\"\u003e\n    \u003ch1 class=\"mb-1\"\u003eIVAN LUMINARIA\u003c/h1\u003e\n    \u003ch3 class=\"mt-0 text-slate-500\"\u003e\n      Oracle, PostgreSQL \u0026 MySQL Expert | DWH Architect | Project Manager\n    \u003c/h3\u003e\n    \u003cp class=\"mt-4\"\u003e\n      Profesional IT con aproximadamente \u003cstrong\u003e30 años de experiencia\u003c/strong\u003e en el diseño, implementación y gestión de soluciones de bases de datos y Data Warehouse en entornos Oracle, PostgreSQL y MySQL.\n    \u003c/p\u003e\n    \u003cp class=\"mt-2\" style=\"font-size: 0.9em;\"\u003e\n      \u003cstrong\u003eLinkedIn:\u003c/strong\u003e \u003ca href=\"https://www.linkedin.com/in/ivanluminaria/\" target=\"_blank\" rel=\"noopener\"\u003eivanluminaria\u003c/a\u003e\u003cbr\u003e\n      \u003cstrong\u003eEmail:\u003c/strong\u003e ivan (dot) luminaria (at) gmail (dot) com\n    \u003c/p\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003chr\u003e\n\u003cp\u003eTrabajo con bases de datos desde hace unos treinta años.\u003c/p\u003e","title":"Sobre mí"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/cluster/","section":"Tags","summary":"","title":"Cluster"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/galera/","section":"Tags","summary":"","title":"Galera"},{"content":"El ticket era lacónico, como suele pasar cuando el problema es grave: \u0026ldquo;La base de datos se cayó otra vez. La aplicación está parada. Tercera vez en dos meses.\u0026rdquo;\nEl cliente tenía un MariaDB en un único servidor Linux — una aplicación de gestión empresarial usada por unos doscientos usuarios internos, con picos de carga durante los cierres contables de fin de mes. Cada vez que el servidor tenía un problema — un disco que se ralentizaba, una actualización del sistema que requería reinicio, un proceso que consumía toda la RAM — la base de datos caía y con ella toda la operatividad empresarial.\nLa pregunta no era \u0026ldquo;cómo reparamos el servidor\u0026rdquo;. La pregunta era: ¿cómo hacemos para que la próxima vez que un servidor tenga un problema, la aplicación siga funcionando?\nLa respuesta, tras veinte años de experiencia con este tipo de escenarios, era una: Galera Cluster.\nEl diagnóstico: un single point of failure clásico #Lo primero que hice fue analizar la infraestructura. El cuadro era familiar:\nUn único servidor MariaDB, ninguna réplica Backup nocturno en disco externo (al menos eso) Ningún mecanismo de failover La aplicación apuntaba directamente a la IP del servidor de base de datos Cada caída, aunque fuera de diez minutos, significaba doscientas personas paradas. Durante los cierres contables, significaba retrasos que se propagaban en cascada por los procesos empresariales.\nPropuse al cliente una solución basada en Galera Cluster: tres nodos MariaDB con replicación síncrona multi-master. Cualquier nodo acepta lecturas y escrituras, los datos son coherentes en los tres, y si un nodo cae los otros dos siguen sirviendo la aplicación sin interrupción.\nEl cliente ya tenía disponibles tres VM Linux — el equipo de infraestructura las había provisionado para otro proyecto que se pospuso. Perfecto: ni siquiera hacía falta pedir hardware.\nEl plan: tres nodos, cero single point of failure #Las máquinas disponibles:\nNodo Hostname IP Nodo 1 db-node1 10.0.1.11 Nodo 2 db-node2 10.0.1.12 Nodo 3 db-node3 10.0.1.13 Una premisa importante: Galera no es una opción nativa de MySQL Community. Se usa MariaDB (que lo integra nativamente) o Percona XtraDB Cluster (basado en MySQL). El cliente ya usaba MariaDB, así que la elección era natural y no requería migración de motor.\nEl objetivo era claro: migrar de una arquitectura de nodo único a un cluster de tres nodos, sin cambiar la aplicación más allá de la dirección de conexión.\nInstalación: misma versión en todos los nodos #Primer principio innegociable: todos los nodos deben tener exactamente la misma versión de MariaDB. He visto clusters inestables durante meses porque alguien había actualizado un nodo y no los demás.\nEn los tres servidores:\n# Añadir el repositorio oficial de MariaDB (ejemplo para 11.4 LTS) curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | \\ sudo bash -s -- --mariadb-server-version=\u0026#34;mariadb-11.4\u0026#34; # Instalar MariaDB Server y el plugin Galera sudo dnf install MariaDB-server MariaDB-client galera-4 -y # Habilitar pero NO iniciar aún el servicio sudo systemctl enable mariadb No iniciar el servicio. Primero se configura. Siempre.\nEl corazón de la configuración: /etc/my.cnf.d/galera.cnf #Este es el archivo que define el comportamiento del cluster. Debe crearse en cada nodo, con las diferencias apropiadas de dirección IP y nombre de nodo.\nAquí la configuración completa para el Nodo 1:\n[mysqld] # === Motor y charset === binlog_format=ROW default_storage_engine=InnoDB innodb_autoinc_lock_mode=2 innodb_flush_log_at_trx_commit=2 innodb_buffer_pool_size=1G # === Configuración WSREP (Galera) === wsrep_on=ON wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so # Lista de TODOS los nodos del cluster wsrep_cluster_address=\u0026#34;gcomm://10.0.1.11,10.0.1.12,10.0.1.13\u0026#34; # Nombre del cluster (debe ser idéntico en todos los nodos) wsrep_cluster_name=\u0026#34;galera_produccion\u0026#34; # Identidad de ESTE nodo (cambia en cada servidor) wsrep_node_address=\u0026#34;10.0.1.11\u0026#34; wsrep_node_name=\u0026#34;db-node1\u0026#34; # Método SST (State Snapshot Transfer) wsrep_sst_method=mariabackup wsrep_sst_auth=\u0026#34;sst_user:password_segura_aqui\u0026#34; # === Red === bind-address=0.0.0.0 Para el Nodo 2 y el Nodo 3, lo único que cambia es:\n# Nodo 2 wsrep_node_address=\u0026#34;10.0.1.12\u0026#34; wsrep_node_name=\u0026#34;db-node2\u0026#34; # Nodo 3 wsrep_node_address=\u0026#34;10.0.1.13\u0026#34; wsrep_node_name=\u0026#34;db-node3\u0026#34; Todo lo demás es idéntico. Idéntico. No ceder a la tentación de \u0026ldquo;personalizar\u0026rdquo; buffer pool u otros parámetros por nodo: en un cluster Galera, la simetría es una virtud.\nPor qué cada parámetro importa #Veamos los parámetros uno por uno, porque cada uno tiene una razón precisa.\nbinlog_format=ROW #Galera requiere el formato ROW para el binary log. Ni STATEMENT, ni MIXED. ROW y punto. Con otros formatos el cluster ni siquiera arranca — y con razón, porque la replicación síncrona basada en certification depende de la precisión a nivel de fila.\ninnodb_autoinc_lock_mode=2 #Este parámetro configura el modo de bloqueo para auto-increment en \u0026ldquo;interleaved\u0026rdquo;. En un cluster multi-master, dos nodos pueden generar INSERT simultáneamente en la misma tabla. Con el lock mode 1 (el predeterminado) se crearían deadlocks. Con el valor 2, InnoDB genera los auto-increment sin lock global, permitiendo inserciones concurrentes desde nodos diferentes.\nLa consecuencia: los IDs auto-increment no serán secuenciales entre nodos. Si tu aplicación depende de la secuencialidad de los IDs, tienes un problema arquitectónico que resolver antes.\ninnodb_flush_log_at_trx_commit=2 #Aquí se hace un compromiso consciente. El valor 1 (predeterminado) garantiza durabilidad total — cada commit se escribe y se hace fsync al disco. Pero en un cluster Galera, la durabilidad ya está garantizada por la replicación síncrona en tres nodos. El valor 2 escribe en el buffer del sistema operativo en cada commit y hace fsync solo cada segundo, mejorando el rendimiento de escritura en un 30-40% en nuestras pruebas.\nSi pierdes un nodo, los datos están en los otros dos. Si pierdes el datacenter entero\u0026hellip; bueno, esa es otra conversación.\nwsrep_sst_method=mariabackup #SST es el mecanismo por el cual un nodo que se une al cluster recibe una copia completa de los datos. Las opciones son:\nMétodo Pro Contra rsync Rápido El nodo donante se bloquea en lectura mariabackup No bloquea al donante Requiere instalación separada mysqldump Simple Lentísimo, bloquea al donante Siempre mariabackup. En producción, bloquear un nodo donante durante un SST significa degradar el cluster en el momento que más lo necesitas.\n# Instalar mariabackup en todos los nodos sudo dnf install MariaDB-backup -y Firewall: los puertos que Galera necesita abiertos #Este es el punto donde veo fallar el 50% de las primeras instalaciones. Galera no usa solo el puerto de MySQL.\n# En los tres nodos sudo firewall-cmd --permanent --add-port=3306/tcp # MySQL estándar sudo firewall-cmd --permanent --add-port=4567/tcp # Comunicación cluster Galera sudo firewall-cmd --permanent --add-port=4567/udp # Replicación multicast (opcional) sudo firewall-cmd --permanent --add-port=4568/tcp # IST (Incremental State Transfer) sudo firewall-cmd --permanent --add-port=4444/tcp # SST (State Snapshot Transfer) sudo firewall-cmd --reload Si SELinux está activo (y debería estarlo), también necesitas las políticas:\nsudo setsebool -P mysql_connect_any 1 Cuatro puertos. Cuatro. Ni uno más, ni uno menos. Si olvidas uno, el cluster se forma pero no sincroniza — y el debug se convierte en un ejercicio de frustración.\nLa migración de datos y el bootstrap #Antes de iniciar el cluster, migré los datos del servidor standalone al Nodo 1 con un dump completo:\n# En el antiguo servidor standalone mysqldump --all-databases --single-transaction --routines --triggers \\ --events \u0026gt; /tmp/full_dump.sql # Transferencia al Nodo 1 scp /tmp/full_dump.sql db-node1:/tmp/ Luego el bootstrap — el momento de la verdad. El primer nodo no se inicia con systemctl start mariadb. Se inicia con el comando de bootstrap.\nSolo en el Nodo 1:\nsudo galera_new_cluster Este comando inicia MariaDB con wsrep_cluster_address=gcomm:// (vacío), que significa: \u0026ldquo;Yo soy el fundador, no busco otros nodos.\u0026rdquo;\nImportación de datos y creación del usuario SST:\n-- Importar el dump del antiguo servidor SOURCE /tmp/full_dump.sql; -- Crear el usuario para la transferencia de datos entre nodos CREATE USER \u0026#39;sst_user\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;password_segura_aqui\u0026#39;; GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO \u0026#39;sst_user\u0026#39;@\u0026#39;localhost\u0026#39;; FLUSH PRIVILEGES; Verificación inmediata:\nSHOW STATUS LIKE \u0026#39;wsrep_cluster_size\u0026#39;; -- +--------------------+-------+ -- | Variable_name | Value | -- +--------------------+-------+ -- | wsrep_cluster_size | 1 | -- +--------------------+-------+ Si el valor es 1, el bootstrap funcionó. Ahora, en los otros dos nodos:\nsudo systemctl start mariadb Estos nodos leen wsrep_cluster_address, encuentran al Nodo 1, reciben un SST completo con todos los datos y se unen al cluster.\nDespués de iniciar los tres:\nSHOW STATUS LIKE \u0026#39;wsrep_cluster_size\u0026#39;; -- +--------------------+-------+ -- | Variable_name | Value | -- +--------------------+-------+ -- | wsrep_cluster_size | 3 | -- +--------------------+-------+ Tres. Ese es el número mágico. El momento en que el cliente dejó de tener un single point of failure.\nVerificar el estado de salud del cluster #Esta es la parte que realmente importa a quien gestiona el cluster día a día. No basta con saber que wsrep_cluster_size es 3. Hay que saber leer el estado completo.\nLa query diagnóstica que uso siempre #SHOW STATUS WHERE Variable_name IN ( \u0026#39;wsrep_cluster_size\u0026#39;, \u0026#39;wsrep_cluster_status\u0026#39;, \u0026#39;wsrep_connected\u0026#39;, \u0026#39;wsrep_ready\u0026#39;, \u0026#39;wsrep_local_state_comment\u0026#39;, \u0026#39;wsrep_incoming_addresses\u0026#39;, \u0026#39;wsrep_evs_state\u0026#39;, \u0026#39;wsrep_flow_control_paused\u0026#39;, \u0026#39;wsrep_local_recv_queue_avg\u0026#39;, \u0026#39;wsrep_local_send_queue_avg\u0026#39;, \u0026#39;wsrep_cert_deps_distance\u0026#39; ); Cómo interpretar los resultados # Variable Valor sano Significado wsrep_cluster_size 3 Todos los nodos están en el cluster wsrep_cluster_status Primary El cluster está operativo y tiene quorum wsrep_connected ON Este nodo está conectado al cluster wsrep_ready ON Este nodo acepta queries wsrep_local_state_comment Synced Este nodo está sincronizado wsrep_flow_control_paused 0.0 Sin pausas por flow control wsrep_local_recv_queue_avg \u0026lt; 0.5 La cola de recepción está bajo control wsrep_local_send_queue_avg \u0026lt; 0.5 La cola de envío está bajo control Las señales de peligro #wsrep_cluster_status = Non-Primary: el nodo ha perdido el quorum. Está aislado. No aceptará escrituras (y no debe). Esto sucede cuando un nodo pierde la conexión con la mayoría del cluster.\nwsrep_flow_control_paused \u0026gt; 0.0: flow control activado. Significa que un nodo es demasiado lento aplicando transacciones y está pidiendo a los demás que frenen. Un valor cercano a 1.0 significa que el cluster está esencialmente detenido, esperando al nodo más lento.\nwsrep_local_recv_queue_avg \u0026gt; 1.0: las transacciones entrantes se acumulan. Podría ser un problema de I/O de disco, CPU, o un nodo subdimensionado.\nScript de monitorización #También entregué al cliente un script para su sistema de monitorización (Zabbix, en su caso):\n#!/bin/bash # galera_health_check.sh — ejecutar en cada nodo MYSQL=\u0026#34;mysql -u monitor -p\u0026#39;monitor_pwd\u0026#39; -Bse\u0026#34; CLUSTER_SIZE=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_cluster_size\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) CLUSTER_STATUS=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_cluster_status\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) NODE_STATE=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_local_state_comment\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) FLOW_CONTROL=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_flow_control_paused\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) if [ \u0026#34;$CLUSTER_SIZE\u0026#34; -lt 3 ] || [ \u0026#34;$CLUSTER_STATUS\u0026#34; != \u0026#34;Primary\u0026#34; ] || [ \u0026#34;$NODE_STATE\u0026#34; != \u0026#34;Synced\u0026#34; ]; then echo \u0026#34;CRITICAL: Galera cluster degradado\u0026#34; echo \u0026#34; Size: $CLUSTER_SIZE | Status: $CLUSTER_STATUS | State: $NODE_STATE | FC: $FLOW_CONTROL\u0026#34; exit 2 fi echo \u0026#34;OK: Galera cluster sano (3 nodos, Primary, Synced)\u0026#34; exit 0 El problema del split-brain : por qué tres nodos y no dos #Cuando presenté la solución al cliente, la primera pregunta fue: \u0026ldquo;¿De verdad necesitamos tres servidores? ¿No bastan dos?\u0026rdquo;\nNo. Y no es una cuestión de coste — es una cuestión de matemáticas.\nGalera usa un algoritmo de consenso basado en **quorum** . Con tres nodos, el quorum es 2: si un nodo cae, los otros dos reconocen que son la mayoría y siguen operando. Con dos nodos, el quorum es 2: si un nodo cae, el que queda no tiene quorum y se bloquea para evitar el split-brain.\nExiste el parámetro pc.ignore_quorum para forzar a un nodo a operar sin quorum, pero es como desactivar la alarma de incendios porque suena demasiado a menudo.\nTres nodos es el mínimo para un cluster Galera en producción. El tercer nodo no es un lujo — es lo que permite al cluster seguir funcionando cuando las cosas van mal.\nCuando un nodo cae y vuelve #Una de las primeras cosas que hice después de la puesta en producción fue simular un fallo — con el cliente mirando.\nApagué el Nodo 3. La aplicación siguió funcionando sin interrupción en los nodos 1 y 2. Sin errores, sin timeouts. Doscientos usuarios que no se enteraron de nada.\nLuego reinicié el Nodo 3. Qué pasó:\nEl nodo arrancó y contactó a los demás a través de wsrep_cluster_address El gap de transacciones era pequeño, así que recibió un **IST** (Incremental State Transfer) — solo las transacciones faltantes En menos de un minuto estaba en Synced de nuevo Si el nodo hubiera estado caído más tiempo y el gcache se hubiera superado, habría recibido un SST completo — el dataset entero. Por eso el parámetro gcache.size es importante:\nwsrep_provider_options=\u0026#34;gcache.size=512M\u0026#34; Un gcache más grande significa que el cluster puede tolerar tiempos de inactividad más largos de un nodo sin necesitar un SST completo. En el caso del cliente, con unos 80-100 MB de transacciones al día, un gcache de 512 MB cubría casi una semana de ausencia.\nEl cliente vio al Nodo 3 volver a sincronizarse y dijo: \u0026ldquo;Entonces, ¿la próxima vez que necesitemos hacer mantenimiento en un servidor no tenemos que parar todo?\u0026rdquo; Exacto. Ese era el punto.\nChecklist de puesta en producción #Antes de declarar el cluster listo al cliente, verifiqué cada punto:\nMisma versión de MariaDB en todos los nodos wsrep_cluster_size = 3 wsrep_cluster_status = Primary en todos los nodos wsrep_local_state_comment = Synced en todos los nodos Test de escritura en Nodo 1, verificación de lectura en Nodo 2 y 3 Test de apagado de un nodo: el cluster sigue funcionando Test de rejoin: el nodo vuelve a Synced sin SST completo Usuario SST configurado y funcionando Firewall verificado en todos los puertos (3306, 4567, 4568, 4444) Monitorización activa sobre wsrep_cluster_status y wsrep_flow_control_paused Backup configurado (en UN nodo, no en los tres) Aplicación reconfigurada para apuntar al load balancer o al VIP Seis meses después #Contacté con el cliente seis meses después de la puesta en producción. Mientras tanto habían tenido dos reinicios programados por actualizaciones de sistema y un fallo imprevisto de disco en uno de los nodos. En los tres casos, la aplicación nunca dejó de funcionar. Cero tiempo de inactividad no planificado.\nLo que más me impactó fue su frase: \u0026ldquo;Antes vivíamos con la ansiedad de que la base de datos cayera. Ahora ya no pensamos en eso.\u0026rdquo;\nEse es el verdadero valor de un cluster Galera bien configurado. No es la tecnología en sí — es la tranquilidad que trae. La certeza de que un único fallo ya no para la empresa.\nLa parte técnica es la más sencilla. Lo que marca la diferencia es entender por qué cada parámetro está configurado de cierta manera, qué pasa cuando las cosas van mal, y cómo diagnosticar los problemas antes de que se conviertan en emergencias. Un cluster que funciona en demo y uno que aguanta en producción: la distancia entre los dos está toda en los detalles que he contado aquí.\nGlosario #Quorum — Mecanismo de consenso basado en la mayoría de nodos. Con 3 nodos el quorum es 2: si uno cae, los otros dos continúan operando. Es lo que previene el split-brain.\nSST — State Snapshot Transfer: mecanismo por el cual un nodo que se une al cluster recibe una copia completa del dataset entero desde un nodo donante. El método recomendado es mariabackup.\nIST — Incremental State Transfer: transferencia de solo las transacciones faltantes a un nodo que reingresa al cluster después de una ausencia breve. Mucho más rápido que un SST completo.\nWSREP — Write Set Replication: API y protocolo de replicación síncrona usado por Galera Cluster. Cada transacción se replica en todos los nodos antes del commit mediante un proceso de certification.\nSplit-brain — Condición crítica donde dos partes del cluster operan independientemente aceptando escrituras divergentes. El quorum lo previene: solo la partición con la mayoría de nodos puede seguir operando.\n","date":"17 febrero 2026","permalink":"https://ivanluminaria.com/es/posts/mysql/galera-cluster-3-nodi/","section":"Database Strategy","summary":"\u003cp\u003eEl ticket era lacónico, como suele pasar cuando el problema es grave: \u0026ldquo;La base de datos se cayó otra vez. La aplicación está parada. Tercera vez en dos meses.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eEl cliente tenía un MariaDB en un único servidor Linux — una aplicación de gestión empresarial usada por unos doscientos usuarios internos, con picos de carga durante los cierres contables de fin de mes. Cada vez que el servidor tenía un problema — un disco que se ralentizaba, una actualización del sistema que requería reinicio, un proceso que consumía toda la RAM — la base de datos caía y con ella toda la operatividad empresarial.\u003c/p\u003e","title":"Galera Cluster con 3 nodos: cómo resolví un problema de disponibilidad en MySQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/high-availability/","section":"Tags","summary":"","title":"High-Availability"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/wsrep/","section":"Tags","summary":"","title":"Wsrep"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/ash/","section":"Tags","summary":"","title":"Ash"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/awr/","section":"Tags","summary":"","title":"Awr"},{"content":"Viernes, 18:40. Ya tenía la chaqueta puesta, listo para salir. El teléfono vibra. Es el project manager.\n\u0026ldquo;Ivan, tenemos un problema. El sistema va lentísimo. Mañana por la mañana es el go-live.\u0026rdquo;\nNo es la primera vez que recibo una llamada así. Pero el tono era diferente. No era la queja genérica sobre la lentitud. Era pánico.\nMe reconecto por VPN, abro una sesión en la base de datos Oracle 19c del cliente. Lo primero que hago es una comprobación rápida:\nSELECT metric_name, value FROM v$sysmetric WHERE metric_name IN (\u0026#39;Database CPU Time Ratio\u0026#39;, \u0026#39;Database Wait Time Ratio\u0026#39;, \u0026#39;Average Active Sessions\u0026#39;); CPU Time Ratio: 12%. En condiciones normales estaba por encima del 80%.\nAverage Active Sessions: 47. En un servidor con 16 cores.\nCuarenta y siete sesiones activas. La base de datos se estaba ahogando.\n🔥 Los síntomas #El equipo de desarrollo había completado el último deploy del código aplicativo esa tarde. Todo parecía funcionar en las pruebas. Pero cuando lanzaron el batch de verificación pre-go-live — el que simula la carga de producción — los tiempos de respuesta explotaron.\nLas queries que normalmente tardaban 2-3 segundos necesitaban 45. Los batches que terminaban en 20 minutos seguían en ejecución después de una hora. Los wait events dominantes eran db file sequential read y db file scattered read — señal inequívoca de I/O físico masivo.\nAlgo estaba leyendo cantidades enormes de datos del disco. Algo que antes no estaba.\n📊 AWR: la fotografía del problema #AWR — Automatic Workload Repository — es la herramienta de diagnóstico más potente que Oracle pone a disposición. Cada hora, Oracle toma una instantánea (snapshot ) de las estadísticas de rendimiento y la conserva en el repositorio interno. Comparando dos snapshots, obtienes un informe que te dice exactamente qué ocurrió en ese período.\nGeneré un snapshot manual para capturar la situación actual:\nEXEC DBMS_WORKLOAD_REPOSITORY.create_snapshot; Luego busqué los snapshots disponibles:\nSELECT snap_id, begin_interval_time, end_interval_time FROM dba_hist_snapshot WHERE begin_interval_time \u0026gt; SYSDATE - 1/6 ORDER BY snap_id DESC; Tenía un snapshot de las 18:00 (antes del problema visible) y el que acababa de crear a las 18:45. Generé el informe AWR:\nSELECT output FROM TABLE(DBMS_WORKLOAD_REPOSITORY.awr_report_text( l_dbid =\u0026gt; (SELECT dbid FROM v$database), l_inst_num =\u0026gt; 1, l_bid =\u0026gt; 4523, l_eid =\u0026gt; 4524 )); Qué decía el informe #La sección Top 5 Timed Foreground Events era elocuente:\nEvent Waits Time (s) % DB time db file scattered read 1.247.832 3.847 58,2% db file sequential read 423.109 1.205 18,2% CPU + Wait for CPU — 892 13,5% log file sync 12.445 287 4,3% direct path read 8.221 198 3,0% db file scattered read al 58%. Son full table scans . Algo estaba leyendo tablas enteras, bloque a bloque, sin usar índices.\nLa sección SQL ordered by Elapsed Time mostraba un solo SQL_ID que consumía el 71% del tiempo total de la base de datos: g4f2h8k1nw3z9.\nAhora sabía qué buscar.\n🔍 ASH: el microscopio #AWR me había dado la fotografía general. Pero necesitaba entender cuándo empezó ese SQL, quién lo ejecutaba, y qué programa lo había lanzado.\nASH — Active Session History — registra el estado de cada sesión activa una vez por segundo. Es el microscopio del DBA: donde AWR te muestra promedios de una hora, ASH te muestra qué ocurría segundo a segundo.\nSELECT sample_time, session_id, sql_id, sql_plan_hash_value, event, program, module FROM v$active_session_history WHERE sql_id = \u0026#39;g4f2h8k1nw3z9\u0026#39; AND sample_time \u0026gt; SYSDATE - 1/24 ORDER BY sample_time DESC; Los resultados eran claros:\nProgram: JDBC Thin Client — la aplicación Java del batch Module: BatchVerificaProduzione Event: db file scattered read en el 92% de las muestras Primera ocurrencia: 17:12 — exactamente después del deploy de la tarde SQL_PLAN_HASH_VALUE: 2891047563 El plan de ejecución había cambiado. Antes del deploy, esa query usaba un plan diferente.\n🧩 El plan de ejecución #Recuperé el plan actual:\nSELECT * FROM TABLE(DBMS_XPLAN.display_awr( sql_id =\u0026gt; \u0026#39;g4f2h8k1nw3z9\u0026#39;, plan_hash_value =\u0026gt; 2891047563 )); El resultado me hizo entender el problema de inmediato:\n--------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | 48721 | | 1 | HASH JOIN | | 2.1M | 48721 | | 2 | TABLE ACCESS FULL | MOVIMENTI_TEMP | 2.1M | 41893 | | 3 | INDEX RANGE SCAN | IDX_CLIENTI_PK | 1 | 2 | --------------------------------------------------------------------------- TABLE ACCESS FULL sobre MOVIMENTI_TEMP. Una tabla temporal con 2,1 millones de filas, leída por completo cada vez. Sin índice. Sin filtro eficaz.\nVerifiqué qué existía antes del deploy consultando el plan anterior en AWR:\nSELECT plan_hash_value, timestamp FROM dba_hist_sql_plan WHERE sql_id = \u0026#39;g4f2h8k1nw3z9\u0026#39; ORDER BY timestamp; El plan anterior (hash 1384726091) usaba un INDEX RANGE SCAN sobre un índice que — descubrimiento — había sido eliminado durante el deploy. El script de migración incluía un DROP TABLE MOVIMENTI_TEMP seguido de una recreación, pero sin recrear el índice.\n⚡ La solución #Diez minutos. Desde el momento en que me conecté hasta que identifiqué la causa. No por habilidad — por las herramientas.\nLa corrección era sencilla:\nCREATE INDEX idx_movimenti_temp_cliente ON movimenti_temp (id_cliente, data_movimento) TABLESPACE idx_data; Después de crear el índice, forcé un re-parse de la query:\nEXEC DBMS_SHARED_POOL.purge(\u0026#39;g4f2h8k1nw3z9\u0026#39;, \u0026#39;C\u0026#39;); Pedí al equipo que relanzara el batch. Tiempo de ejecución: 18 minutos. Idéntico a las pruebas anteriores.\nEl go-live del sábado por la mañana se realizó con normalidad.\n📋 AWR vs ASH: cuándo usar cada uno #Después de aquel episodio formalicé una regla que siempre sigo:\nCaracterística AWR ASH Granularidad Snapshots por hora (configurables) Muestra cada segundo Profundidad histórica Hasta 30 días (por defecto 8) 1 hora en memoria, luego en AWR Caso de uso principal Análisis de tendencias, comparación de períodos Diagnóstico puntual, aislamiento de SQL Vista principal DBA_HIST_* V$ACTIVE_SESSION_HISTORY Vista histórica — DBA_HIST_ACTIVE_SESS_HISTORY Licencia requerida Diagnostic Pack Diagnostic Pack Salida típica Informe HTML/texto Queries ad hoc La regla empírica: AWR para entender qué cambió, ASH para entender por qué.\nAWR te dice: \u0026ldquo;Entre las 17:00 y las 18:00, el 58% del tiempo de la base de datos se gastó en full table scans.\u0026rdquo; ASH te dice: \u0026ldquo;A las 17:12:34, la sesión 847 estaba ejecutando la query g4f2h8k1nw3z9 con un full table scan sobre MOVIMENTI_TEMP, lanzada por el programa BatchVerificaProduzione.\u0026rdquo;\nSon complementarios. Usar solo uno es como diagnosticar un problema mirando solo el TAC o solo los análisis de sangre.\n🛡️ Las queries que todo DBA debería tener preparadas #A lo largo de los años he construido un conjunto de queries diagnósticas que siempre tengo a mano. Las comparto porque en una emergencia no hay tiempo para escribirlas desde cero.\nTop SQL por tiempo de ejecución (última hora) #SELECT sql_id, COUNT(*) AS samples, ROUND(COUNT(*) / 60, 1) AS est_minutes, MAX(event) AS top_event, MAX(program) AS program FROM v$active_session_history WHERE sample_time \u0026gt; SYSDATE - 1/24 AND sql_id IS NOT NULL GROUP BY sql_id ORDER BY samples DESC FETCH FIRST 10 ROWS ONLY; Distribución de wait events para un SQL específico #SELECT event, COUNT(*) AS samples, ROUND(COUNT(*) * 100 / SUM(COUNT(*)) OVER(), 1) AS pct FROM v$active_session_history WHERE sql_id = \u0026#39;\u0026amp;sql_id\u0026#39; AND sample_time \u0026gt; SYSDATE - 1/24 GROUP BY event ORDER BY samples DESC; Comparación de planes de ejecución en el tiempo #SELECT plan_hash_value, MIN(timestamp) AS first_seen, MAX(timestamp) AS last_seen, COUNT(*) AS executions_in_awr FROM dba_hist_sqlstat WHERE sql_id = \u0026#39;\u0026amp;sql_id\u0026#39; GROUP BY plan_hash_value ORDER BY first_seen; 🎯 Qué aprendí aquella noche #Tres lecciones que llevo conmigo.\nPrimera: el deploy no es solo código. Es también estructura. Cuando liberas en producción, debes verificar que índices, constraints, estadísticas y grants sean coherentes con lo que había antes. Un script que hace DROP TABLE y CREATE TABLE sin recrear los índices es una bomba de relojería.\nSegunda: AWR y ASH no son herramientas para DBAs senior. Son herramientas de primera línea, como un desfibrilador. Debes saber usarlas antes de necesitarlas, no durante la emergencia.\nTercera: diez minutos de diagnóstico correcto valen más que tres horas de intentos a ciegas. Cuando el sistema está de rodillas, la tentación es reiniciar, matar sesiones, meter más recursos. Pero sin saber qué está pasando, estás disparando en la oscuridad.\nEsa noche salí de la oficina a las 19:20. Cuarenta minutos después de la llamada. Al día siguiente el go-live arrancó sin contratiempos, y el lunes el sistema funcionaba con normalidad.\nNo soy un héroe. Solo usé las herramientas correctas.\nGlosario #AWR — Automatic Workload Repository. Componente integrado en Oracle que recopila estadisticas de rendimiento mediante snapshots periodicos y genera informes diagnosticos comparativos.\nASH — Active Session History. Componente Oracle que muestrea el estado de cada sesion activa una vez por segundo, almacenandolo en memoria y luego en AWR. Es el microscopio del DBA para el diagnostico puntual.\nFull Table Scan — Operacion de lectura en la que Oracle lee todos los bloques de una tabla sin usar indices. En los wait events aparece como db file scattered read.\nWait Event — Evento de espera registrado por Oracle cada vez que una sesion no puede continuar porque espera un recurso (I/O, lock, CPU, red). El analisis de wait events es la base de la metodologia diagnostica de Oracle.\nSnapshot — Captura puntual de las estadisticas de rendimiento tomada periodicamente por AWR (por defecto cada 60 minutos). La comparacion entre dos snapshots genera el informe AWR.\n","date":"10 febrero 2026","permalink":"https://ivanluminaria.com/es/posts/oracle/oracle-awr-ash/","section":"Database Strategy","summary":"\u003cp\u003eViernes, 18:40. Ya tenía la chaqueta puesta, listo para salir. El teléfono vibra. Es el project manager.\u003c/p\u003e\n\u003cp\u003e\u0026ldquo;Ivan, tenemos un problema. El sistema va lentísimo. Mañana por la mañana es el go-live.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eNo es la primera vez que recibo una llamada así. Pero el tono era diferente. No era la queja genérica sobre la lentitud. Era pánico.\u003c/p\u003e\n\u003cp\u003eMe reconecto por VPN, abro una sesión en la base de datos Oracle 19c del cliente. Lo primero que hago es una comprobación rápida:\u003c/p\u003e","title":"AWR, ASH y los 10 minutos que salvaron un go-live"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/diagnostic/","section":"Tags","summary":"","title":"Diagnostic"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/go-live/","section":"Tags","summary":"","title":"Go-Live"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/grant/","section":"Tags","summary":"","title":"Grant"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/privileges/","section":"Tags","summary":"","title":"Privileges"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/revoke/","section":"Tags","summary":"","title":"Revoke"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/roles/","section":"Tags","summary":"","title":"Roles"},{"content":"La primera vez que trabajé seriamente con PostgreSQL venía de años utilizando otros motores de base de datos. Buscaba el comando CREATE USER. Lo encontraba. Luego veía CREATE ROLE. Luego ALTER USER. Luego ALTER ROLE.\nDurante unos minutos pensé: \u0026ldquo;Vale, aquí alguien se divierte confundiendo a la gente\u0026rdquo;.\nEn realidad no. PostgreSQL es mucho más coherente de lo que parece. Solo que lo es a su manera.\nEn PostgreSQL no existen usuarios. Existen roles. #La clave es esta: en PostgreSQL todo es un ROLE.\nUn ROLE puede:\ntener derecho de login\\ no tener derecho de login\\ poseer objetos\\ heredar permisos de otros roles\\ ser utilizado como contenedor de privilegios Lo que en otros motores llamas \u0026ldquo;usuario\u0026rdquo; en PostgreSQL es simplemente un rol con el atributo LOGIN.\nDe hecho:\nCREATE USER mario; no es más que un atajo para:\nCREATE ROLE mario WITH LOGIN; Lo mismo ocurre con ALTER USER: es solo un alias de ALTER ROLE.\n¿Por qué solo existen realmente CREATE ROLE y ALTER ROLE?\nPorque PostgreSQL no distingue conceptualmente entre usuario y rol. Es el mismo objeto con atributos distintos. Minimalista. Elegante. Coherente.\nSi un rol tiene LOGIN, se comporta como un usuario.\nSi no tiene LOGIN, es un contenedor de permisos.\nCuando lo entiendes de verdad, cambia la forma en que diseñas la seguridad.\nEl modelo mental correcto #Hoy razono así:\nCreo roles \u0026ldquo;funcionales\u0026rdquo; que representan conjuntos de privilegios\\ Asigno esos roles a los usuarios reales\\ Evito conceder permisos directamente a los usuarios ¿Por qué? Porque los usuarios cambian. Los roles no.\nSi mañana llega un nuevo compañero, no reescribo medio sistema de grants.\nLe asigno el rol adecuado y listo.\nArquitectura limpia. Cero magia. Cero caos.\nUna historia real (sin nombres incómodos) #Hace un tiempo me pidieron crear un usuario de solo lectura para un sistema de monitorización.\nSolicitud aparentemente simple: \u0026ldquo;Debe leer algunas tablas. Nada de escritura.\u0026rdquo;\nEl clásico \u0026ldquo;si total es solo read-only\u0026rdquo;.\nLa trampa es siempre la misma: si solo ejecutas un GRANT SELECT sobre las tablas existentes, funciona hoy.\nDentro de tres meses alguien crea una nueva tabla y el sistema de monitorización empieza a lanzar errores.\nY adivina a quién llaman.\nLa solución correcta requiere atención en cuatro niveles:\nPermiso de conexión al database\\ Permiso de uso del esquema (USAGE)\\ Permisos SELECT sobre tablas y secuencias existentes\\ Default privileges para los objetos futuros Si te saltas una pieza, tarde o temprano pagas el precio.\nEjemplo: creación correcta de un usuario read-only #Supongamos que queremos crear un usuario de solo lectura sobre dos esquemas.\nPrimero creo el rol con login:\nCREATE ROLE srv_monitorizacion WITH LOGIN PASSWORD \u0026#39;PasswordSegura123#\u0026#39;; Lo aseguro:\nALTER ROLE srv_monitorizacion NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT; Permito la conexión al database:\nGRANT CONNECT ON DATABASE mydb TO srv_monitorizacion; Permiso de uso de los esquemas:\nGRANT USAGE ON SCHEMA schema1 TO srv_monitorizacion; GRANT USAGE ON SCHEMA schema2 TO srv_monitorizacion; Permisos de lectura sobre los objetos existentes:\nGRANT SELECT ON ALL TABLES IN SCHEMA schema1 TO srv_monitorizacion; GRANT SELECT ON ALL TABLES IN SCHEMA schema2 TO srv_monitorizacion; GRANT SELECT ON ALL SEQUENCES IN SCHEMA schema1 TO srv_monitorizacion; GRANT SELECT ON ALL SEQUENCES IN SCHEMA schema2 TO srv_monitorizacion; Y ahora la parte que muchos olvidan:\nALTER DEFAULT PRIVILEGES IN SCHEMA schema1 GRANT SELECT ON TABLES TO srv_monitorizacion; ALTER DEFAULT PRIVILEGES IN SCHEMA schema2 GRANT SELECT ON TABLES TO srv_monitorizacion; Así también las tablas futuras serán legibles.\nNota importante: los ALTER DEFAULT PRIVILEGES se aplican al rol que crea los objetos. Si varios owners crean tablas en los mismos esquemas, la configuración debe replicarse para cada uno.\nPor qué este modelo es potente #El hecho de que todo sea un ROLE permite construir jerarquías limpias.\nEjemplo avanzado:\nCREATE ROLE role_readonly; GRANT SELECT ON ALL TABLES IN SCHEMA schema1 TO role_readonly; CREATE ROLE srv_monitorizacion WITH LOGIN PASSWORD \u0026#39;...\u0026#39;; GRANT role_readonly TO srv_monitorizacion; Ahora puedo asignar role_readonly a diez usuarios distintos sin duplicar grants.\nEsto es diseño. No solo sintaxis.\nConclusión #PostgreSQL no complica el concepto de usuario. Lo simplifica.\nExiste un único tipo de objeto: el ROLE. Depende de nosotros usarlo bien.\nSi lo tratas como un simple \u0026ldquo;usuario con contraseña\u0026rdquo;, funciona.\nSi lo usas como un bloque arquitectónico, se convierte en una herramienta poderosa para diseñar una seguridad limpia, escalable y mantenible.\nLa diferencia no está en los comandos.\nEstá en el modelo mental con el que los utilizas.\nGlosario #ROLE — Entidad fundamental de PostgreSQL que unifica el concepto de usuario y grupo de permisos: un ROLE con LOGIN es un usuario, sin LOGIN es un contenedor de privilegios.\nDEFAULT PRIVILEGES — Mecanismo PostgreSQL que define automáticamente los privilegios a asignar a todos los objetos futuros creados en un schema, evitando repetir los GRANT manualmente.\nSchema — Namespace lógico dentro de una base de datos que agrupa tablas, vistas, funciones y otros objetos, permitiendo organización y separación de permisos.\nGRANT — Comando SQL para asignar privilegios específicos a un usuario o rol sobre bases de datos, tablas o columnas.\nLeast Privilege — Principio de seguridad que prevé asignar a cada usuario solo los permisos estrictamente necesarios para desempeñar su función.\n","date":"10 febrero 2026","permalink":"https://ivanluminaria.com/es/posts/postgresql/postgresql_roles_and_users/","section":"Database Strategy","summary":"\u003cp\u003eLa primera vez que trabajé seriamente con PostgreSQL venía de\naños utilizando otros motores de base de datos. Buscaba el comando \u003ccode\u003eCREATE USER\u003c/code\u003e. Lo encontraba.\nLuego veía \u003ccode\u003eCREATE ROLE\u003c/code\u003e. Luego \u003ccode\u003eALTER USER\u003c/code\u003e. Luego \u003ccode\u003eALTER ROLE\u003c/code\u003e.\u003cbr\u003e\nDurante unos minutos pensé: \u0026ldquo;Vale, aquí alguien se divierte confundiendo\na la gente\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eEn realidad no. PostgreSQL es mucho más coherente de lo que parece.\nSolo que lo es a su manera.\u003c/p\u003e\n\u003ch2 id=\"en-postgresql-no-existen-usuarios-existen-roles\" class=\"relative group\"\u003eEn PostgreSQL no existen usuarios. Existen roles. \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#en-postgresql-no-existen-usuarios-existen-roles\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa clave es esta: \u003cstrong\u003een PostgreSQL todo es un ROLE\u003c/strong\u003e.\u003c/p\u003e","title":"Roles y usuarios en PostgreSQL: por qué todo es (solo) un ROLE"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/security/","section":"Tags","summary":"","title":"Security"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/bug-fixing/","section":"Tags","summary":"","title":"Bug-Fixing"},{"content":"Me llama un cliente. Voz tensa, palabras medidas.\n\u0026ldquo;Ivan, tenemos un problema. Mejor dicho, tenemos el problema.\u0026rdquo;\nConozco ese tono. Es el tono de quien ya ha intentado resolver las cosas internamente, ha fracasado, y ahora busca a alguien que le diga la verdad sin rodeos.\nEl problema es un software de gestión — no un sitio web, no una app — un sistema crítico sobre el que funcionan procesos empresariales importantes. Tiene algunos años. Creció rápido, como siempre sucede cuando el negocio corre más rápido que la arquitectura. Y ahora se ha acumulado todo: bugs abiertos que nadie cierra, solicitudes de evolución que nadie planifica, desarrolladores que trabajan en versiones diferentes del código sin saber qué hace el otro.\nEl clásico escenario que, en palabras, \u0026ldquo;funciona\u0026rdquo;. Pero que por dentro es un campo minado.\n🧠 La primera reunión: entender qué es lo que realmente no funciona #Cuando entro en un proyecto como este, no miro el código primero.\nMiro a las personas. Miro cómo se comunican. Miro dónde se pierde la información.\nEl equipo estaba compuesto por cuatro desarrolladores buenos. Serios. Competentes.\nPero trabajaban así:\nel código estaba en una carpeta compartida en la red los cambios se comunicaban por email o en una hoja Excel los bugs se reportaban verbalmente, por chat, por tickets — sin un criterio único nadie sabía con certeza cuál era la versión \u0026ldquo;buena\u0026rdquo; del software ¿Y sabes qué pasa en estas situaciones?\nCada uno tiene razón desde su punto de vista. Pero el proyecto, en su conjunto, está fuera de control.\nEl problema no es técnico. Es organizativo.\nY aquí cambia todo.\n📌 La propuesta: GitHub como columna vertebral del proyecto #Lo primero que puse sobre la mesa fue claro, directo, sin adornos:\nAdoptamos GitHub. Todo el código pasa por ahí. Sin excepciones.\nNo es cuestión de moda. No es porque \u0026ldquo;lo hacen todos\u0026rdquo;.\nEs porque GitHub resuelve, con herramientas concretas, problemas que ninguna hoja Excel podrá gestionar jamás:\nVersionado real: cada cambio está rastreado, comentado, reversible Branches y Pull Requests : cada desarrollador trabaja en su copia, luego propone los cambios al equipo — no sobrescribe el trabajo de los demás Issue tracker integrado: los bugs y las solicitudes de evolución viven en el mismo lugar que el código Historial completo: quién hizo qué, cuándo, por qué Vi la cara del desarrollador senior. Una mezcla de curiosidad y desconfianza.\n\u0026ldquo;Pero nosotros siempre lo hemos hecho así.\u0026rdquo;\nLe respondí con calma: \u0026ldquo;Lo sé. Y el resultado es la razón por la que estoy aquí.\u0026rdquo;\nNo lo dije para provocar. Lo dije porque es la verdad.\nY la verdad, cuando se dice de la manera correcta, no ofende. Libera.\n🔬 El segundo paso: la AI como acelerador, no como sustituto #Una vez definido el flujo de trabajo en GitHub — branches, review, merge controlados — hice la segunda propuesta.\n\u0026ldquo;Integremos la inteligencia artificial en el proceso de resolución de bugs.\u0026rdquo;\nSilencio.\nEntiendo la reacción. Cuando dices \u0026ldquo;AI\u0026rdquo; en una sala de desarrolladores, la mitad piensa en ChatGPT generando código al azar, la otra mitad piensa que les estás diciendo que su trabajo ya no sirve.\nNinguna de las dos cosas.\nLo que propuse es muy diferente:\nCuando un desarrollador toma un bug, antes de escribir una línea de código, usa la AI para analizar el contexto La AI lee el código involucrado, los logs, la descripción del problema Propone hipótesis. No soluciones definitivas — hipótesis razonadas El desarrollador evalúa, verifica, y luego implementa La AI no sustituye al programador.\nLa AI le ahorra las primeras dos horas de análisis — esas en las que estás leyendo código escrito por otra persona, intentando entender qué diablos pasa.\nY esas dos horas, multiplicadas por cada bug, por cada desarrollador, por cada semana, se convierten en un número que cambia las cuentas del proyecto.\n📊 Los números que puse sobre la mesa #No vendí sueños. Presenté estimaciones conservadoras.\nEl equipo gestionaba una media de 15-20 bugs por semana.\nEl tiempo medio de resolución era de aproximadamente 6 horas por bug (entre análisis, fix, testing, deploy).\nCon la introducción de GitHub + AI en el workflow, mi estimación era:\nMétrica Antes Después (estimación) Tiempo medio análisis bug ~2.5 horas ~15/20 minutos Tiempo total resolución ~6 horas ~30 minutos Bugs resueltos por semana 15-20 180-240 Conflictos de código frecuentes raros Visibilidad estado proyecto ninguna completa Una reducción de más del 90% en el tiempo total de resolución.\nUn aumento de 12 veces en la capacidad del equipo para cerrar tickets.\nSin contratar a nadie. Sin cambiar a las personas. Cambiando el método.\n🛠️ Cómo funciona en la práctica #El workflow que diseñé es simple. Intencionadamente simple.\n1. El bug llega como Issue en GitHub\nTítulo claro, descripción, etiqueta de prioridad. Basta de emails, basta de chat.\n2. El desarrollador crea un branch dedicado\nfix/issue-234-error-calculo-iva — el nombre lo dice todo.\n3. Antes de tocar el código, consulta a la AI\nLe pasa el código involucrado, el error, el contexto. La AI devuelve un análisis estructurado: dónde podría estar el problema, qué archivos están involucrados, qué tests verificar.\n4. El desarrollador implementa el fix\nCon una ventaja enorme: ya sabe dónde mirar.\n5. Pull Request con revisión Un colega revisa el código. No por formalidad — por calidad.\n6. Merge en el branch principal\nSolo después de la aprobación. El código \u0026ldquo;bueno\u0026rdquo; sigue siendo bueno.\n7. El Issue se cierra automáticamente\nTrazabilidad completa. Del problema a la solución, todo documentado.\n📈 Qué cambió después de tres semanas #Los primeros días fueron los más duros. Siempre es así.\nNuevas herramientas, nuevos hábitos, la tentación de volver al \u0026ldquo;cómo se hacía antes\u0026rdquo;.\nPero después de tres semanas ocurrió algo.\nEl desarrollador senior — el que me había mirado con desconfianza — me escribió:\n\u0026ldquo;Ivan, ayer resolví un bug que el año pasado me había bloqueado durante dos días. Con la AI tardé cuarenta minutos. No porque la AI escribió el código. Sino porque me mostró inmediatamente dónde estaba el problema.\u0026rdquo;\nAhí está. Ese es el punto.\nLa AI no escribe mejor código que un desarrollador experto.\nLa AI acelera el camino entre el problema y la comprensión del problema.\nY la comprensión es siempre el paso más costoso.\n🎯 La lección que me llevo a casa #Cada vez que entro en un proyecto en dificultades, encuentro el mismo patrón:\nPersonas competentes Herramientas inadecuadas Procesos ausentes o informales Frustración creciente La solución nunca es \u0026ldquo;trabajar más\u0026rdquo;.\nLa solución es trabajar de manera diferente.\nGitHub no es una herramienta para desarrolladores. Es una herramienta para equipos.\nLa AI no es un juguete. Es un multiplicador de competencia.\nPero ninguno de los dos funciona si no hay alguien que mire el proyecto desde arriba, entienda dónde se pierden las horas, y tenga el coraje de decir: \u0026ldquo;Cambiemos.\u0026rdquo;\n💬 Para quienes se reconocen en esta historia #Si estás gestionando un proyecto de software y te ves reflejado en lo que he descrito — el código disperso, los bugs que vuelven, el equipo que trabaja mucho pero cierra poco — ten claro que no es culpa de las personas.\nEs culpa del sistema en el que trabajan.\nY el sistema se puede cambiar.\nSe debe cambiar.\nNo hacen falta revoluciones. Hacen falta decisiones precisas, implementadas con método.\nUn repositorio compartido. Un flujo de trabajo claro. Un asistente inteligente que acelera el análisis.\nTres cosas. Tres decisiones.\nQue transforman el caos en control.\nGlosario #Pull Request — Solicitud formal de incorporar cambios de un branch al branch principal, con code review obligatoria. El mecanismo que garantiza que el código \u0026ldquo;bueno\u0026rdquo; siga siendo bueno.\nVersion Control — Sistema que rastrea cada cambio en el código, manteniendo el historial completo. Git es el estándar; GitHub añade colaboración sobre Git.\nIssue Tracker — Sistema de seguimiento integrado para bugs y solicitudes de evolución. En GitHub, las issues viven en el mismo lugar que el código, con trazabilidad del problema a la solución.\nCode Review — Revisión del código por parte de un colega antes del merge. Captura bugs, mejora la calidad y difunde el conocimiento del codebase en el equipo.\nBranch — Rama de desarrollo independiente que permite trabajar en cambios aislados sin afectar el código principal hasta el merge aprobado.\n","date":"3 febrero 2026","permalink":"https://ivanluminaria.com/es/posts/project-management/ai-github-project-management/","section":"Database Strategy","summary":"\u003cp\u003eMe llama un cliente. Voz tensa, palabras medidas.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Ivan, tenemos un problema. Mejor dicho, tenemos \u003cstrong\u003eel\u003c/strong\u003e problema.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eConozco ese tono. Es el tono de quien ya ha intentado resolver las cosas internamente, ha fracasado, y ahora busca a alguien que le diga la verdad sin rodeos.\u003c/p\u003e\n\u003cp\u003eEl problema es un software de gestión — no un sitio web, no una app — un sistema crítico sobre el que funcionan procesos empresariales importantes. Tiene algunos años. Creció rápido, como siempre sucede cuando el negocio corre más rápido que la arquitectura. Y ahora se ha acumulado todo: bugs abiertos que nadie cierra, solicitudes de evolución que nadie planifica, desarrolladores que trabajan en versiones diferentes del código sin saber qué hace el otro.\u003c/p\u003e","title":"Cuando el caos se convierte en método: AI y GitHub para gestionar un proyecto que nadie quería tocar"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/github/","section":"Tags","summary":"","title":"Github"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/software-evolution/","section":"Tags","summary":"","title":"Software-Evolution"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/workflow/","section":"Tags","summary":"","title":"Workflow"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/agile/","section":"Tags","summary":"","title":"Agile"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/audit/","section":"Tags","summary":"","title":"Audit"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/meeting/","section":"Tags","summary":"","title":"Meeting"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/scrum/","section":"Tags","summary":"","title":"Scrum"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/standup/","section":"Tags","summary":"","title":"Standup"},{"content":"Primer lunes del proyecto. Equipo nuevo, metodología nueva, esperanzas nuevas. El PM propone el standup diario. Todos asienten. \u0026ldquo;Quince minutos, de pie, tres preguntas. Simple.\u0026rdquo;\nLa primera semana funciona. A las 9:15 se empieza, a las 9:28 ya estás en tu escritorio. Cada uno dice lo suyo en dos minutos, se señalan los bloqueos, se despiden. Eficiencia pura.\nLa segunda semana alguien levanta la mano a mitad de ronda: \u0026ldquo;¿Puedo explicar un momento el problema que tengo con la integración?\u0026rdquo; Cinco minutos de discusión técnica entre dos personas. Los otros seis se quedan escuchando algo que no les concierne.\nLa tercera semana el standup dura treinta y cinco minutos. Alguien trae el portátil. Otro se sienta. La ronda de las tres preguntas se ha convertido en una reunión de estado con discusiones abiertas, demos improvisadas y debates arquitectónicos.\nEn la cuarta semana el equipo empieza a saltarse el standup. \u0026ldquo;Total, ya dura media hora, no tengo tiempo.\u0026rdquo;\nHe visto esta secuencia al menos diez veces en mi carrera. No es mala suerte. Es un patrón.\n⏱️ Por qué la restricción de los 15 minutos no es negociable #El standup tiene un solo propósito: sincronizar al equipo. No es una reunión de análisis. No es un momento de resolución de problemas. No es una sesión de diseño. Es un punto de alineación rápido.\nY la restricción temporal es lo que lo hace posible.\nCuando el standup dura 15 minutos, ocurren cosas específicas:\nLas personas se preparan antes de la reunión, porque saben que tienen dos minutos Los problemas se señalan, no se resuelven. La resolución ocurre después, entre las personas involucradas El equipo mantiene la percepción de que el standup es útil y respetuoso con su tiempo Nadie llega pensando \u0026ldquo;ahí va, otra media hora tirada\u0026rdquo; Cuando el standup pasa de 20 minutos, el mecanismo se rompe:\nDuración Efecto en el equipo 10-15 min Foco alto, participación activa, percepción positiva 15-20 min Aceptable, pero algunos empiezan a distraerse 20-30 min Las personas no involucradas en los hilos largos se desconectan mentalmente 30-45 min El equipo percibe el standup como pérdida de tiempo. Empiezan las ausencias 45+ min El standup está muerto. Se ha convertido en una reunión de estado disfrazada de práctica ágil Lo más peligroso no es el desbordamiento en sí. Es que ocurre gradualmente. Tres minutos más hoy, cinco mañana. Nadie se da cuenta hasta que es demasiado tarde.\n❓ Las tres preguntas — y nada más #El standup clásico se basa en tres preguntas:\n¿Qué hice ayer? ¿Qué haré hoy? ¿Hay algo que me bloquea? Simple. Pero la simplicidad es traidora, porque la tentación de expandir es constante.\n\u0026ldquo;Qué hice ayer\u0026rdquo; no significa contar tu jornada. Significa decir: \u0026ldquo;Cerré la migración de las tablas lookup\u0026rdquo; o \u0026ldquo;Trabajé en el bug #247, aún no lo resolví.\u0026rdquo; Diez segundos, no tres minutos.\n\u0026ldquo;Qué haré hoy\u0026rdquo; no es un plan detallado. Es una declaración de intención: \u0026ldquo;Hoy termino el bug #247 y empiezo las pruebas de integración.\u0026rdquo;\n\u0026ldquo;¿Hay algo que me bloquea?\u0026rdquo; es la pregunta más importante. Porque aquí emergen las dependencias, los cuellos de botella, los problemas que uno solo no puede resolver. Pero — y esto es fundamental — el bloqueo se señala, no se resuelve en directo.\nCuando alguien dice \u0026ldquo;Estoy bloqueado porque no tengo acceso al entorno de staging\u0026rdquo;, la respuesta correcta no es una discusión de quince minutos sobre quién debe dar el acceso, cómo configurarlo y por qué no funcionaba ayer. La respuesta correcta es: \u0026ldquo;Ok, hablamos después del standup, tú y yo.\u0026rdquo;\nEs esta disciplina la que mantiene el standup por debajo de 15 minutos. Sin ella, cada bloqueo se convierte en una reunión dentro de la reunión.\n💀 Cuando el standup muere #He identificado una lista bastante precisa de las formas en que un standup puede morir. Las enumero no por pesimismo, sino porque reconocerlas es la única forma de prevenirlas.\nEl thread killer #Una persona cuenta un problema técnico complejo. Otra persona responde. Empieza un diálogo entre dos, mientras seis personas se quedan paradas. El facilitador no interviene porque \u0026ldquo;es un tema importante\u0026rdquo;. Quince minutos perdidos.\nLa demo improvisada #\u0026ldquo;Esperen, les muestro lo que hice.\u0026rdquo; Pantalla compartida, navegación por la aplicación, explicación de detalles de UI. ¿Interesante? Quizás. ¿Pertinente al standup? No.\nEl manager que hace preguntas #El PM o el team lead empieza a profundizar: \u0026ldquo;¿Esa feature está al 60% o al 70%? ¿Cuándo prevés terminar? ¿Hablaste con el cliente?\u0026rdquo; El standup se transforma en un reporte individual de estado.\nLa ausencia del facilitador #Sin alguien que marque el ritmo, el standup se convierte en una conversación libre. La conversación libre es hermosa en el bar, no a las 9:15 de la mañana cuando ocho personas tienen que trabajar.\nEl portátil abierto #Cuando las personas traen el laptop al standup, el mensaje implícito es: \u0026ldquo;Esta reunión no merece mi atención completa.\u0026rdquo; Y tienen razón — si el standup dura 40 minutos, no la merece.\n🛠️ Cómo hacer funcionar un standup — de verdad #Después de veinte años de proyectos, mi receta es esta. No es elegante, no es de manual, pero funciona.\n1. Timer visible #Un cronómetro en la pantalla compartida (o un teléfono sobre la mesa) que arranca cuando empieza el standup. Todos lo ven. Cuando marca 15 minutos, el standup termina. Punto.\nNo es autoritario. Es un acuerdo de equipo. El timer no es el enemigo — es el guardián del tiempo de todos.\n2. Facilitador con el mandato de cortar #Necesitas una persona — rotativa o fija — cuyo único trabajo es decir: \u0026ldquo;Ok, esto lo profundizamos después. Siguiente.\u0026rdquo; No es falta de educación. Es respeto por las seis personas que están esperando.\nEl mejor facilitador lo hace con naturalidad: \u0026ldquo;Interesante, lo hablamos justo después. Marco, te toca.\u0026rdquo;\n3. De pie, de verdad #No es folklore. Estar de pie tiene un efecto psicológico concreto: las personas quieren terminar rápido. Cuando te sientas, te relajas. Cuando estás de pie, tiendes a la síntesis.\nSi el equipo es remoto, el principio se traduce en: cámaras encendidas, nada de multitasking. La señal debe ser: \u0026ldquo;Estos 15 minutos tienen mi atención completa.\u0026rdquo;\n4. Sin portátiles, sin compartir pantalla #El standup es verbal. Si algo requiere una demo, un diagrama, una explicación visual — no es material de standup. Es material de una reunión separada, con las personas adecuadas.\n5. Parking lot #Cada vez que surge un tema que merece profundización, el facilitador lo apunta en una lista visible — el \u0026ldquo;parking lot\u0026rdquo;. Después del standup, las personas involucradas se quedan y lo discuten. Los demás van a trabajar.\nEl parking lot es la herramienta más subestimada en la gestión de standups. Permite decir \u0026ldquo;lo hablamos después\u0026rdquo; sin que el tema se olvide.\n📊 El standup en números #Hagamos un cálculo que nadie hace nunca.\nUn equipo de 8 personas. Standup diario. 220 días laborables al año.\nEscenario Duración Horas/persona/año Horas totales equipo/año Standup de 15 minutos 15 min 55 horas 440 horas Standup de 30 minutos 30 min 110 horas 880 horas Standup de 45 minutos 45 min 165 horas 1.320 horas La diferencia entre un standup bien gestionado y uno fuera de control es 880 horas al año. Para un equipo de 8 personas. Son 110 jornadas laborables. Casi cinco meses-persona.\nY eso sin contar el efecto indirecto: un standup de 45 minutos no roba solo 45 minutos. Roba también los 10-15 minutos de concentración necesarios después para volver al flujo de trabajo.\n🔄 Standup remoto vs presencial #Desde 2020 los standups son frecuentemente remotos. Cambia el medio, pero los principios siguen siendo idénticos. Con algunas precauciones adicionales.\nEn remoto es peor (si no tienes cuidado) # La latencia de audio crea superposiciones que alargan los tiempos El multitasking es invisible (pero real) La falta de lenguaje corporal dificulta que el facilitador sepa cuándo cortar Compartir pantalla está a un clic de distancia, y la tentación de usarlo es alta Cómo gestionar el standup remoto # Práctica Motivo Orden de palabra predefinido Evita el \u0026ldquo;¿quién habla?\u0026rdquo; y los silencios incómodos Cámaras encendidas Señala presencia y atención Chat para el parking lot Captura temas en tiempo real sin interrumpir Timer compartido en pantalla Mismo principio que el standup presencial Todos en mute excepto quien habla Elimina ruidos de fondo y tentaciones de interrumpir El truco más efectivo que he encontrado para los standups remotos es la ronda por relevos: cada persona, después de hablar, nombra a la siguiente. \u0026ldquo;Terminé. Sara, te toca.\u0026rdquo; Esto mantiene la atención activa y da ritmo a la reunión.\n🎯 El standup es una herramienta, no un ritual #Lo que siempre me ha llamado la atención es la facilidad con que el standup se convierte en un ritual vacío. Lo haces porque \u0026ldquo;se hace así\u0026rdquo;, porque \u0026ldquo;somos ágiles\u0026rdquo;, porque \u0026ldquo;el framework lo dice\u0026rdquo;. Pero nadie se pregunta: ¿está funcionando?\nUn standup funciona cuando el equipo lo percibe como útil. Cuando a las 9:15 las personas se presentan con ganas, dicen lo suyo en dos minutos, escuchan a los demás, y a las 9:30 están en su escritorio sabiendo exactamente qué pasa en el proyecto.\nUn standup no funciona cuando las personas lo perciben como una obligación. Cuando suspiran mirando el reloj. Cuando revisan el teléfono. Cuando piensan \u0026ldquo;podría haber usado esta media hora para trabajar.\u0026rdquo;\nLa diferencia entre ambos escenarios es casi siempre la misma: si la restricción de los 15 minutos se respeta o no.\nNo hacen falta frameworks sofisticados. No hacen falta certificaciones. Hace falta un timer, un facilitador con columna vertebral, y la conciencia de que el tiempo de las personas tiene valor.\nQuince minutos. Tres preguntas. Parking lot para el resto.\nTodo lo demás es ruido.\nGlosario #Daily Standup — Reunión diaria de máximo 15 minutos donde cada miembro del equipo responde tres preguntas: qué hice ayer, qué haré hoy, qué me bloquea.\nParking Lot — Lista visible de temas surgidos durante una reunión que merecen profundización pero se posponen para respetar el timebox.\nFacilitador — Persona responsable de guiar una reunión manteniendo el foco, respetando el timebox y garantizando que todos tengan voz.\nTimeboxing — Técnica de gestión del tiempo que asigna un intervalo fijo y no negociable a una actividad, forzando la conclusión dentro del límite establecido.\nScrum — Framework ágil para la gestión de proyectos que organiza el trabajo en sprints de duración fija, con roles definidos y ceremonias estructuradas.\n","date":"27 enero 2026","permalink":"https://ivanluminaria.com/es/posts/project-management/standup-meeting-15-minuti/","section":"Database Strategy","summary":"\u003cp\u003ePrimer lunes del proyecto. Equipo nuevo, metodología nueva, esperanzas nuevas. El PM propone el standup diario. Todos asienten. \u0026ldquo;Quince minutos, de pie, tres preguntas. Simple.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eLa primera semana funciona. A las 9:15 se empieza, a las 9:28 ya estás en tu escritorio. Cada uno dice lo suyo en dos minutos, se señalan los bloqueos, se despiden. Eficiencia pura.\u003c/p\u003e\n\u003cp\u003eLa segunda semana alguien levanta la mano a mitad de ronda: \u0026ldquo;¿Puedo explicar un momento el problema que tengo con la integración?\u0026rdquo; Cinco minutos de discusión técnica entre dos personas. Los otros seis se quedan escuchando algo que no les concierne.\u003c/p\u003e","title":"Standup meeting: por qué solo funcionan si duran 15 minutos"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/team-management/","section":"Tags","summary":"","title":"Team-Management"},{"content":"Me ha pasado más de una vez: entro en un entorno Oracle y encuentro la misma situación. Todos los usuarios aplicativos conectados como schema owner, con el rol DBA asignado. Desarrolladores, procesos batch, herramientas de reporting — todos con los mismos privilegios que el usuario propietario de las tablas.\nCuando preguntas por qué, la respuesta siempre es alguna variante de: \u0026ldquo;Así todo funciona sin problemas de permisos.\u0026rdquo;\nClaro. Todo funciona. Hasta el día en que un desarrollador ejecuta un DROP TABLE sobre la tabla equivocada. O un batch de importación hace un TRUNCATE sobre una tabla de producción pensando que está en el entorno de pruebas. O alguien ejecuta un DELETE FROM clientes sin la cláusula WHERE.\nEse día el problema ya no son los permisos. Es que no tienes idea de quién hizo qué, y no tienes ninguna herramienta para impedir que vuelva a ocurrir.\nEl contexto: un patrón que se repite #El cliente era una empresa mediana con una aplicación de gestión sobre Oracle 19c. Unos veinte usuarios entre desarrolladores, cuentas aplicativas y operadores. El schema aplicativo — llamémoslo APP_OWNER — contenía unas 300 tablas, unas sesenta vistas y unas cuantas docenas de procedimientos PL/SQL.\nEl problema era fácil de describir:\nTodos se conectaban como APP_OWNER APP_OWNER tenía el rol DBA Ningún audit configurado Ninguna separación entre quien lee y quien escribe Las contraseñas se compartían por email No era negligencia. Era inercia. El sistema había crecido así a lo largo de los años, y nadie se había detenido a repensar el modelo. Funcionaba, y eso bastaba.\nHasta que un operador borró por error los datos de facturación de un trimestre entero. Ningún log, ningún rastro, ningún culpable identificable. Solo un backup de dos días antes y un vacío en los datos que llevó semanas rellenar.\nCómo funciona la seguridad en Oracle: el modelo #Antes de contar lo que hice, conviene entender cómo Oracle estructura la seguridad. El modelo es diferente de PostgreSQL y de MySQL, y las diferencias no son cosméticas.\nUsuario y schema: la misma cosa (casi) #En Oracle, crear un usuario significa crear un schema. No son dos conceptos separados: el usuario APP_OWNER es también el schema APP_OWNER, y los objetos creados por ese usuario viven en ese schema.\nCREATE USER app_read IDENTIFIED BY \u0026#34;PasswordSegura#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 0 ON users; La QUOTA 0 es intencional: este usuario no debe crear objetos. Es un consumidor, no un propietario.\nPrivilegios de sistema vs privilegios de objeto #Oracle distingue claramente entre:\nSystem privileges: operaciones globales como CREATE TABLE, CREATE SESSION, ALTER SYSTEM Object privileges: operaciones sobre objetos específicos como SELECT ON app_owner.clientes, EXECUTE ON app_owner.pkg_facturas El rol DBA incluye más de 200 system privileges. Asignarlo a un usuario aplicativo es como entregar las llaves de todo el edificio a quien solo necesita entrar en una habitación.\nLos roles: predefinidos y personalizados #Oracle ofrece roles predefinidos (CONNECT, RESOURCE, DBA) y permite crear roles personalizados. Los roles predefinidos tienen un problema histórico: CONNECT y RESOURCE incluían privilegios excesivos en versiones anteriores. Desde Oracle 12c se han reducido, pero la costumbre de asignarlos sin pensarlo es difícil de erradicar.\nEl camino correcto es crear roles personalizados calibrados a las necesidades reales.\nLa implementación: tres roles, cero ambigüedad #Diseñé tres roles: lectura, escritura y administración aplicativa.\n1. Rol de solo lectura #CREATE ROLE app_read_role; -- Privilegios sobre las tablas GRANT SELECT ON app_owner.clientes TO app_read_role; GRANT SELECT ON app_owner.pedidos TO app_read_role; GRANT SELECT ON app_owner.facturas TO app_read_role; GRANT SELECT ON app_owner.productos TO app_read_role; GRANT SELECT ON app_owner.movimientos TO app_read_role; -- Privilegios sobre las vistas GRANT SELECT ON app_owner.v_informe_ventas TO app_read_role; GRANT SELECT ON app_owner.v_estado_pedidos TO app_read_role; En un entorno con 300 tablas no las enumeras una por una a mano. Usé un bloque PL/SQL para generar los grants:\nBEGIN FOR t IN (SELECT table_name FROM dba_tables WHERE owner = \u0026#39;APP_OWNER\u0026#39;) LOOP EXECUTE IMMEDIATE \u0026#39;GRANT SELECT ON app_owner.\u0026#39; || t.table_name || \u0026#39; TO app_read_role\u0026#39;; END LOOP; END; / Simple, repetible y sobre todo: documentado. Porque dentro de seis meses alguien tendrá que entender qué se hizo y por qué.\n2. Rol de lectura y escritura #CREATE ROLE app_write_role; -- Hereda todo del rol de lectura GRANT app_read_role TO app_write_role; -- Agrega DML sobre las tablas operativas GRANT INSERT, UPDATE, DELETE ON app_owner.pedidos TO app_write_role; GRANT INSERT, UPDATE, DELETE ON app_owner.movimientos TO app_write_role; GRANT INSERT, UPDATE ON app_owner.clientes TO app_write_role; -- Permiso de ejecución sobre los procedimientos aplicativos GRANT EXECUTE ON app_owner.pkg_pedidos TO app_write_role; GRANT EXECUTE ON app_owner.pkg_facturas TO app_write_role; Nota: nada de DELETE sobre la tabla clientes. No porque sea técnicamente imposible, sino porque el proceso aplicativo prevé una desactivación, no un borrado. El privilegio refleja el proceso, no la comodidad.\n3. Rol de administración aplicativa #CREATE ROLE app_admin_role; -- Hereda el rol de escritura GRANT app_write_role TO app_admin_role; -- Agrega DDL controlado GRANT CREATE VIEW TO app_admin_role; GRANT CREATE PROCEDURE TO app_admin_role; GRANT CREATE SYNONYM TO app_admin_role; -- Puede gestionar las tablas de configuración GRANT INSERT, UPDATE, DELETE ON app_owner.parametros TO app_admin_role; GRANT INSERT, UPDATE, DELETE ON app_owner.lookup_tipos TO app_admin_role; Nada de CREATE TABLE, nada de DROP ANY, nada de ALTER SYSTEM. El admin aplicativo gestiona la lógica, no la estructura física.\nCreación de usuarios y asignación #-- Usuario para reportes (solo lectura) CREATE USER srv_report IDENTIFIED BY \u0026#34;RptSecure#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 0 ON users; GRANT CREATE SESSION TO srv_report; GRANT app_read_role TO srv_report; -- Usuario aplicativo (lectura y escritura) CREATE USER srv_app IDENTIFIED BY \u0026#34;AppSecure#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 0 ON users; GRANT CREATE SESSION TO srv_app; GRANT app_write_role TO srv_app; -- DBA aplicativo (administración) CREATE USER dba_app IDENTIFIED BY \u0026#34;DbaSecure#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 10M ON users; GRANT CREATE SESSION TO dba_app; GRANT app_admin_role TO dba_app; Cada usuario tiene su propia contraseña, un rol específico y una cuota de disco coherente con su propósito. srv_report no tiene cuota porque no debe crear nada. dba_app tiene 10 MB porque necesita crear vistas y procedimientos.\nRevocación del rol DBA #El paso más delicado: quitar el DBA a APP_OWNER.\nREVOKE DBA FROM app_owner; Una línea. Pero antes de ejecutarla, verifiqué que APP_OWNER aún tuviera los privilegios necesarios para ser propietario de sus objetos:\nSELECT privilege FROM dba_sys_privs WHERE grantee = \u0026#39;APP_OWNER\u0026#39;; SELECT granted_role FROM dba_role_privs WHERE grantee = \u0026#39;APP_OWNER\u0026#39;; Y asigné solo los privilegios estrictamente necesarios:\nGRANT CREATE SESSION TO app_owner; GRANT CREATE TABLE TO app_owner; GRANT CREATE VIEW TO app_owner; GRANT CREATE PROCEDURE TO app_owner; GRANT CREATE SEQUENCE TO app_owner; GRANT UNLIMITED TABLESPACE TO app_owner; APP_OWNER sigue siendo el propietario de los objetos pero ya no tiene el poder de hacer cualquier cosa en la base de datos. Es un propietario, no un dios.\nAudit: saber quién hizo qué #Tener los roles correctos no basta. Hay que saber quién hizo qué, especialmente en las operaciones críticas.\nOracle desde la versión 12c ofrece Unified Audit, que sustituye el viejo audit tradicional con un sistema centralizado.\n-- Audit sobre operaciones DDL críticas CREATE AUDIT POLICY pol_ddl_critico ACTIONS CREATE TABLE, DROP TABLE, ALTER TABLE, TRUNCATE TABLE, CREATE USER, DROP USER, ALTER USER, GRANT, REVOKE; ALTER AUDIT POLICY pol_ddl_critico ENABLE; -- Audit sobre accesos a datos sensibles CREATE AUDIT POLICY pol_acceso_datos ACTIONS SELECT ON app_owner.clientes, DELETE ON app_owner.facturas, UPDATE ON app_owner.facturas; ALTER AUDIT POLICY pol_acceso_datos ENABLE; -- Audit sobre logins fallidos CREATE AUDIT POLICY pol_login_fallidos ACTIONS LOGON; ALTER AUDIT POLICY pol_login_fallidos ENABLE WHENEVER NOT SUCCESSFUL; Para verificar qué se está registrando:\nSELECT * FROM unified_audit_trail WHERE event_timestamp \u0026gt; SYSDATE - 7 ORDER BY event_timestamp DESC; El audit no es paranoia. Es la única forma de responder a la pregunta \u0026ldquo;¿quién hizo qué?\u0026rdquo; sin tener que recurrir a la intuición.\nLa comparación con PostgreSQL y MySQL #Este artículo es el tercero de una serie sobre gestión de seguridad en bases de datos relacionales. Los dos primeros cubren PostgreSQL y MySQL.\nLas diferencias entre los tres sistemas son sustanciales:\nAspecto Oracle PostgreSQL MySQL ¿Usuario = schema? Sí No (independientes) Sí (bases de datos separadas) Modelo de roles Predefinidos + custom Todo es un ROLE Roles desde MySQL 8.0 Identidad Nombre de usuario Nombre de usuario Par usuario@host Audit nativo Unified Audit (12c+) pgAudit (extensión) Audit plugin Privilegios granulares System + Object Database/Schema/Object Global/DB/Table/Column GRANT ALL Existe pero peligroso Existe, desaconsejado Existe, desaconsejado En PostgreSQL todo es un ROLE, y la simplicidad del modelo es su punto fuerte. En MySQL la identidad está vinculada al host de origen, lo que agrega una capa de complejidad (y seguridad) que los otros no tienen. En Oracle el modelo es el más rico y el más granular, pero también el más fácil de configurar mal por exceso de opciones.\nEl principio sigue siendo el mismo en todas partes: dale a cada uno solo lo que necesita, ni un privilegio más.\nQué cambió después #La transición fue gradual — dos semanas para el despliegue completo, con pruebas en cada aplicación y procedimiento. Algunos scripts dejaron de funcionar porque daban por sentados privilegios que no les correspondían. Cada error era en realidad un problema oculto que antes era invisible.\nEl resultado:\n20 usuarios nominales en lugar de un único schema compartido 3 roles personalizados en lugar del rol DBA Audit activo sobre DDL y operaciones sensibles Cero incidentes de borrado accidental en los meses siguientes El cliente no notó mejoras de rendimiento. No era ese el objetivo. Lo que notó fue que cuando alguien cometía un error, el daño era contenido y rastreable. Y eso, en un entorno de producción, vale más que cualquier optimización.\nConclusión #GRANT ALL PRIVILEGES y el rol DBA son atajos. Funcionan en el sentido de que eliminan los errores de permisos. Pero también eliminan cualquier capa de protección.\nLa seguridad en Oracle no es un problema de herramientas — las herramientas están ahí, y son potentes. Es un problema de diseño: decidir quién puede hacer qué, documentarlo, implementarlo y luego verificar que funciona.\nNo es el trabajo más glamuroso del mundo. Pero es el que marca la diferencia entre una base de datos que simplemente sobrevive y una que está verdaderamente bajo control.\nGlosario #System Privilege — Privilegio Oracle que autoriza operaciones globales en la base de datos como CREATE TABLE, CREATE SESSION o ALTER SYSTEM, independientes de cualquier objeto específico.\nObject Privilege — Privilegio Oracle que autoriza operaciones sobre un objeto específico de la base de datos como SELECT, INSERT o EXECUTE sobre una tabla, vista o procedimiento.\nREVOKE — Comando SQL para eliminar privilegios o roles previamente asignados a un usuario o rol, complementario al comando GRANT.\nUnified Audit — Sistema de auditoría centralizado introducido en Oracle 12c que unifica todos los tipos de auditoría en una única infraestructura, sustituyendo el antiguo audit tradicional.\nLeast Privilege — Principio de seguridad que prevé asignar a cada usuario solo los permisos estrictamente necesarios para desempeñar su función.\n","date":"27 enero 2026","permalink":"https://ivanluminaria.com/es/posts/oracle/oracle-roles-privileges/","section":"Database Strategy","summary":"\u003cp\u003eMe ha pasado más de una vez: entro en un entorno Oracle y encuentro la misma situación. Todos los usuarios aplicativos conectados como schema owner, con el rol DBA asignado. Desarrolladores, procesos batch, herramientas de reporting — todos con los mismos privilegios que el usuario propietario de las tablas.\u003c/p\u003e\n\u003cp\u003eCuando preguntas por qué, la respuesta siempre es alguna variante de: \u0026ldquo;Así todo funciona sin problemas de permisos.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eClaro. Todo funciona. Hasta el día en que un desarrollador ejecuta un \u003ccode\u003eDROP TABLE\u003c/code\u003e sobre la tabla equivocada. O un batch de importación hace un \u003ccode\u003eTRUNCATE\u003c/code\u003e sobre una tabla de producción pensando que está en el entorno de pruebas. O alguien ejecuta un \u003ccode\u003eDELETE FROM clientes\u003c/code\u003e sin la cláusula \u003ccode\u003eWHERE\u003c/code\u003e.\u003c/p\u003e","title":"Usuarios, roles y privilegios en Oracle: por qué GRANT ALL nunca es la respuesta"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/categories/data-warehouse/","section":"Categories","summary":"","title":"Data-Warehouse"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/dimensional-modeling/","section":"Tags","summary":"","title":"Dimensional-Modeling"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/etl/","section":"Tags","summary":"","title":"Etl"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/hierarchies/","section":"Tags","summary":"","title":"Hierarchies"},{"content":"Tres niveles. Top Group, Group, Client. Parece una estructura trivial — el tipo de jerarquía que dibujas en una pizarra en cinco minutos y que cualquier herramienta de BI debería manejar sin problemas.\nLuego descubres que no todos los clientes pertenecen a un grupo. Y que no todos los grupos pertenecen a un top group. Y que los reportes de agregación que el negocio pide — facturación por top group, número de clientes por grupo, drill-down desde la cima hasta la hoja — producen resultados erróneos o incompletos porque la jerarquía tiene huecos.\nEn jerga técnica se llama ragged hierarchy : una jerarquía en la que no todas las ramas alcanzan la misma profundidad. En el mundo real se llama \u0026ldquo;el problema que nadie ve hasta que abre el reporte y los números no cuadran.\u0026rdquo;\nEl cliente y el modelo original #El proyecto era un data warehouse para una empresa del sector energético — distribución de gas y servicios relacionados. El sistema fuente gestionaba un maestro de clientes con una estructura jerárquica: los clientes podían agruparse bajo una entidad comercial (el Group), y los grupos podían a su vez pertenecer a una entidad superior (el Top Group).\nEl modelo en la fuente era una tabla única con las referencias jerárquicas:\nCREATE TABLE stg_clienti ( client_id NUMBER(10) NOT NULL, client_name VARCHAR2(100) NOT NULL, group_id NUMBER(10), group_name VARCHAR2(100), top_group_id NUMBER(10), top_group_name VARCHAR2(100), revenue NUMBER(15,2), region VARCHAR2(50), CONSTRAINT pk_stg_clienti PRIMARY KEY (client_id) ); Aquí un ejemplo de los datos:\nINSERT INTO stg_clienti VALUES (1001, \u0026#39;Rossi Energia Srl\u0026#39;, 10, \u0026#39;Consorzio Nord\u0026#39;, 100, \u0026#39;Holding Nazionale\u0026#39;, 125000.00, \u0026#39;Lombardia\u0026#39;); INSERT INTO stg_clienti VALUES (1002, \u0026#39;Bianchi Gas SpA\u0026#39;, 10, \u0026#39;Consorzio Nord\u0026#39;, 100, \u0026#39;Holding Nazionale\u0026#39;, 89000.00, \u0026#39;Piemonte\u0026#39;); INSERT INTO stg_clienti VALUES (1003, \u0026#39;Verdi Distribuzione\u0026#39;, 20, \u0026#39;Gruppo Centro\u0026#39;, 100, \u0026#39;Holding Nazionale\u0026#39;, 67000.00, \u0026#39;Toscana\u0026#39;); INSERT INTO stg_clienti VALUES (1004, \u0026#39;Neri Servizi\u0026#39;, 20, \u0026#39;Gruppo Centro\u0026#39;, NULL, NULL, 45000.00, \u0026#39;Lazio\u0026#39;); INSERT INTO stg_clienti VALUES (1005, \u0026#39;Gialli Utilities\u0026#39;, NULL, NULL, NULL, NULL, 38000.00, \u0026#39;Sicilia\u0026#39;); INSERT INTO stg_clienti VALUES (1006, \u0026#39;Blu Energia\u0026#39;, NULL, NULL, NULL, NULL, 52000.00, \u0026#39;Sardegna\u0026#39;); INSERT INTO stg_clienti VALUES (1007, \u0026#39;Viola Gas Srl\u0026#39;, 30, \u0026#39;Rete Sud\u0026#39;, NULL, NULL, 71000.00, \u0026#39;Campania\u0026#39;); INSERT INTO stg_clienti VALUES (1008, \u0026#39;Arancio Distribuzione\u0026#39;, 30, \u0026#39;Rete Sud\u0026#39;, NULL, NULL, 33000.00, \u0026#39;Calabria\u0026#39;); Miren los datos con atención. Hay cuatro situaciones diferentes:\nClient 1001, 1002, 1003: jerarquía completa — Client → Group → Top Group Client 1004: tiene un Group pero el Group no tiene Top Group Client 1005, 1006: sin Group, sin Top Group — clientes directos Client 1007, 1008: tienen un Group (Rete Sud) pero el Group no tiene Top Group Esto es una ragged hierarchy. Tres niveles sobre el papel, pero en la realidad las ramas tienen profundidades diferentes.\nEl problema: los reportes no cuadran #El negocio pedía un reporte sencillo: facturación agregada por Top Group, con posibilidad de drill-down por Group y luego por Client. Una petición razonable — el tipo de cosa que esperas de cualquier DWH.\nLa consulta más natural:\nSELECT top_group_name, group_name, COUNT(*) AS num_clientes, SUM(revenue) AS facturacion_total FROM stg_clienti GROUP BY top_group_name, group_name ORDER BY top_group_name, group_name; El resultado:\nTOP_GROUP_NAME GROUP_NAME NUM_CLIENTES FACTURACION_TOTAL ------------------ ---------------- ------------ ----------------- Holding Nazionale Consorzio Nord 2 214000.00 Holding Nazionale Gruppo Centro 1 67000.00 (null) Gruppo Centro 1 45000.00 (null) Rete Sud 2 104000.00 (null) (null) 2 90000.00 Cinco filas. Y al menos tres problemas.\nGruppo Centro aparece dos veces: una bajo \u0026ldquo;Holding Nazionale\u0026rdquo; (el cliente 1003 que tiene top group) y una bajo NULL (el cliente 1004 cuyo top group es NULL). El mismo grupo, partido en dos filas, con totales separados. Cualquiera que mire este reporte pensará que Gruppo Centro tiene 67K de facturación bajo la holding y 45K en algún otro sitio. En realidad es un único grupo con 112K totales.\nLos clientes directos (Gialli Utilities y Blu Energia) terminan en una fila con dos NULL. La dirección no sabe qué hacer con una fila sin nombre.\nEl total por Top Group está mal porque faltan las filas con NULL. Si sumas solo las filas con top group, pierdes 239K de facturación — el 30% del total.\nEl enfoque clásico: COALESCE y rezos #La primera reacción, la que veo en el 90% de los casos, es añadir `COALESCE` en la consulta:\nSELECT COALESCE(top_group_name, group_name, client_name) AS top_group_name, COALESCE(group_name, client_name) AS group_name, client_name, revenue FROM stg_clienti; ¿Funciona? En cierto sentido sí — rellena los huecos. Pero introduce problemas nuevos.\nEl cliente \u0026ldquo;Gialli Utilities\u0026rdquo; ahora aparece como Top Group, Group y Client simultáneamente. Si el negocio quiere contar cuántos Top Groups hay, el número está inflado. Si quiere filtrar por \u0026ldquo;verdaderos\u0026rdquo; top groups, no hay forma de distinguirlos de los clientes promovidos por la COALESCE.\nY este es el caso sencillo, con tres niveles. He visto jerarquías de cinco niveles gestionadas con cadenas de COALESCE anidados, múltiples CASE WHEN, y una lógica de reportes tan enrevesada que nadie se atrevía a tocarla. Cada nueva petición del negocio requería un cambio en cascada en todas las consultas.\nEl problema de fondo es que la COALESCE es un parche aplicado en la capa de presentación. No resuelve el problema estructural: la jerarquía está incompleta y el modelo dimensional no lo sabe.\nLa solución: self-parenting #El principio es simple: quien no tiene padre se convierte en padre de sí mismo. Esta técnica se llama self-parenting .\n¿Un Client sin Group? Ese cliente se convierte en su propio Group. ¿Un Group sin Top Group? Ese grupo se convierte en su propio Top Group. De esta forma la jerarquía siempre está completa a tres niveles, sin huecos, sin NULL.\nNo es un truco. Es una técnica estándar en modelado dimensional, descrita por Kimball y usada en producción desde hace décadas. La idea es que la dimensión jerárquica en el DWH debe ser balanceada: cada registro debe tener un valor válido para cada nivel de la jerarquía. Si la fuente no lo garantiza, lo garantiza el ETL .\nLa tabla dimensional #CREATE TABLE dim_client_hierarchy ( client_key NUMBER(10) NOT NULL, client_id NUMBER(10) NOT NULL, client_name VARCHAR2(100) NOT NULL, group_id NUMBER(10) NOT NULL, group_name VARCHAR2(100) NOT NULL, top_group_id NUMBER(10) NOT NULL, top_group_name VARCHAR2(100) NOT NULL, region VARCHAR2(50), is_direct_client CHAR(1) DEFAULT \u0026#39;N\u0026#39;, is_standalone_group CHAR(1) DEFAULT \u0026#39;N\u0026#39;, CONSTRAINT pk_dim_client_hier PRIMARY KEY (client_key) ); Noten dos cosas. Primero: ninguna columna es nullable. Group y Top Group son NOT NULL. Segundo: añadí dos flags — is_direct_client e is_standalone_group — que permiten distinguir los registros balanceados artificialmente de los que tienen una jerarquía natural. Esto es importante: el negocio debe poder filtrar los \u0026ldquo;verdaderos\u0026rdquo; top groups de los clientes promovidos.\nLa lógica ETL #INSERT INTO dim_client_hierarchy ( client_key, client_id, client_name, group_id, group_name, top_group_id, top_group_name, region, is_direct_client, is_standalone_group ) SELECT client_id AS client_key, client_id, client_name, -- Si no tiene group, el cliente se convierte en group de sí mismo COALESCE(group_id, client_id) AS group_id, COALESCE(group_name, client_name) AS group_name, -- Si no tiene top group, el group (o cliente) se convierte en su propio top group COALESCE(top_group_id, group_id, client_id) AS top_group_id, COALESCE(top_group_name, group_name, client_name) AS top_group_name, region, CASE WHEN group_id IS NULL THEN \u0026#39;Y\u0026#39; ELSE \u0026#39;N\u0026#39; END AS is_direct_client, CASE WHEN group_id IS NOT NULL AND top_group_id IS NULL THEN \u0026#39;Y\u0026#39; ELSE \u0026#39;N\u0026#39; END AS is_standalone_group FROM stg_clienti; Miren la cascada de COALESCE en la transformación. La lógica es:\ngroup_id: si el cliente tiene grupo, usa ese; si no, usa el propio cliente top_group_id: si hay top group, usa ese; si no pero hay group, usa el group; si tampoco hay group, usa el cliente Cada nivel \u0026ldquo;faltante\u0026rdquo; se rellena con el nivel inmediatamente inferior. El resultado es una jerarquía siempre completa.\nEl resultado después del balanceo #SELECT client_key, client_name, group_name, top_group_name, is_direct_client, is_standalone_group FROM dim_client_hierarchy ORDER BY top_group_id, group_id, client_id; KEY CLIENT_NAME GROUP_NAME TOP_GROUP_NAME DIRECT STANDALONE ---- -------------------- ---------------- ------------------ ------ ---------- 1001 Rossi Energia Srl Consorzio Nord Holding Nazionale N N 1002 Bianchi Gas SpA Consorzio Nord Holding Nazionale N N 1003 Verdi Distribuzione Gruppo Centro Holding Nazionale N N 1004 Neri Servizi Gruppo Centro Gruppo Centro N Y 1007 Viola Gas Srl Rete Sud Rete Sud N Y 1008 Arancio Distribuzione Rete Sud Rete Sud N Y 1005 Gialli Utilities Gialli Utilities Gialli Utilities Y N 1006 Blu Energia Blu Energia Blu Energia Y N Ocho filas, cero NULL. Cada cliente tiene un group y un top group. Los flags dicen la verdad: Gialli y Blu son clientes directos (self-parented a todos los niveles), Gruppo Centro y Rete Sud son grupos standalone (self-parented al nivel top group).\nLos reportes después del balanceo #La misma consulta de agregación que antes producía resultados rotos:\nSELECT top_group_name, group_name, COUNT(*) AS num_clientes, SUM(f.revenue) AS facturacion_total FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id GROUP BY top_group_name, group_name ORDER BY top_group_name, group_name; TOP_GROUP_NAME GROUP_NAME NUM_CLIENTES FACTURACION_TOTAL ------------------ ------------------ ------------ ----------------- Blu Energia Blu Energia 1 52000.00 Gialli Utilities Gialli Utilities 1 38000.00 Gruppo Centro Gruppo Centro 1 45000.00 Holding Nazionale Consorzio Nord 2 214000.00 Holding Nazionale Gruppo Centro 1 67000.00 Rete Sud Rete Sud 2 104000.00 Ningún NULL. Cada fila tiene un top group y un group identificables. Los totales cuadran.\nY si el negocio quiere solo los \u0026ldquo;verdaderos\u0026rdquo; top groups, excluyendo los clientes promovidos:\nSELECT top_group_name, COUNT(*) AS num_clientes, SUM(f.revenue) AS facturacion_total FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id WHERE d.is_direct_client = \u0026#39;N\u0026#39; AND d.is_standalone_group = \u0026#39;N\u0026#39; GROUP BY top_group_name ORDER BY facturacion_total DESC; TOP_GROUP_NAME NUM_CLIENTES FACTURACION_TOTAL ------------------ ------------ ----------------- Holding Nazionale 3 281000.00 Los flags hacen todo filtrable. Sin lógica condicional en el reporte, sin CASE WHEN, sin COALESCE. El modelo dimensional ya contiene toda la información necesaria.\nEl drill-down completo #La verdadera prueba de una jerarquía balanceada es el drill-down: desde el nivel más alto al más bajo, sin sorpresas.\n-- Nivel 1: total por Top Group SELECT top_group_name, COUNT(DISTINCT group_id) AS num_grupos, COUNT(*) AS num_clientes, SUM(f.revenue) AS facturacion FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id GROUP BY top_group_name ORDER BY facturacion DESC; TOP_GROUP_NAME NUM_GRUPOS NUM_CLIENTES FACTURACION ------------------ ---------- ------------ ----------- Holding Nazionale 2 3 281000.00 Rete Sud 1 2 104000.00 Blu Energia 1 1 52000.00 Gruppo Centro 1 1 45000.00 Gialli Utilities 1 1 38000.00 -- Nivel 2: drill-down dentro de \u0026#34;Holding Nazionale\u0026#34; SELECT group_name, COUNT(*) AS num_clientes, SUM(f.revenue) AS facturacion FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id WHERE d.top_group_name = \u0026#39;Holding Nazionale\u0026#39; GROUP BY group_name ORDER BY facturacion DESC; GROUP_NAME NUM_CLIENTES FACTURACION ---------------- ------------ ----------- Consorzio Nord 2 214000.00 Gruppo Centro 1 67000.00 -- Nivel 3: drill-down dentro de \u0026#34;Consorzio Nord\u0026#34; SELECT client_name, f.revenue FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id WHERE d.group_name = \u0026#39;Consorzio Nord\u0026#39; ORDER BY f.revenue DESC; CLIENT_NAME REVENUE ------------------- ---------- Rossi Energia Srl 125000.00 Bianchi Gas SpA 89000.00 Tres niveles de drill-down, cero NULL, cero lógica condicional. La jerarquía está balanceada y los números cuadran en cada nivel.\nPor qué la COALESCE en los reportes no basta #Alguien podría objetar: \u0026ldquo;Pero la COALESCE en el reporte hace lo mismo, sin necesidad de modificar el modelo.\u0026rdquo;\nNo. Hace algo parecido, pero con tres diferencias fundamentales.\nPrimero: la COALESCE hay que repetirla en todas partes. Cada consulta, cada reporte, cada dashboard, cada extracción. Si tienes veinte reportes que usan la jerarquía, debes acordarte de aplicar la COALESCE en los veinte. Y cuando llega el veintiuno, debes acordarte de nuevo. El self-parenting en el modelo dimensional se hace una vez en el ETL y punto.\nSegundo: la COALESCE no distingue. No sabes si \u0026ldquo;Gialli Utilities\u0026rdquo; en el campo top_group es un verdadero top group o un cliente promovido. Con los flags en el modelo dimensional tienes la información para filtrar. Sin flags, el negocio está ciego.\nTercero: el rendimiento. Un GROUP BY con COALESCE sobre columnas nullable es menos eficiente que un GROUP BY sobre columnas NOT NULL. El optimizador de Oracle gestiona mejor las columnas con restricción NOT NULL — puede eliminar verificaciones de NULL, usar índices más agresivamente y producir planes de ejecución más simples. Sobre una tabla dimensional con millones de filas, la diferencia se nota.\nCuándo usar el self-parenting (y cuándo no) #El self-parenting funciona bien cuando:\nLa jerarquía tiene un número fijo de niveles (típicamente 2-5) El caso de uso principal es la agregación y el drill-down en reportes El modelo es un data warehouse o un cubo OLAP Los niveles faltantes son la excepción, no la regla No funciona bien cuando:\nLa jerarquía es recursiva con profundidad variable (ej. organigramas con N niveles) Se necesita navegar el grafo de relaciones (ej. redes sociales, cadenas de suministro) El modelo es OLTP y el self-parenting crearía ambigüedad en las lógicas aplicativas Los niveles de la jerarquía cambian frecuentemente en el tiempo Para jerarquías recursivas con profundidad variable, el enfoque correcto es diferente: tablas de bridge, closure tables o modelos parent-child con CTEs recursivas. Son herramientas potentes pero resuelven un problema distinto.\nEl self-parenting resuelve un problema específico — jerarquías de niveles fijos con ramas incompletas — y lo resuelve de la forma más simple posible: balanceando la estructura aguas arriba, en el modelo, en lugar de aguas abajo, en los reportes.\nLa regla que me guía #He diseñado decenas de dimensiones jerárquicas en veinte años de data warehousing. La regla que llevo conmigo es siempre la misma:\nSi el reporte necesita lógica condicional para gestionar la jerarquía, el problema está en el modelo, no en el reporte.\nUn reporte debería hacer GROUP BY y JOIN. Si además tiene que decidir cómo gestionar los niveles faltantes, está haciendo el trabajo del ETL. Y un reporte que hace el trabajo del ETL es un reporte que tarde o temprano se rompe.\nEl self-parenting no es elegante. No es sofisticado. Es una solución que un informático recién graduado podría encontrar fea. Pero funciona, es mantenible, y transforma un problema que infesta cada reporte individual en un problema que se resuelve una vez, en un solo punto, y no vuelve más.\nA veces la mejor solución es la más simple. Esta es una de esas veces.\nGlosario #COALESCE — Función SQL que devuelve el primer valor no NULL de una lista de expresiones. A menudo usada como workaround para las jerarquías incompletas en los reportes, pero no resuelve el problema estructural en el modelo dimensional.\nDrill-down — Navegación en los reportes desde un nivel agregado hasta un nivel de detalle (ej. de Top Group a Group a Client). Requiere una jerarquía completa y balanceada para funcionar correctamente sin NULLs ni filas faltantes.\nOLAP — Online Analytical Processing — procesamiento orientado al análisis multidimensional de datos, típico de los data warehouses y cubos de análisis. Contrapuesto al OLTP (Online Transaction Processing) de los sistemas transaccionales.\nRagged hierarchy — Jerarquía en la que no todas las ramas alcanzan la misma profundidad: algunos niveles intermedios están ausentes. Común en datos maestros de clientes, productos y estructuras organizativas donde no todas las entidades comparten la misma estructura jerárquica.\nSelf-parenting — Técnica de balanceo de jerarquías desequilibradas: quien no tiene padre se convierte en padre de sí mismo. El nivel faltante se rellena con los datos del nivel inferior, eliminando los NULLs de la dimensión y garantizando un drill-down correcto.\n","date":"20 enero 2026","permalink":"https://ivanluminaria.com/es/posts/data-warehouse/ragged-hierarchies/","section":"Database Strategy","summary":"\u003cp\u003eTres niveles. Top Group, Group, Client. Parece una estructura trivial — el tipo de jerarquía que dibujas en una pizarra en cinco minutos y que cualquier herramienta de BI debería manejar sin problemas.\u003c/p\u003e\n\u003cp\u003eLuego descubres que no todos los clientes pertenecen a un grupo. Y que no todos los grupos pertenecen a un top group. Y que los reportes de agregación que el negocio pide — facturación por top group, número de clientes por grupo, \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Navegación en reportes desde un nivel agregado hasta un nivel de detalle, típica del análisis OLAP y los data warehouses.\" data-glossary-url=\"/es/glossary/drill-down/\" data-glossary-more=\"Leer más →\"\u003edrill-down\u003c/span\u003e\n desde la cima hasta la hoja — producen resultados erróneos o incompletos porque la jerarquía tiene huecos.\u003c/p\u003e","title":"Jerarquías desbalanceadas: cuando el cliente no tiene padre y el grupo no tiene abuelo"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/olap/","section":"Tags","summary":"","title":"Olap"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/reporting/","section":"Tags","summary":"","title":"Reporting"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/authentication/","section":"Tags","summary":"","title":"Authentication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/communication/","section":"Tags","summary":"","title":"Communication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/conflict-management/","section":"Tags","summary":"","title":"Conflict-Management"},{"content":"Era un jueves por la tarde, una de esas reuniones que sobre el papel debía durar una hora. Éramos siete, conectados en una llamada. El orden del día era sencillo: decidir la estrategia de migración de una base de datos Oracle de on-premise a cloud.\nSencillo, claro. Sobre el papel.\nA los veinte minutos, la reunión se había convertido en un duelo.\n🔥 La chispa #Por un lado estaba el responsable de infraestructura. Hombre de experiencia, veinte años de datacenters a sus espaldas. Su posición era granítica: migración lift-and-shift, cero cambios en la arquitectura, se lleva todo tal como está.\nPor el otro, el lead developer. Joven, brillante, con las ideas claras. Quería reescribir la capa aplicativa, adoptar servicios cloud-native, containerizar todo. Lo rehacemos desde cero, total el código es viejo.\nDos posiciones legítimas. Dos perspectivas reales. Dos personas inteligentes.\nPero la conversación había tomado un rumbo familiar — y peligroso.\n\u0026ldquo;No, no tiene sentido llevar todo a cloud sin repensar la arquitectura.\u0026rdquo;\n\u0026ldquo;No, reescribir todo es un riesgo enorme y no tenemos presupuesto.\u0026rdquo;\nNo. No. No.\nCada frase empezaba con \u0026ldquo;no\u0026rdquo;. Cada respuesta era una negación de la anterior. Brazos cruzados, el tono subiendo, las frases acortándose. Conozco ese patrón. Lo he visto cientos de veces. Y sé cómo termina: no termina. La reunión se cierra sin decisión, se pospone a la semana siguiente, y mientras tanto nadie hace nada porque \u0026ldquo;todavía no hemos decidido\u0026rdquo;.\nEl proyecto se detiene. No por motivos técnicos. Por orgullo.\n🎭 Tres palabras que lo cambian todo #En ese momento hice algo muy sencillo. Esperé una pausa — porque en las discusiones acaloradas siempre hay un momento en que todos toman aire — y dije:\n\u0026ldquo;Marco, tienes razón: llevar todo a cloud sin cambiar nada es la vía más rápida para llegar a producción. Y podríamos identificar dos o tres componentes que, durante la migración, tiene sentido repensar en clave cloud-native. Luca, ¿cuáles elegirías tú?\u0026rdquo;\nNadie dijo \u0026ldquo;no\u0026rdquo;. Nadie fue contradicho.\nMarco vio validada su posición — su enfoque conservador era el punto de partida. A Luca se le ofreció un papel concreto — elegir qué modernizar, con un mandato preciso.\nEn treinta segundos, dos personas que estaban discutiendo se encontraron colaborando sobre la misma pizarra.\nLa reunión terminó antes de lo previsto. Con una decisión. Una de verdad.\n🧠 Qué es la técnica del \u0026ldquo;Sí-Y\u0026rdquo; #Lo que hice tiene un nombre. Se llama \u0026ldquo;Yes-And\u0026rdquo; — en español, \u0026ldquo;Sí-Y\u0026rdquo;. Viene del teatro de improvisación, donde hay una regla fundamental: nunca negar la propuesta de tu compañero de escena.\nSi alguien dice \u0026ldquo;Estamos en un barco en medio del océano\u0026rdquo;, no respondes \u0026ldquo;No, estamos en una oficina\u0026rdquo;. Respondes \u0026ldquo;Sí, y parece que se acerca una tormenta\u0026rdquo;. Construyes. Añades. Avanzas.\nEn la gestión de proyectos funciona del mismo modo.\nCuando alguien propone algo y respondes \u0026ldquo;No, pero\u0026hellip;\u0026rdquo;, esto es lo que pasa a nivel psicológico:\nel interlocutor se pone a la defensiva deja de escuchar lo que viene después del \u0026ldquo;pero\u0026rdquo; se concentra en cómo rebatir, no en cómo resolver la conversación se convierte en un ping-pong de negaciones Cuando respondes \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo;, sucede lo contrario:\nel interlocutor se siente reconocido baja las defensas se vuelve receptivo a tu aportación la conversación se vuelve constructiva No es manipulación. No es diplomacia vacía. Es una técnica precisa para hacer avanzar las decisiones sin quemar las relaciones.\n🛠️ Cómo funciona en la práctica diaria #En treinta años de proyectos, he aplicado el \u0026ldquo;Sí-Y\u0026rdquo; en decenas de situaciones. Funciona dondequiera que haya una decisión que tomar y varias personas con opiniones diferentes.\nEn las reuniones de proyecto #En lugar de: \u0026ldquo;No, la timeline de tres meses es irreal.\u0026rdquo;\nPrueba con: \u0026ldquo;Sí, tres meses es el objetivo. Y para llegar, deberíamos reducir el alcance del primer lanzamiento a estas tres funcionalidades — las demás las ponemos en la fase dos.\u0026rdquo;\n¿Notas la diferencia? En la primera versión tienes un muro. En la segunda tienes un plan.\nEn las code reviews #En lugar de: \u0026ldquo;No, este enfoque está mal, lo has escrito de forma demasiado complicada.\u0026rdquo;\nPrueba con: \u0026ldquo;Sí, funciona. Y podríamos simplificarlo extrayendo esta lógica a un método separado — se vuelve más testeable.\u0026rdquo;\nEl desarrollador no se siente atacado. Se siente ayudado. Y la próxima vez viene a pedirte opinión antes de escribir el código, no después.\nEn las negociaciones con stakeholders #En lugar de: \u0026ldquo;No, no podemos añadir esa feature ahora, ya vamos retrasados.\u0026rdquo;\nPrueba con: \u0026ldquo;Sí, esa feature tiene sentido. Y para incluirla sin comprometer la fecha de entrega, deberíamos sustituirla por esta otra que es menos prioritaria. ¿Cuál de las dos preferís?\u0026rdquo;\nEl stakeholder no oye un \u0026ldquo;no\u0026rdquo;. Oye un \u0026ldquo;sí, y ahora decidimos juntos cómo hacerlo\u0026rdquo;.\n⚠️ Cuándo el \u0026ldquo;Sí-Y\u0026rdquo; no funciona #Sería bonito decir que funciona siempre. No es así. Hay situaciones en las que el \u0026ldquo;Sí-Y\u0026rdquo; es la herramienta equivocada.\nProblemas de seguridad. Si alguien propone quitar la autenticación de la base de datos de producción porque \u0026ldquo;ralentiza las queries\u0026rdquo;, la respuesta no es \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo;. La respuesta es \u0026ldquo;No. Punto.\u0026rdquo;\nViolaciones de proceso. Si un desarrollador quiere hacer deploy en producción el viernes por la noche sin tests, no hay \u0026ldquo;Sí-Y\u0026rdquo; que valga. Hay un proceso, y hay que respetarlo.\nDeadlines no negociables. Cuando el go-live es el lunes y estamos a jueves, no es el momento de construir sobre las ideas de todos. Es el momento de decidir, ejecutar y cerrar.\nComportamientos tóxicos. El \u0026ldquo;Sí-Y\u0026rdquo; funciona con personas de buena fe que tienen opiniones diferentes. No funciona con quien solo quiere tener razón, con quien boicotea, con quien no escucha por principio. En esos casos hace falta otro tipo de conversación — privada, directa y muy franca.\nLa técnica no es una fórmula mágica. Es una herramienta. Y como todas las herramientas, hay que saber cuándo usarla y cuándo dejarla.\n📊 El coste oculto del \u0026ldquo;No, pero\u0026hellip;\u0026rdquo; #Intenté hacer un cálculo aproximado en un proyecto que gestioné hace dos años. Un equipo de ocho personas, reuniones tres veces por semana.\nSituación Duración media de la reunión Decisiones tomadas Antes (cultura del \u0026ldquo;No, pero\u0026hellip;\u0026rdquo;) 1h 20min 0.5 por reunión Después (cultura del \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo;) 45min 1.8 por reunión El equipo tomaba decisiones tres veces más rápido y las reuniones duraban casi la mitad.\nNo tengo datos científicos. Son datos empíricos, recogidos en un proyecto específico. Pero el patrón es coherente con lo que he visto en veinte años: los equipos que discuten de forma constructiva van más rápido que los que pelean. No porque eviten el conflicto — porque lo atraviesan mejor.\n🎯 Lo que he aprendido #El \u0026ldquo;Sí-Y\u0026rdquo; no es diplomacia. No es evitar el enfrentamiento. No es decir sí a todo.\nEs reconocer que la mayoría de las discusiones en los proyectos IT no tratan de quién tiene razón. Tratan de cómo hacer que las cosas avancen. Y las cosas avanzan cuando las personas se sienten escuchadas, no cuando son derrotadas.\nHe visto proyectos bloquearse durante semanas porque dos personas brillantes no conseguían dejar de decirse \u0026ldquo;no\u0026rdquo; mutuamente. Y he visto esos mismos proyectos desbloquearse en quince minutos cuando alguien tuvo el buen sentido de decir \u0026ldquo;sí, y\u0026hellip;\u0026rdquo;.\nNo hace falta un curso de comunicación. No hace falta un coach. Hace falta probar, la próxima vez que alguien diga algo con lo que no estés de acuerdo, a responder \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo; en lugar de \u0026ldquo;No, pero\u0026hellip;\u0026rdquo;.\nUn ejercicio sencillo. Que cambia la forma en que se toman las decisiones.\nQue cambia la forma en que las personas trabajan juntas.\nY que, a veces, salva una reunión que estaba a punto de estallar.\n💬 Para quien le haya pasado al menos una vez #Si alguna vez has estado en una reunión donde dos personas hablaban a la vez y nadie escuchaba a nadie. Si alguna vez has visto un proyecto bloquearse no por un problema técnico, sino por un problema de comunicación. Si alguna vez has pensado \u0026ldquo;¿por qué no podemos simplemente decidir?\u0026rdquo;\nPrueba el \u0026ldquo;Sí-Y\u0026rdquo;. La próxima reunión. Una sola vez.\nNo cuesta nada. No necesita aprobación. No requiere presupuesto.\nSolo requiere la capacidad de contenerte un segundo antes de decir \u0026ldquo;no\u0026rdquo; — y sustituirlo por \u0026ldquo;sí, y\u0026hellip;\u0026rdquo;.\nEl resultado podría sorprenderte.\nGlosario #Yes-And — Técnica de comunicación nacida en el teatro de improvisación que sustituye el \u0026ldquo;No, pero\u0026hellip;\u0026rdquo; por \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo;, transformando las discusiones en construcción colaborativa.\nStakeholder — Persona o grupo con un interés directo en el resultado de un proyecto: cliente, usuario final, sponsor, equipo técnico o cualquier parte afectada por las decisiones del proyecto.\nScope — Perímetro de un proyecto que define qué está incluido y qué excluido: funcionalidades, entregables, restricciones y límites acordados con los stakeholders.\nLift-and-Shift — Estrategia de migración que traslada un sistema de un entorno a otro sin modificar su arquitectura, código o configuración.\nTimeboxing — Técnica de gestión del tiempo que asigna un intervalo fijo y no negociable a una actividad, forzando la conclusión dentro del límite establecido.\nEl resultado podría sorprenderte.\n","date":"13 enero 2026","permalink":"https://ivanluminaria.com/es/posts/project-management/tecnica-si-e-yes-and/","section":"Database Strategy","summary":"\u003cp\u003eEra un jueves por la tarde, una de esas reuniones que sobre el papel debía durar una hora. Éramos siete, conectados en una llamada. El orden del día era sencillo: decidir la estrategia de migración de una base de datos Oracle de on-premise a cloud.\u003c/p\u003e\n\u003cp\u003eSencillo, claro. Sobre el papel.\u003c/p\u003e\n\u003cp\u003eA los veinte minutos, la reunión se había convertido en un duelo.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-la-chispa\" class=\"relative group\"\u003e🔥 La chispa \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-la-chispa\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePor un lado estaba el responsable de infraestructura. Hombre de experiencia, veinte años de datacenters a sus espaldas. Su posición era granítica: \u003cstrong\u003emigración lift-and-shift, cero cambios en la arquitectura, se lleva todo tal como está\u003c/strong\u003e.\u003c/p\u003e","title":"La técnica del Sí-Y: cómo evité una discusión que estaba a punto de estallar"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/team-leadership/","section":"Tags","summary":"","title":"Team-Leadership"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/users/","section":"Tags","summary":"","title":"Users"},{"content":"Hace unas semanas un cliente me llama. Tono pragmático, petición aparentemente banal:\n\u0026ldquo;Necesito crear un usuario en MySQL para una aplicación que debe acceder a una base de datos. ¿Puedes encargarte?\u0026rdquo;\nClaro. CREATE USER, `GRANT` , siguiente.\nSolo que después añade: \u0026ldquo;La aplicación corre en dos servidores diferentes. Y a veces también nos conectaremos en local para mantenimiento.\u0026rdquo;\nAhí es donde la cosa deja de ser banal. Porque en MySQL, crear \u0026ldquo;un usuario\u0026rdquo; no significa lo que piensas.\nEl modelo de autenticación de MySQL: usuario + host #Lo primero que hay que entender — y que muchos DBA con experiencia en Oracle o PostgreSQL descubren a costa propia — es que en MySQL la identidad de un usuario no es solo su nombre.\nEs el par 'usuario'@'host'.\nEsto significa que:\n\u0026#39;mario\u0026#39;@\u0026#39;localhost\u0026#39; \u0026#39;mario\u0026#39;@\u0026#39;192.168.1.10\u0026#39; \u0026#39;mario\u0026#39;@\u0026#39;%\u0026#39; no son el mismo usuario. Son tres usuarios diferentes. Con contraseñas diferentes, privilegios diferentes, comportamientos diferentes.\nCuando MySQL recibe una conexión, mira dos cosas:\nEl nombre de usuario proporcionado La dirección IP (o hostname) desde la que llega la conexión Luego busca en la tabla mysql.user la fila que corresponde al par más específico. No la primera encontrada. La más específica.\n¿Por qué este modelo? #La elección de diseño no es casual. MySQL nació en 1995 para la web. Entornos donde la misma base de datos sirve aplicaciones que corren en máquinas diferentes, redes diferentes, con necesidades de acceso diferentes.\nEl modelo usuario@host permite:\ndar acceso completo desde localhost (para el DBA) dar acceso limitado desde un application server específico bloquear todo lo demás Sin firewall. Sin VPN. Directamente en el motor de autenticación.\nEs un modelo potente. Pero si no lo entiendes, te muerde.\nEl caso del cliente: cómo lo resolví #Volvamos a la petición. La aplicación corre en dos servidores (192.168.1.20 y 192.168.1.21) y también se necesita acceso local para mantenimiento.\nLa tentación es crear un único usuario con '%' (comodín = cualquier host):\nCREATE USER \u0026#39;app_ventas\u0026#39;@\u0026#39;%\u0026#39; IDENTIFIED BY \u0026#39;PasswordSegura#2026\u0026#39;; GRANT SELECT, INSERT, UPDATE ON ventas_db.* TO \u0026#39;app_ventas\u0026#39;@\u0026#39;%\u0026#39;; ¿Funciona? Sí. ¿Es correcto? No.\nEl problema del '%' es que acepta conexiones desde cualquier IP. Si mañana alguien encuentra la contraseña, puede conectarse desde cualquier punto de la red. O del mundo, si la base de datos está expuesta.\nLa solución correcta es crear usuarios específicos para cada origen:\n-- Acceso desde el application server primario CREATE USER \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.20\u0026#39; IDENTIFIED BY \u0026#39;PasswordSegura#2026\u0026#39;; GRANT SELECT, INSERT, UPDATE ON ventas_db.* TO \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; -- Acceso desde el application server secundario CREATE USER \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.21\u0026#39; IDENTIFIED BY \u0026#39;PasswordSegura#2026\u0026#39;; GRANT SELECT, INSERT, UPDATE ON ventas_db.* TO \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.21\u0026#39;; -- Acceso local para mantenimiento (privilegios diferentes) CREATE USER \u0026#39;app_ventas\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;PasswordMant#2026\u0026#39;; GRANT SELECT ON ventas_db.* TO \u0026#39;app_ventas\u0026#39;@\u0026#39;localhost\u0026#39;; Tres usuarios. Mismo nombre. Privilegios calibrados.\nEl usuario local tiene solo SELECT porque sirve para verificaciones, no para escribir datos. Contraseña diferente porque el contexto de uso es diferente.\nPrincipio del privilegio mínimo . Aplicado en el punto correcto.\nLa trampa del matching: ¿quién gana? #Aquí es donde nacen la mayoría de los errores.\nSi existen tanto 'mario'@'%' como 'mario'@'localhost', y Mario se conecta desde localhost, ¿qué usuario se usa?\nRespuesta: 'mario'@'localhost'.\nMySQL ordena las filas en la tabla mysql.user de la más específica a la menos específica:\nHost literal exacto (192.168.1.20) Patrón con comodín (192.168.1.%) Comodín total (%) Y usa la primera coincidencia en orden de especificidad.\nEl problema clásico es este: creas 'mario'@'%' con todos los privilegios. Después alguien crea 'mario'@'localhost' sin privilegios (o con una contraseña diferente). Desde ese momento, Mario ya no puede entrar desde local y nadie entiende por qué.\nHe visto este escenario al menos una docena de veces en producción. La solución es siempre la misma: verifica qué existe antes de crear.\nSELECT user, host, authentication_string FROM mysql.user WHERE user = \u0026#39;mario\u0026#39;; Si no lo haces antes, lo harás después. Con más urgencia y menos calma.\nMySQL vs MariaDB: las diferencias que importan #El modelo usuario@host es idéntico entre MySQL y MariaDB. Pero hay diferencias de implementación que vale la pena conocer.\nAutenticación por defecto:\nVersión Plugin por defecto MySQL 5.7 mysql_native_password MySQL 8.0+ caching_sha2_password MariaDB 10.x mysql_native_password Si migras de MariaDB a MySQL 8 (o viceversa), los clientes podrían no conectarse porque el plugin de autenticación es diferente. No es un bug. Es un cambio de configuración por defecto.\nCreación de usuarios:\nEn MySQL 8, GRANT ya no crea usuarios implícitamente. Debes hacer CREATE USER primero y GRANT después. Siempre.\n-- MySQL 8: correcto CREATE USER \u0026#39;app\u0026#39;@\u0026#39;10.0.0.5\u0026#39; IDENTIFIED BY \u0026#39;pwd123\u0026#39;; GRANT SELECT ON mydb.* TO \u0026#39;app\u0026#39;@\u0026#39;10.0.0.5\u0026#39;; -- MySQL 5.7 / MariaDB: todavía funciona (pero está deprecado) GRANT SELECT ON mydb.* TO \u0026#39;app\u0026#39;@\u0026#39;10.0.0.5\u0026#39; IDENTIFIED BY \u0026#39;pwd123\u0026#39;; Si estás escribiendo scripts de provisioning, este detalle puede romper una pipeline CI/CD entera.\nRoles:\nMySQL 8.0 introdujo los roles. MariaDB los soporta desde la 10.0.5, pero con sintaxis ligeramente diferente.\n-- MySQL 8.0 CREATE ROLE \u0026#39;role_lectura\u0026#39;; GRANT SELECT ON ventas_db.* TO \u0026#39;role_lectura\u0026#39;; GRANT \u0026#39;role_lectura\u0026#39; TO \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; SET DEFAULT ROLE \u0026#39;role_lectura\u0026#39; FOR \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; -- MariaDB 10.x CREATE ROLE role_lectura; GRANT SELECT ON ventas_db.* TO role_lectura; GRANT role_lectura TO \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; SET DEFAULT ROLE role_lectura FOR \u0026#39;app_ventas\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; La diferencia parece cosmética (comillas o no), pero en scripts automatizados puede generar errores sintácticos.\nEl usuario anónimo: el fantasma que nadie invitó #MySQL viene instalado con un usuario anónimo : ''@'localhost'. Sin nombre, sin contraseña.\nEste usuario es un residuo histórico de las instalaciones de desarrollo. En producción es un riesgo de seguridad puro.\nEl usuario anónimo gana sobre 'mario'@'%' cuando la conexión llega desde localhost, porque 'localhost' es más específico que '%'.\nResultado: Mario se conecta desde local, MySQL lo autentica como usuario anónimo, y los privilegios de Mario desaparecen.\nLo primero que hay que hacer en cualquier instalación MySQL/MariaDB en producción:\nSELECT user, host FROM mysql.user WHERE user = \u0026#39;\u0026#39;; -- Si se encuentra: DROP USER \u0026#39;\u0026#39;@\u0026#39;localhost\u0026#39;; DROP USER \u0026#39;\u0026#39;@\u0026#39;%\u0026#39;; -- si existe FLUSH PRIVILEGES ; No es paranoia. Es higiene.\nChecklist operativa #Después de la experiencia con el cliente, formalicé una checklist que uso cada vez que debo crear usuarios en MySQL o MariaDB:\nVerifica usuarios existentes con el mismo nombre en hosts diferentes Elimina usuarios anónimos si están presentes Crea usuarios con hosts específicos, nunca con '%' en producción si no es estrictamente necesario Asigna solo los privilegios necesarios — SELECT si basta SELECT Usa CREATE USER + GRANT separados (obligatorio en MySQL 8) Verifica el plugin de autenticación si los clientes tienen problemas de conexión Documenta los pares usuario/host — en seis meses nadie recordará por qué existen tres \u0026ldquo;app_ventas\u0026rdquo; Conclusión #En MySQL y MariaDB un usuario no es un nombre. Es un nombre ligado a un punto de origen.\nEste modelo es potente porque permite segmentar los accesos sin infraestructura adicional. Pero también es fuente de errores sutiles si no se comprende a fondo.\nLa próxima vez que alguien te pida \u0026ldquo;crear un usuario en MySQL\u0026rdquo;, antes de escribir el primer CREATE USER, pregúntate: ¿desde dónde se conectará?\nLa respuesta a esa pregunta lo cambia todo.\nGlosario #GRANT — Comando SQL para asignar privilegios a un usuario o rol. En MySQL 8 ya no crea usuarios implícitamente: primero CREATE USER, luego GRANT.\nLeast Privilege — Principio de seguridad que prevé asignar solo los permisos estrictamente necesarios. En MySQL se aplica calibrando privilegios por par usuario/host.\nAuthentication Plugin — Módulo que gestiona la verificación de credenciales. El default cambia entre MySQL 5.7 (mysql_native_password), MySQL 8 (caching_sha2_password) y MariaDB.\nAnonymous User — Usuario MySQL sin nombre (''@'localhost') creado automáticamente durante la instalación. Puede interferir con el matching de usuarios legítimos y debe eliminarse en producción.\nFLUSH PRIVILEGES — Comando que recarga las tablas de grant en memoria, haciendo efectivos los cambios manuales de privilegios. Necesario después de operaciones directas sobre la tabla mysql.user.\n","date":"13 enero 2026","permalink":"https://ivanluminaria.com/es/posts/mysql/mysql-users-and-hosts/","section":"Database Strategy","summary":"\u003cp\u003eHace unas semanas un cliente me llama. Tono pragmático, petición aparentemente banal:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Necesito crear un usuario en MySQL para una aplicación que debe acceder a una base de datos. ¿Puedes encargarte?\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eClaro. \u003ccode\u003eCREATE USER\u003c/code\u003e, \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Comando SQL para asignar privilegios específicos a un usuario o rol sobre bases de datos, tablas o columnas. En MySQL 8 ya no crea usuarios implícitamente.\" data-glossary-url=\"/es/glossary/grant/\" data-glossary-more=\"Leer más →\"\u003e`GRANT`\u003c/span\u003e\n, siguiente.\u003c/p\u003e\n\u003cp\u003eSolo que después añade: \u0026ldquo;La aplicación corre en dos servidores diferentes. Y a veces también nos conectaremos en local para mantenimiento.\u0026rdquo;\u003c/p\u003e","title":"Usuarios MySQL: por qué 'mario' y 'mario'@'localhost' no son la misma persona"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/indexes/","section":"Tags","summary":"","title":"Indexes"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/pg_trgm/","section":"Tags","summary":"","title":"Pg_trgm"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/query-tuning/","section":"Tags","summary":"","title":"Query-Tuning"},{"content":"Hace algunas semanas, un cliente me contactó con un problema muy común:\n\u0026ldquo;La búsqueda en la consola administrativa es lenta. A veces tarda varios segundos. Ya hemos reducido las JOIN, pero el problema no ha desaparecido.\u0026rdquo;\nEntorno: PostgreSQL en cloud managed.\nTabla principal: payment_report (~6 millones de filas, 3 GB).\nColumna buscada: reference_code.\nQuery problemática:\nSELECT * FROM reporting.payment_report r JOIN reporting.payment_cart c ON c.id = r.cart_id WHERE c.service_id = 1001 AND r.reference_code LIKE \u0026#39;%ABC123%\u0026#39; ORDER BY c.created_at DESC LIMIT 100; 🧠 Primera observación: las JOIN no eran el problema #Comparé:\nVersión AS-IS (3 JOIN sobre la misma tabla) Versión TO-BE (solo 1 JOIN) ¿El resultado?\nEl plan de ejecución mostraba en ambos casos:\nParallel Seq Scan on payment_report Rows Removed by Filter: ~2,000,000 Buffers: shared read = cientos de miles Execution Time: 14–18 seconds Reducir las JOIN tuvo un impacto marginal.\nEl verdadero problema era otro.\n📌 El culpable: LIKE '%valor%' sin un índice adecuado #Una búsqueda con wildcard inicial (%valor%) hace inutilizable un índice B-Tree normal.\nPostgreSQL se ve obligado a realizar un escaneo secuencial de toda la tabla.\nEn este caso específico:\n~3 GB de datos cientos de miles de páginas de 8KB leídas carga dominada por I/O segundos de latencia No es un problema de \u0026ldquo;SQL mal escrito\u0026rdquo;. Es un problema de access path.\n🔬 Antes de crear un índice: análisis de riesgo #El cliente preguntó con razón:\n\u0026ldquo;Si creamos un índice trigram (GIN), ¿corremos el riesgo de ralentizar las transacciones de pago?\u0026rdquo;\nAquí entra en juego un concepto que a menudo se ignora: el **churn** .\n¿Qué es el churn? #Representa cuánto cambia una tabla después de insertar las filas.\nAlta frecuencia de: - UPDATE - DELETE\n→ alto churn\n→ mayor coste de mantenimiento del índice\n→ posible degradación en escrituras\nEn nuestro caso:\nTabla payment_report: - ~12k inserciones/día - 0 updates - 0 deletes - 0 dead tuples\nPerfil: append-only\nEste es el mejor escenario posible para introducir un índice GIN.\n📊 Verificación clave: ¿sincrónico o batch? #La tabla no tenía timestamp de inserción.\nSolución: análisis indirecto.\nCorrelacioné las filas de payment_report con el timestamp del carrito (payment_cart.created_at) y analicé la distribución horaria.\nResultado:\npatrón continuo 24/7 picos diurnos descenso nocturno correlación perfecta con el tráfico de carritos Conclusión: carga near real-time, no batch nocturno.\n🛠️ La solución #CREATE EXTENSION IF NOT EXISTS pg_trgm ; CREATE INDEX CONCURRENTLY idx_payment_report_reference_trgm ON reporting.payment_report USING gin (reference_code gin_trgm_ops); Precauciones:\nCrear en ventana off-peak Usar modo CONCURRENTLY Monitorizar I/O durante la creación 📈 Resultado: el plan de ejecución antes y después #Este es el plan de ejecución completo de la query — antes y después de crear el índice trigram.\nAntes (sin índice trigram):\nNested Loop Inner Join → Nested Loop Inner Join → Nested Loop Inner Join → Seq Scan on payment_report as r Filter: ((reference_code)::text ~~ \u0026#39;%ABC123%\u0026#39;::text) → Index Scan using payment_cart_pkey on payment_cart as c Filter: (service_id = 1001) Index Cond: (id = r.cart_id) → Index Only Scan using payment_cart_pkey on payment_cart as c2 Index Cond: (id = c.id) → Index Only Scan using payment_cart_pkey on payment_cart as c3 Index Cond: (id = c.id) Después (con índice trigram):\nNested Loop Inner Join → Nested Loop Inner Join → Nested Loop Inner Join → Bitmap Heap Scan on payment_report as r Recheck Cond: ((reference_code)::text ~~ \u0026#39;%ABC123%\u0026#39;::text) → Bitmap Index Scan using idx_payment_report_reference_trgm Index Cond: ((reference_code)::text ~~ \u0026#39;%ABC123%\u0026#39;::text) → Index Scan using payment_cart_pkey on payment_cart as c Filter: (service_id = 1001) Index Cond: (id = r.cart_id) → Index Only Scan using payment_cart_pkey on payment_cart as c2 Index Cond: (id = c.id) → Index Only Scan using payment_cart_pkey on payment_cart as c3 Index Cond: (id = c.id) El punto clave está en los pasos 4–5: el Seq Scan — que leía toda la tabla fila por fila — ha sido reemplazado por un Bitmap Heap Scan guiado por el índice trigram idx_payment_report_reference_trgm. PostgreSQL ahora filtra directamente a través del índice y solo hace el recheck en las filas candidatas.\nMisma query, mismo dato, pero un access path completamente diferente. De segundos a milisegundos.\n🎯 Lección clave #Cuando una query es lenta:\nNo te detengas en el número de JOIN. Mira el plan de ejecución. Identifica si el cuello de botella es CPU o I/O. Evalúa el churn antes de introducir un índice GIN. Mide siempre antes de decidir. A menudo el problema no es \u0026ldquo;optimizar la query\u0026rdquo;.\nEs darle al planner el índice correcto.\n💬 ¿Por qué comparto este caso? #Porque es un escenario extremadamente común:\nTablas grandes Búsquedas tipo \u0026ldquo;contiene\u0026rdquo; Miedo a introducir índices GIN Temor a degradar el rendimiento de escritura Con datos en la mano, la decisión se vuelve técnica, no emocional.\nLa optimización no es magia.\nEs medición, análisis de planes y comprensión del comportamiento real del sistema.\nGlosario #GIN Index — Generalized Inverted Index: tipo de índice PostgreSQL que crea un mapping inverso de cada elemento a los registros que lo contienen. Ideal para búsquedas \u0026ldquo;contiene\u0026rdquo; en texto con pg_trgm.\nB-Tree — Estructura de datos de árbol balanceado, índice predeterminado en bases de datos relacionales. Eficiente para búsquedas de igualdad y rango, pero inutilizable para LIKE '%valor%'.\npg_trgm — Extensión PostgreSQL que descompone texto en trigramas (secuencias de 3 caracteres), habilitando índices GIN para acelerar búsquedas con wildcard.\nChurn — Medida de cuánto cambia una tabla después de la inserción. Bajo churn (append-only) es el mejor escenario para introducir un índice GIN sin degradar las escrituras.\nExecution Plan — Secuencia de operaciones elegida por la base de datos para resolver una query. Leer el plan es el primer paso para identificar si el problema es CPU, I/O o un access path incorrecto.\n","date":"6 enero 2026","permalink":"https://ivanluminaria.com/es/posts/postgresql/like-optimization-postgresql/","section":"Database Strategy","summary":"\u003cp\u003eHace algunas semanas, un cliente me contactó con un problema muy común:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;La búsqueda en la consola administrativa es lenta. A veces tarda\nvarios segundos. Ya hemos reducido las JOIN, pero el problema no ha\ndesaparecido.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eEntorno: PostgreSQL en cloud managed.\u003cbr\u003e\nTabla principal: \u003ccode\u003epayment_report\u003c/code\u003e (~6 millones de filas, 3 GB).\u003cbr\u003e\nColumna buscada: \u003ccode\u003ereference_code\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eQuery problemática:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereporting\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epayment_report\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereporting\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epayment_cart\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eON\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecart_id\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eservice_id\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1001\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"k\"\u003eAND\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereference_code\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eLIKE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;%ABC123%\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eBY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecreated_at\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"-primera-observación-las-join-no-eran-el-problema\" class=\"relative group\"\u003e🧠 Primera observación: las JOIN no eran el problema \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-primera-observaci%c3%b3n-las-join-no-eran-el-problema\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eComparé:\u003c/p\u003e","title":"When a LIKE '%value%' Slows Everything Down: A Real PostgreSQL Optimization Case"},{"content":"La historia que voy a contar es real. No daré nombres — no por diplomacia, sino porque los nombres no importan. Lo que importa es entender el mecanismo. Porque este mecanismo se repite, idéntico, en decenas de empresas. Y cuesta millones.\n🏢 El cliente: un grupo asegurador con una ambición legítima #Una empresa sólida del sector asegurador. Operaciones en Italia, Francia, países del Norte de Europa, España. Miles de empleados, millones de pólizas gestionadas, un negocio en crecimiento.\nEn un momento dado, la dirección toma una decisión razonable: necesitamos un software de gestión a medida. Un sistema que refleje nuestros procesos, nuestras reglas de negocio, las especificidades normativas de cada país en el que operamos.\nDecisión legítima. Sensata. Incluso estratégica.\nEl problema no es la decisión.\nEl problema es a quién se la confían.\n💰 Primer acto: la gran multinacional (2013–2018) #Se contrata — en pleno outsourcing — a una de las Big de la consultoría IT mundial. Un nombre que todos conocen. Miles de consultores, oficinas en cada continente, presentaciones en PowerPoint que harían llorar de emoción.\nEl proyecto arranca. Se definen los requisitos. Se estima el presupuesto. Se firman los contratos.\nPasan los meses. Luego los años.\nLos entregables llegan — sobre el papel. Pero el software no funciona como debería. Las especificaciones cambian. Los costes se disparan. Los consultores rotan: el que había entendido el dominio se va, llega otro que empieza de cero. El clásico esquema de consultoría a cuerpo que se convierte, en la práctica, en una consultoría a tiempo indefinido.\nDe 2013 a 2018: más de 2,5 millones de euros gastados.\nResultado: un software incompleto, inestable, que nadie internamente sabía mantener.\nPorque el código lo habían escrito ellos. Con sus convenciones. Con su arquitectura. Y cuando se fueron, se llevaron también el conocimiento.\n🔄 Segundo acto: cambiamos de proveedor (2018–2022) #La dirección, escarmentada pero no resignada, decide cambiar. \u0026ldquo;El problema era el proveedor\u0026rdquo;, piensan. \u0026ldquo;Busquemos uno mejor.\u0026rdquo;\nEntra en escena otra multinacional. Igual de famosa. Igual de grande. Igual de cara.\nNuevo kickoff. Nuevo análisis de requisitos — porque obviamente no pueden partir del trabajo del proveedor anterior. Nuevas diapositivas. Nuevas promesas.\nY la historia se repite.\nMismos problemas, actores diferentes. Rotación de consultores. Pérdida de know-how. Plazos que se alargan. Presupuestos que explotan. Reuniones interminables en las que se discuten hitos que nunca llegan.\nDe 2018 a 2022: otros 1,5 millones de euros.\nResultado: otro software que no satisface las necesidades del negocio.\nTotal invertido en casi una década: más de 4 millones de euros.\nSoftware funcionando: cero.\n📊 Hagamos las cuentas del desastre # Período Proveedor Inversión Resultado 2013 – 2018 Multinacional A ~2.500.000 € Software incompleto, abandonado 2018 – 2022 Multinacional B ~1.500.000 € Software inadecuado, abandonado Total ~4.000.000+ € Ningún software en producción Cuatro millones de euros. Casi diez años de proyecto. Dos de los nombres más prestigiosos de la consultoría IT global.\nY al final, la empresa se encuentra exactamente en el punto de partida.\nNo es mala suerte. Es un patrón.\nY quien lleva treinta años trabajando en este sector, como yo, lo reconoce a primera vista.\n🧠 Por qué sucede: la anatomía del fracaso #Este tipo de fracaso no es un accidente. Es el resultado previsible de un modelo de negocio con un defecto estructural.\n1. El incentivo está equivocado.\nUna gran consultora gana dinero vendiendo jornadas-hombre. Cuanto más dura el proyecto, más factura. No hay ningún incentivo real para cerrar el proyecto rápido y bien. Hay un incentivo para mantenerlo vivo el mayor tiempo posible.\n2. La rotación es endémica.\nLas multinacionales de consultoría tienen tasas de rotación del 15-25% anual. En un proyecto que dura cinco años, el equipo se renueva completamente al menos dos veces. Cada vez se empieza de nuevo: nueva curva de aprendizaje, nueva interpretación de los requisitos, nuevos errores.\n3. El know-how se va por la puerta (vendor lock-in ).\nCuando el proveedor termina (o es despedido), el conocimiento del sistema se va con él. El cliente se queda con un software que no entiende, no sabe mantener y no puede evolucionar.\n4. Las especificaciones se convierten en un arma (scope creep ).\nEn un proyecto custom de esta envergadura, las especificaciones siempre están incompletas — porque el negocio es complejo y está en evolución. Esto se convierte en la coartada perfecta: \u0026ldquo;el software no funciona porque las especificaciones han cambiado\u0026rdquo;. Y siempre es culpa de otro.\n✅ El punto de inflexión: comprar, no construir #Al final, tras casi una década y más de 4 millones quemados, la empresa toma la decisión que debería haber tomado desde el principio:\nComprar un software de mercado ya funcional y adaptarlo internamente a sus necesidades.\nUn producto asegurador comercial, probado, con una base de código estable y una comunidad de soporte. Y un equipo interno — personas que conocen el negocio, que permanecen en la empresa, que acumulan conocimiento en lugar de dispersarlo — encargado de personalizarlo y evolucionarlo.\n¿Coste? Una fracción de lo gastado en los diez años anteriores.\n¿Resultado? Un sistema que funciona. Que evoluciona. Que la empresa realmente posee.\nLa lección es brutal en su sencillez:\nNo todo hay que construirlo desde cero. Y sobre todo, no todo hay que delegarlo en quien no tiene interés en terminar.\n🏗️ La comparación que duele: nuestro Data Warehouse #Y aquí entra la parte de la historia que conozco por dentro. Porque para la misma empresa, en el mismo período, un colega y yo construimos algo que funciona. Cada día.\nUn **Data Warehouse** completo. Diseñado, desarrollado, puesto en producción y mantenido por dos personas.\nNo una demo. No un prototipo. Un sistema de producción que:\nCarga datos cada día — el ciclo ETL completo se ejecuta en una hora y media Integra 4 sistemas fuente diferentes — cada uno con su formato, su protocolo, sus particularidades Recoge datos de 4 áreas geográficas: Italia, Francia, países del Norte de Europa, España Comprende aproximadamente 60.000 líneas de código escritas a cuatro manos La arquitectura fue diseñada por mí — desde el modelo de datos a la estrategia de carga, desde la gestión de errores a la historización Software de gestión custom Data Warehouse Equipo Dos multinacionales (decenas de consultores) 2 personas Duración del proyecto ~10 años (y contando) 3 años Presupuesto 4.000.000+ € Una fracción Líneas de código Desconocidas (y abandonadas) ~60.000 (documentadas, mantenidas) Resultado Ningún software en producción Sistema en producción diaria Tiempo de procesamiento — 1h 30min / día Cobertura geográfica — 4 países, 4 sistemas fuente Know-how Perdido con cada cambio de proveedor Interno, estable, documentado Dos personas. Tres años. Un sistema que cada mañana se despierta, recoge datos de cuatro rincones de Europa, los transforma, los carga y los pone a disposición para las decisiones empresariales. En una hora y media.\nSesenta mil líneas de código. Cada una pensada, probada, mantenida por quien la escribió.\nNingún PowerPoint. Ningún kickoff. Ningún consultor que se va llevándose el conocimiento.\nSolo competencia, arquitectura sólida y trabajo bien hecho.\n🎯 La lección #Cuando hablo con empresas que están a punto de emprender un gran proyecto IT, siempre les digo lo mismo:\nNo paguéis por una marca. Pagad por las personas.\nUn equipo pequeño de profesionales que conocen el dominio, que permanecen en el proyecto, que son responsables del resultado — vale más que cien consultores rotando y facturando jornadas.\nEl software no se construye con diapositivas. Se construye con las manos en el código, con la arquitectura en la cabeza y con la responsabilidad encima.\nCuatro millones de euros en humo enseñan una sola cosa:\nEl coste más alto no es el del proveedor equivocado que eliges.\nEs el del tiempo que pierdes antes de entender que la solución era más sencilla de lo que te habían vendido.\n💬 A quien está a punto de firmar ese contrato #Si tu empresa está a punto de confiar un proyecto crítico a una gran consultora, detente un momento.\nPregúntate:\n¿Quién escribirá el código? ¿Seguirá en la empresa dentro de dos años? Si el proveedor se va mañana, ¿sabríamos mantener el sistema? ¿Existe un producto de mercado que cubra el 80% de nuestras necesidades? ¿Podemos construir un equipo interno pequeño, competente y estable? Las respuestas a estas preguntas valen más que cualquier propuesta comercial.\nPorque la diferencia entre un proyecto que funciona y uno que quema millones no está en la tecnología.\nEstá en las personas. En la continuidad. En la responsabilidad.\nY en la capacidad de decir \u0026ldquo;no\u0026rdquo; a quien te vende complejidad cuando la solución es simple.\nGlosario #Data Warehouse — Sistema centralizado de recopilación e historización de datos de fuentes diversas, diseñado para análisis y soporte a decisiones empresariales. En el caso descrito, construido por dos personas con 60.000 líneas de código.\nETL — Extract, Transform, Load: proceso de extracción de datos de los sistemas fuente, transformación y carga en el data warehouse. El ciclo ETL del DWH descrito se ejecuta en una hora y media.\nVendor Lock-in — Dependencia estructural de un proveedor externo que hace difícil cambiar de provider. Se instaura cuando el know-how y el código quedan en manos del proveedor.\nScope Creep — Expansión incontrolada de los requisitos del proyecto más allá del alcance inicial. Las especificaciones incompletas se convierten en la coartada para retrasos y costes adicionales.\nOutsourcing — Externalización de actividades IT a proveedores externos. Arriesgado para proyectos estratégicos a largo plazo, donde la rotación de consultores y la pérdida de know-how pueden quemar millones.\n","date":"30 diciembre 2025","permalink":"https://ivanluminaria.com/es/posts/project-management/4-milioni-nessun-software/","section":"Database Strategy","summary":"\u003cp\u003eLa historia que voy a contar es real. No daré nombres — no por diplomacia, sino porque los nombres no importan. Lo que importa es entender el mecanismo. Porque este mecanismo se repite, idéntico, en decenas de empresas. Y cuesta millones.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-el-cliente-un-grupo-asegurador-con-una-ambición-legítima\" class=\"relative group\"\u003e🏢 El cliente: un grupo asegurador con una ambición legítima \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-el-cliente-un-grupo-asegurador-con-una-ambici%c3%b3n-leg%c3%adtima\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUna empresa sólida del sector asegurador. Operaciones en Italia, Francia, países del Norte de Europa, España. Miles de empleados, millones de pólizas gestionadas, un negocio en crecimiento.\u003c/p\u003e","title":"4 millones de euros, dos multinacionales, cero software: historia real de un fracaso anunciado"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/data-warehouse/","section":"Tags","summary":"","title":"Data-Warehouse"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/insurance/","section":"Tags","summary":"","title":"Insurance"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/outsourcing/","section":"Tags","summary":"","title":"Outsourcing"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/execution-plan/","section":"Tags","summary":"","title":"Execution-Plan"},{"content":"Dos mil millones de filas. No es un número que se alcance en un día. Se necesitan años de transacciones, movimientos, registros diarios que se acumulan. Y durante todo ese tiempo la base de datos funciona, las consultas responden, los reportes salen. Luego un día alguien abre un ticket: \u0026ldquo;el reporte mensual tarda cuatro horas.\u0026rdquo;\nCuatro horas. Para un reporte que seis meses antes tardaba veinte minutos.\nNo es un bug. No es un problema de red o de almacenamiento lento. Es la física de los datos: cuando una tabla crece más allá de cierto umbral, los enfoques que funcionaban dejan de funcionar. Y si no diseñaste la estructura para manejar ese crecimiento, la base de datos hace lo único que puede: leerlo todo.\nEl contexto: telecomunicaciones y volúmenes industriales #El cliente era un operador de telecomunicaciones. Nada exótico — un clásico entorno Oracle 19c Enterprise Edition sobre Linux, almacenamiento SAN, unas treinta instancias entre producción, staging y desarrollo. La instancia crítica era la de facturación: facturación, CDR (Call Detail Records), movimientos contables.\nLa tabla en el centro del problema se llamaba TXN_MOVIMENTI. Recopilaba cada transacción individual del sistema de facturación desde 2016. La estructura era más o menos esta:\nCREATE TABLE txn_movimenti ( txn_id NUMBER(18) NOT NULL, data_movimento DATE NOT NULL, cod_cliente VARCHAR2(20) NOT NULL, tipo_movimento VARCHAR2(10) NOT NULL, importo NUMBER(15,4), canale VARCHAR2(30), stato VARCHAR2(5) DEFAULT \u0026#39;ATT\u0026#39;, data_insert TIMESTAMP DEFAULT SYSTIMESTAMP, CONSTRAINT pk_txn_movimenti PRIMARY KEY (txn_id) ); 2.1 mil millones de filas. 380 GB de datos. Un solo segmento, un solo tablespace, sin particiones. Un monolito.\nLos índices estaban ahí: uno en la clave primaria, uno en data_movimento, uno compuesto en (cod_cliente, data_movimento). Pero cuando una tabla supera cierto tamaño, incluso un index range scan ya no es suficiente, porque el volumen de datos devuelto sigue siendo enorme.\nLos síntomas: no es lentitud, es colapso #Los problemas no aparecieron todos a la vez. Llegaron gradualmente, como sucede siempre con las tablas que crecen sin control.\nPrimera señal: los reportes mensuales. La consulta agregada de facturación — que sumaba importes por cliente para un mes dado — había pasado de 20 minutos a 4 horas en el transcurso de un año. El plan de ejecución mostraba un index range scan sobre la fecha, pero el número de bloques leídos era monstruoso: Oracle tenía que recorrer cientos de miles de leaf blocks del índice y luego hacer table access by rowid para recuperar las columnas no cubiertas.\nSegunda señal: el mantenimiento. El ALTER INDEX REBUILD sobre el índice de la fecha requería seis horas. La recopilación de estadísticas (DBMS_STATS.GATHER_TABLE_STATS) no terminaba en una noche. Los backups RMAN se habían convertido en una ruleta: a veces entraban en la ventana, a veces no.\nTercera señal: los full table scan involuntarios. Consultas con predicados sobre la fecha que el optimizador decidía resolver con un full table scan porque el coste estimado del index scan era superior. Sobre 380 GB de datos.\nEl plan de ejecución de la consulta de facturación era este:\nSELECT cod_cliente, TRUNC(data_movimento, \u0026#39;MM\u0026#39;) AS mese, SUM(importo) AS totale FROM txn_movimenti WHERE data_movimento BETWEEN DATE \u0026#39;2025-01-01\u0026#39; AND DATE \u0026#39;2025-01-31\u0026#39; AND stato = \u0026#39;CON\u0026#39; GROUP BY cod_cliente, TRUNC(data_movimento, \u0026#39;MM\u0026#39;); --------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost | --------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 125K | 890K | | 1 | HASH GROUP BY | | 125K | 890K | | 2 | TABLE ACCESS BY INDEX ROWID| TXN_MOVIMENTI | 28M | 885K | |* 3 | INDEX RANGE SCAN | IDX_TXN_DATA | 28M | 85K | --------------------------------------------------------------------- 28 millones de filas solo para enero. El índice encontraba las filas, pero luego Oracle tenía que ir a buscar cada fila individual de la tabla para leer cod_cliente, importo y stato. Millones de operaciones de I/O aleatorio sobre una tabla de 380 GB dispersa en miles de bloques.\nLa solución: no se necesita un índice mejor, se necesita una estructura diferente #Pasé dos días analizando los patrones de acceso antes de proponer cualquier solución. Porque el partitioning no es una varita mágica — si te equivocas con la clave de partición, empeoras las cosas.\nLos patrones eran claros:\nEl 90% de las consultas tenía un predicado sobre la fecha (data_movimento) Los reportes eran siempre mensuales o trimestrales Las consultas operativas (cliente individual) usaban siempre cod_cliente + data_movimento Los datos de más de 3 años no se leían nunca en los reportes, solo en los procesos anuales de archivo La elección recayó en un interval partitioning mensual sobre la columna data_movimento. No range partitioning clásico, donde hay que crear manualmente cada partición futura. Interval: defines el intervalo una vez y Oracle crea las particiones automáticamente cuando llegan datos para un nuevo período.\nLa implementación: CTAS, índices locales y cero downtime (casi) #No se puede hacer ALTER TABLE ... PARTITION BY sobre una tabla existente con 2 mil millones de filas. No en Oracle 19c, al menos no sin Online Table Redefinition. Y esa opción, sobre una tabla de estas dimensiones, tiene sus propios riesgos.\nElegí el enfoque CTAS — Create Table As Select — con paralelismo. Crear la nueva tabla particionada, copiar los datos, renombrar.\nPaso 1: crear la tabla particionada #CREATE TABLE txn_movimenti_part PARTITION BY RANGE (data_movimento) INTERVAL (NUMTOYMINTERVAL(1, \u0026#39;MONTH\u0026#39;)) ( PARTITION p_before_2016 VALUES LESS THAN (DATE \u0026#39;2016-01-01\u0026#39;), PARTITION p_2016_01 VALUES LESS THAN (DATE \u0026#39;2016-02-01\u0026#39;), PARTITION p_2016_02 VALUES LESS THAN (DATE \u0026#39;2016-03-01\u0026#39;) -- Oracle creará automáticamente las particiones posteriores ) TABLESPACE ts_billing_data NOLOGGING PARALLEL 8 AS SELECT /*+ PARALLEL(t, 8) */ txn_id, data_movimento, cod_cliente, tipo_movimento, importo, canale, stato, data_insert FROM txn_movimenti t; El `NOLOGGING` es fundamental: sin él, la copia genera redo log por cada bloque escrito. Sobre 380 GB significaría llenar el área de redo y poner el sistema en modo archivelog durante días. Con NOLOGGING la copia tardó 3 horas y media con paralelismo a 8.\nDespués de la copia restauré el logging:\nALTER TABLE txn_movimenti_part LOGGING; Y lancé un backup RMAN inmediatamente, porque los segmentos NOLOGGING no son recuperables en caso de restore.\nPaso 2: índices locales #El diseño de índices sobre una tabla particionada es diferente de una tabla normal. El concepto clave es: índice local vs índice global.\nUn índice **local** está particionado con la misma clave que la tabla. Cada partición de la tabla tiene su partición de índice correspondiente. Ventaja: las operaciones de mantenimiento sobre una partición no tocan las demás.\nUn índice global abarca todas las particiones. Es más eficiente para consultas que no filtran por la clave de partición, pero cualquier operación DDL sobre la partición (drop, truncate, split) invalida el índice entero.\n-- Clave primaria como índice global (necesario para búsquedas puntuales) ALTER TABLE txn_movimenti_part ADD CONSTRAINT pk_txn_mov_part PRIMARY KEY (txn_id) USING INDEX GLOBAL; -- Índice local sobre la fecha (alineado con la partición) CREATE INDEX idx_txn_mov_data ON txn_movimenti_part (data_movimento) LOCAL PARALLEL 8; -- Índice local compuesto para consultas operativas CREATE INDEX idx_txn_mov_cli_data ON txn_movimenti_part (cod_cliente, data_movimento) LOCAL PARALLEL 8; La clave primaria permanece global porque las consultas por txn_id nunca incluyen la fecha — se necesita acceso directo. Los otros índices son locales porque se alinean con los patrones de uso: consultas por fecha, consultas por cliente+fecha.\nPaso 3: el cambio #-- Renombrar la tabla original (respaldo) ALTER TABLE txn_movimenti RENAME TO txn_movimenti_old; -- Renombrar la nueva tabla ALTER TABLE txn_movimenti_part RENAME TO txn_movimenti; -- Reconstruir sinónimos si existen -- Recompilar objetos invalidados BEGIN FOR obj IN (SELECT object_name, object_type FROM dba_objects WHERE status = \u0026#39;INVALID\u0026#39; AND owner = \u0026#39;BILLING\u0026#39;) LOOP BEGIN IF obj.object_type = \u0026#39;PACKAGE BODY\u0026#39; THEN EXECUTE IMMEDIATE \u0026#39;ALTER PACKAGE billing.\u0026#39; || obj.object_name || \u0026#39; COMPILE BODY\u0026#39;; ELSIF obj.object_type IN (\u0026#39;PROCEDURE\u0026#39;,\u0026#39;FUNCTION\u0026#39;,\u0026#39;VIEW\u0026#39;) THEN EXECUTE IMMEDIATE \u0026#39;ALTER \u0026#39; || obj.object_type || \u0026#39; billing.\u0026#39; || obj.object_name || \u0026#39; COMPILE\u0026#39;; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; END LOOP; END; / El downtime real fue el tiempo de los dos ALTER TABLE RENAME: unos pocos segundos. Todo lo demás — la copia de datos, la creación de índices — ocurrió en paralelo con el sistema activo.\nPaso 4: recopilar estadísticas #BEGIN DBMS_STATS.GATHER_TABLE_STATS( ownname =\u0026gt; \u0026#39;BILLING\u0026#39;, tabname =\u0026gt; \u0026#39;TXN_MOVIMENTI\u0026#39;, granularity =\u0026gt; \u0026#39;ALL\u0026#39;, estimate_percent =\u0026gt; DBMS_STATS.AUTO_SAMPLE_SIZE, degree =\u0026gt; 8 ); END; / El parámetro granularity =\u0026gt; 'ALL' es importante: le dice a Oracle que recopile estadísticas a nivel global, de partición y de subpartición. Sin él, el optimizador podría tomar decisiones equivocadas porque no conoce la distribución de los datos dentro de las particiones individuales.\nAntes y después: los números #La misma consulta de facturación, después del partitioning:\n------------------------------------------------------------------------ | Id | Operation | Name | Rows | Cost | ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 125K | 12K | | 1 | HASH GROUP BY | | 125K | 12K | | 2 | PARTITION RANGE SINGLE | | 28M | 11K | | 3 | TABLE ACCESS FULL | TXN_MOVIMENTI | 28M | 11K | ------------------------------------------------------------------------ Miren la operación en el paso 2: PARTITION RANGE SINGLE. Oracle sabe que los datos de enero están en una sola partición y lee solo esa. El full table scan que antes aterrorizaba es ahora un full partition scan — sobre aproximadamente 4 GB en lugar de 380.\nMétrica Antes Después Variación Tiempo consulta mensual 4 horas 3 minutos -98% Consistent gets 48M 580K -98.8% Physical reads 12M 95K -99.2% Tiempo GATHER_TABLE_STATS 14 horas 25 min (por partición) -97% Tiempo rebuild índice 6 horas 12 min (por partición) -97% Tamaño backup incremental 380 GB ~4 GB/mes -99% El coste pasó de 890K a 12K. No es una mejora porcentual — es un orden de magnitud diferente.\nPartition pruning: la verdadera magia #El mecanismo que hace todo esto posible se llama **partition pruning** . No es algo que se configure — Oracle lo hace automáticamente cuando el predicado de la consulta coincide con la clave de partición.\nPero hay que saber cuándo funciona y cuándo no.\nFunciona con predicados directos sobre la columna de partición:\n-- Pruning activo: Oracle lee solo la partición de enero WHERE data_movimento BETWEEN DATE \u0026#39;2025-01-01\u0026#39; AND DATE \u0026#39;2025-01-31\u0026#39; -- Pruning activo: Oracle lee solo la partición específica WHERE data_movimento = DATE \u0026#39;2025-03-15\u0026#39; No funciona cuando la columna está dentro de una función:\n-- Pruning DESACTIVADO: Oracle debe leer todas las particiones WHERE TRUNC(data_movimento) = DATE \u0026#39;2025-01-01\u0026#39; -- Pruning DESACTIVADO: función sobre la columna WHERE TO_CHAR(data_movimento, \u0026#39;YYYY-MM\u0026#39;) = \u0026#39;2025-01\u0026#39; -- Pruning DESACTIVADO: expresión aritmética WHERE data_movimento + 30 \u0026gt; SYSDATE Este es el error más común que veo después de una implementación de partitioning: los desarrolladores aplican funciones a la columna de fecha sin darse cuenta de que están desactivando el pruning. Y la tabla vuelve a leerse entera.\nDediqué medio día a revisar todas las consultas de la aplicación que tocaban TXN_MOVIMENTI. Encontré once con TRUNC(data_movimento) en el WHERE. Once consultas que habrían ignorado el partitioning.\nLa gestión del ciclo de vida: drop partition #Una de las ventajas más concretas del partitioning es la gestión del ciclo de vida de los datos. Antes del partitioning, archivar datos antiguos significaba un DELETE de miles de millones de filas — una operación que genera montañas de redo y undo, bloquea la tabla durante horas y arriesga hacer explotar el tablespace de undo.\nCon el partitioning:\n-- Archivar los datos de 2016 en un tablespace de solo lectura ALTER TABLE txn_movimenti MOVE PARTITION p_2016_01 TABLESPACE ts_archive; -- O, si los datos ya no se necesitan ALTER TABLE txn_movimenti DROP PARTITION p_2016_01; Un DROP PARTITION sobre una partición de 4 GB tarda menos de un segundo. No genera undo. No genera redo significativo. No bloquea las otras particiones. Es una operación DDL, no DML.\nConfiguré un job mensual que movía las particiones de más de 5 años al tablespace de archivo y las ponía en solo lectura. El cliente recuperó 120 GB de espacio activo sin eliminar un solo dato.\nLo que aprendí (y los errores a evitar) #Después de quince años de partitioning Oracle, tengo una lista de cosas que me gustaría haber sabido antes.\nLa clave de partición debe coincidir con el patrón de acceso. Parece obvio, pero he visto tablas particionadas por cod_cliente cuando el 95% de las consultas filtra por fecha. El partitioning solo funciona si las consultas pueden hacer pruning.\nInterval partitioning es casi siempre mejor que range estático. Con range clásico hay que crear manualmente las particiones futuras, lo que significa un job programado o un DBA que se acuerde. Con interval Oracle las crea solo. Un problema menos.\nLos índices globales son una trampa. Funcionan bien para las consultas, pero cualquier operación DDL sobre la partición los invalida. Y reconstruir un índice global sobre 2 mil millones de filas tarda horas. Usa índices locales donde sea posible y acepta el compromiso.\nNOLOGGING no es opcional para operaciones masivas. Sin NOLOGGING, un CTAS de 380 GB genera la misma cantidad de redo. Tu área de archivelog se llenará, la base de datos entrará en espera, y el DBA de guardia recibirá una llamada a las 3 de la mañana.\nPrueba el pruning antes de ir a producción. No te fíes: verifica con EXPLAIN PLAN que cada consulta crítica haga efectivamente pruning. Un solo TRUNC() en el predicado equivocado y tienes un full table scan de 380 GB.\nEl partitioning no sustituye los índices. Reduce el volumen de datos a examinar, pero dentro de la partición sigues necesitando los índices correctos. Una partición mensual de 28 millones de filas sin índice sigue siendo un problema.\nCuándo necesitas partitioning #No todas las tablas necesitan partitioning. Mi regla empírica:\nBajo 10 millones de filas: probablemente no Entre 10 y 100 millones: depende del patrón de acceso y del ritmo de crecimiento Más de 100 millones: probablemente sí Más de mil millones: no tienes elección Pero el momento correcto para implementarlo es antes de que se vuelva urgente. Cuando la tabla ya tiene 2 mil millones de filas, la migración es un proyecto en sí mismo. Cuando tiene 50 millones y está creciendo, es trabajo de una tarde.\nMi mayor error con el partitioning? No haberlo propuesto seis meses antes, cuando todas las señales ya estaban ahí.\nGlosario #Partition Pruning — Mecanismo automático de Oracle que excluye las particiones no relevantes durante la ejecución de una query, leyendo solo las que contienen datos correspondientes al predicado.\nCTAS — Create Table As Select: técnica para crear una nueva tabla poblándola con un SELECT en una única operación. Fundamental para migrar tablas de miles de millones de filas al partitioning.\nLocal Index — Índice particionado con la misma clave que la tabla. Cada partición tiene su porción de índice, haciendo las operaciones DDL independientes entre particiones.\nNOLOGGING — Modo Oracle que suprime la generación de redo log durante operaciones masivas, reduciendo tiempos de días a horas. Requiere backup RMAN inmediato después del uso.\nTablespace — Unidad lógica de almacenamiento Oracle que agrupa datafiles físicos. En el partitioning, permite mover particiones antiguas a almacenamiento de archivo y gestionar el ciclo de vida de los datos.\n","date":"23 diciembre 2025","permalink":"https://ivanluminaria.com/es/posts/oracle/oracle-partitioning/","section":"Database Strategy","summary":"\u003cp\u003eDos mil millones de filas. No es un número que se alcance en un día. Se necesitan años de transacciones, movimientos, registros diarios que se acumulan. Y durante todo ese tiempo la base de datos funciona, las consultas responden, los reportes salen. Luego un día alguien abre un ticket: \u0026ldquo;el reporte mensual tarda cuatro horas.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eCuatro horas. Para un reporte que seis meses antes tardaba veinte minutos.\u003c/p\u003e\n\u003cp\u003eNo es un bug. No es un problema de red o de almacenamiento lento. Es la física de los datos: cuando una tabla crece más allá de cierto umbral, los enfoques que funcionaban dejan de funcionar. Y si no diseñaste la estructura para manejar ese crecimiento, la base de datos hace lo único que puede: leerlo todo.\u003c/p\u003e","title":"Oracle Partitioning: cuando 2 mil millones de filas ya no caben en una query"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/partitioning/","section":"Tags","summary":"","title":"Partitioning"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/architecture/","section":"Tags","summary":"","title":"Architecture"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/data-guard/","section":"Tags","summary":"","title":"Data-Guard"},{"content":"El cliente era una empresa mediana del sector asegurador. Trescientos empleados, un aplicativo de gestión interno sobre Oracle 19c, un solo servidor físico en la sala de máquinas de la planta baja. Sin réplica. Sin standby. Sin plan de disaster recovery.\nDurante cinco años todo había funcionado. Y cuando las cosas funcionan, nadie quiere gastar dinero protegiéndose de problemas que nunca han ocurrido.\nEl día en que todo se paró #Un miércoles de noviembre por la mañana, a las 8:47, el disco del grupo de datos principal sufrió un fallo físico. No un error lógico, no una corrupción recuperable. Un fallo hardware. La controladora RAID perdió dos discos simultáneamente — uno llevaba semanas degradado sin que nadie se diera cuenta, el otro cedió de golpe.\nLa base de datos se detuvo. Las pólizas no se emitían. Los siniestros no se tramitaban. El call center respondía a los clientes diciendo \u0026ldquo;problemas técnicos, llame más tarde.\u0026rdquo;\nRecibí la llamada a las 9:15. Cuando llegué a la sede, el administrador de sistemas ya estaba buscando discos compatibles. Los encontró a primera hora de la tarde. Entre la sustitución, la reconstrucción del RAID y la recuperación de la base de datos desde el backup de la noche anterior, el sistema volvió a estar operativo a las 15:20.\nSeis horas y media de parada total. Y la pérdida de todas las transacciones desde las 23:00 de la noche anterior hasta las 8:47 de la mañana — unas diez horas de datos, porque el backup era solo nocturno y los archived log no se copiaban a otra máquina.\nEsa noche el CEO envió un email a toda la empresa. Al día siguiente me llamó: \u0026ldquo;¿Qué tenemos que hacer para que esto no vuelva a pasar?\u0026rdquo;\nEl diseño #La respuesta era simple en concepto, menos en la ejecución: necesitaban una segunda base de datos, sincronizada en tiempo real, lista para asumir el rol del primario en caso de fallo.\nOracle Active Data Guard hace exactamente eso. Una base de datos primaria genera redo logs , y un standby los recibe y aplica continuamente. Si el primario muere, el standby se convierte en primario. Si todo va bien, el standby también se puede usar en modo solo lectura — para informes, para backups, para aligerar la carga.\nDiseñé una arquitectura de dos nodos:\nPrimario (oraprod1): el servidor existente, con los discos nuevos, en la sede principal Standby (oraprod2): un nuevo servidor idéntico, en el centro de datos del proveedor de hosting, a 12 km de distancia La distancia no era casual. Suficientemente lejos para sobrevivir a un evento localizado (incendio, inundación, corte de suministro prolongado), suficientemente cerca para permitir la réplica síncrona sin latencia perceptible.\nLa configuración #Preparación del primario #El primer paso fue verificar que el primario estuviera en modo ARCHIVELOG con FORCE LOGGING activo. Sin estos dos prerrequisitos, Data Guard no tiene nada que replicar.\n-- Verificar modo archivelog SELECT log_mode FROM v$database; -- Si es necesario, activar SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE ARCHIVELOG; ALTER DATABASE OPEN; -- Force logging: impide operaciones NOLOGGING ALTER DATABASE FORCE LOGGING; El FORCE LOGGING es fundamental. Sin él, cualquier operación con cláusula NOLOGGING — un CREATE TABLE AS SELECT, un ALTER INDEX REBUILD — no genera redo y crea huecos en la réplica. Lo he visto ocurrir tres veces en mi carrera. La tercera vez decidí que FORCE LOGGING se activa siempre, sin excepciones.\nStandby redo logs #En el primario creé los standby redo logs — grupos dedicados que se usarán cuando (y si) este servidor se convierta en standby tras un switchover.\n-- Standby redo logs: n+1 respecto a los redo logs online -- Si tienes 3 grupos online, creas 4 standby ALTER DATABASE ADD STANDBY LOGFILE GROUP 4 SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 5 SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 6 SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 7 SIZE 200M; La regla es n+1: si el primario tiene tres grupos de redo log, el standby necesita cuatro. No está documentada con total claridad, pero la aprendí por las malas — con tres grupos iguales, bajo carga pesada el standby puede quedarse bloqueado esperando un grupo libre.\nConfiguración de red #El tnsnames.ora en ambos nodos debe conocer tanto al primario como al standby. La configuración es simétrica:\nORAPROD1 = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = oraprod) ) ) ORAPROD2 = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.0.5.1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = oraprod) ) ) El listener.ora en el standby debe incluir una entrada estática para la base de datos, porque durante el restore el standby aún no está abierto y el listener no puede registrarlo dinámicamente:\nSID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = oraprod_DGMGRL) (ORACLE_HOME = /u01/app/oracle/product/19c) (SID_NAME = oraprod) ) ) El sufijo _DGMGRL lo usa el Data Guard Broker para identificar la instancia. Sin esta entrada estática, el broker no puede conectarse al standby y las operaciones de switchover fallan con errores crípticos que te hacen perder media jornada.\nCreación del standby #Para la copia inicial de la base de datos usé un DUPLICATE vía RMAN a través de la red. Sin backup en cinta, sin transferencia manual de archivos. Directo, del primario al standby:\n-- En el servidor standby, iniciar la instancia en NOMOUNT STARTUP NOMOUNT PFILE=\u0026#39;/u01/app/oracle/product/19c/dbs/initoraprod.ora\u0026#39;; -- Desde RMAN, conectado a ambos RMAN TARGET sys/password@ORAPROD1 AUXILIARY sys/password@ORAPROD2 DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE DORECOVER SPFILE SET db_unique_name=\u0026#39;oraprod_stby\u0026#39; SET log_archive_dest_2=\u0026#39;\u0026#39; SET fal_server=\u0026#39;ORAPROD1\u0026#39; NOFILENAMECHECK; El NOFILENAMECHECK se usa cuando las rutas de los archivos son idénticas en ambas máquinas — misma estructura de directorios, misma convención de nombres. Si las rutas difieren, se necesitan los parámetros DB_FILE_NAME_CONVERT y LOG_FILE_NAME_CONVERT.\nLa copia tardó unas tres horas para 400 GB a través de una línea dedicada de 1 Gbps. No la más rápida, pero es una operación que se hace una sola vez.\nData Guard Broker #El Broker es el componente que gestiona la configuración Data Guard de forma centralizada y permite el switchover con un solo comando. Sin el Broker puedes hacer todo a mano, pero no quieres hacerlo a mano cuando el primario acaba de caer y el CEO te llama cada cinco minutos.\n-- En el primario ALTER SYSTEM SET dg_broker_start=TRUE; -- En el standby ALTER SYSTEM SET dg_broker_start=TRUE; Luego, desde DGMGRL en el primario:\nDGMGRL\u0026gt; CREATE CONFIGURATION dg_config AS PRIMARY DATABASE IS oraprod CONNECT IDENTIFIER IS ORAPROD1; DGMGRL\u0026gt; ADD DATABASE oraprod_stby AS CONNECT IDENTIFIER IS ORAPROD2 MAINTAINED AS PHYSICAL; DGMGRL\u0026gt; ENABLE CONFIGURATION; En ese punto, SHOW CONFIGURATION debe devolver:\nConfiguration - dg_config Protection Mode: MaxPerformance Members: oraprod - Primary database oraprod_stby - Physical standby database Fast-Start Failover: DISABLED Configuration Status: SUCCESS La palabra que quieres ver es SUCCESS. Cualquier otra cosa significa que hay un problema de red, configuración o permisos que resolver antes de continuar.\nEl primer switchover #Dos semanas después de la puesta en producción de la arquitectura, hice la primera prueba de switchover. Un sábado por la mañana, con el aplicativo cerrado, pero con el CEO presente — quería verlo con sus propios ojos.\nDGMGRL\u0026gt; SWITCHOVER TO oraprod_stby; Un solo comando. Cuarenta y dos segundos. El primario se convirtió en standby, el standby se convirtió en primario. Las aplicaciones, configuradas con el servicio correcto, se reconectaron automáticamente.\nDGMGRL\u0026gt; SHOW CONFIGURATION; Configuration - dg_config Protection Mode: MaxPerformance Members: oraprod_stby - Primary database oraprod - Physical standby database Fast-Start Failover: DISABLED Configuration Status: SUCCESS Después hicimos el switchback — vuelta al primario original. Otros treinta y ocho segundos. Limpio.\nEl CEO miró la pantalla, me miró a mí, y dijo: \u0026ldquo;Cuarenta y dos segundos contra seis horas. ¿Por qué no lo hicimos antes?\u0026rdquo;\nNo le di la respuesta. La sabíamos los dos.\nLo que no te cuentan #La configuración que he descrito funciona. Pero hay cosas que la documentación de Oracle no enfatiza lo suficiente.\nEl gap de red. La réplica síncrona (SYNC) garantiza cero pérdida de datos pero introduce latencia en cada commit. Con 12 km y una buena fibra, la latencia añadida era de 1-2 milisegundos — aceptable. Pero a 100 km habría sido 5-8 ms, y en una aplicación con miles de commits por segundo, la ralentización se habría notado. Por eso elegí el modo MaxPerformance (asíncrono) como predeterminado, aceptando la posibilidad teórica de perder unos segundos de transacciones en caso de desastre total. Para ese cliente, perder cinco segundos de datos era infinitamente mejor que perder diez horas.\nEl password file. El archivo de contraseñas del usuario SYS debe ser idéntico en primario y standby. Si lo cambias en uno y no en el otro, el redo transport se detiene silenciosamente. Ningún error evidente, solo un gap que crece. Lo descubrí después de una hora de debugging un domingo por la noche.\nLos temp tablespace. El standby no replica los tablespaces temporales. Si abres el standby en lectura para informes (Active Data Guard), debes crear manualmente los temp tablespaces, de lo contrario las consultas con sort o hash join fallan con errores que no tienen nada que ver con el problema real.\n-- En el standby abierto en modo solo lectura ALTER TABLESPACE TEMP ADD TEMPFILE SIZE 2G AUTOEXTEND ON; Los parches. Primario y standby deben estar al mismo nivel de parches. Si aplicas una PSU al primario sin aplicarla al standby, el redo podría contener estructuras que el standby no sabe interpretar. El switchover funcionará, pero después podrías tener corrupciones silenciosas. El procedimiento correcto es: parchear el standby primero, switchover, parchear el antiguo primario (ahora standby), switchback.\nLos números #A seis meses de la implementación, el balance era claro:\nMétrica Antes Después RPO (Recovery Point Objective) ~10 horas (backup nocturno) \u0026lt; 5 segundos RTO (Recovery Time Objective) 6+ horas (restore desde backup) \u0026lt; 1 minuto (switchover) Disponibilidad de informes en paralelo No Sí (Active Data Guard) Coste de infraestructura adicional — 1 servidor + línea dedicada Pruebas de switchover realizadas 0 6 (una al mes) El coste total del proyecto — servidor, licencias, línea dedicada, implementación — era aproximadamente una cuarta parte de lo que había costado aquel único día de parada. No en términos técnicos. En términos de pólizas no emitidas, siniestros no tramitados, clientes no atendidos.\nLo que aprendí #El disaster recovery no es un problema técnico. Es un problema de percepción del riesgo. Mientras la base de datos funciona, el DR es un gasto. Cuando la base de datos se para, el DR es una inversión que se debería haber hecho seis meses antes.\nNo puedes convencer a un CEO con un diagrama arquitectónico. Solo puedes esperar a que ocurra el desastre y estar preparado con la solución. Es cínico, pero así funciona en el noventa por ciento de los casos.\nLo único que puedes hacer antes es documentar el riesgo, dejar por escrito que lo señalaste, y tener el proyecto listo en el cajón. Yo había propuesto ese proyecto dieciocho meses antes. Lo habían archivado con un \u0026ldquo;lo revisamos el año que viene.\u0026rdquo;\nEl año que viene llegó un miércoles de noviembre por la mañana, a las 8:47.\nGlosario #Data Guard — Tecnologia Oracle para la replica en tiempo real de una base de datos en uno o mas servidores standby. El standby recibe y aplica continuamente los redo logs del primario, permitiendo switchover en segundos.\nRedo Log — Archivos de log donde Oracle registra cada modificacion de datos antes de escribirla en los datafiles. Son la base de la recuperacion y la replica Data Guard: sin redo, ninguna de estas operaciones es posible.\nRPO — Recovery Point Objective. La cantidad maxima de datos que una organizacion puede permitirse perder en caso de desastre, medida en tiempo. Con Data Guard asincrono se reducen a pocos segundos.\nRTO — Recovery Time Objective. El tiempo maximo aceptable para restaurar el servicio tras un fallo. Con Data Guard y switchover automatico, se pasa de horas a menos de un minuto.\nRMAN — Recovery Manager. Herramienta nativa Oracle para backup, restore y recovery, incluyendo la creacion de bases de datos standby via DUPLICATE ... FOR STANDBY FROM ACTIVE DATABASE.\n","date":"16 diciembre 2025","permalink":"https://ivanluminaria.com/es/posts/oracle/oracle-data-guard/","section":"Database Strategy","summary":"\u003cp\u003eEl cliente era una empresa mediana del sector asegurador. Trescientos empleados, un aplicativo de gestión interno sobre Oracle 19c, un solo servidor físico en la sala de máquinas de la planta baja. Sin réplica. Sin standby. Sin plan de disaster recovery.\u003c/p\u003e\n\u003cp\u003eDurante cinco años todo había funcionado. Y cuando las cosas funcionan, nadie quiere gastar dinero protegiéndose de problemas que nunca han ocurrido.\u003c/p\u003e\n\u003ch2 id=\"el-día-en-que-todo-se-paró\" class=\"relative group\"\u003eEl día en que todo se paró \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#el-d%c3%ada-en-que-todo-se-par%c3%b3\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn miércoles de noviembre por la mañana, a las 8:47, el disco del grupo de datos principal sufrió un fallo físico. No un error lógico, no una corrupción recuperable. Un fallo hardware. La controladora RAID perdió dos discos simultáneamente — uno llevaba semanas degradado sin que nadie se diera cuenta, el otro cedió de golpe.\u003c/p\u003e","title":"De single instance a Data Guard: el día en que el CEO entendió el DR"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/disaster-recovery/","section":"Tags","summary":"","title":"Disaster-Recovery"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/switchover/","section":"Tags","summary":"","title":"Switchover"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/kimball/","section":"Tags","summary":"","title":"Kimball"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/scd/","section":"Tags","summary":"","title":"Scd"},{"content":"El director comercial se presenta en la reunión del lunes por la mañana con una pregunta sencilla: \u0026ldquo;¿Cuántos clientes teníamos en la región Norte en junio pasado?\u0026rdquo;\nRespuesta del DWH: silencio.\nNo porque el sistema estuviera caído, ni porque faltara la tabla. El dato estaba ahí, técnicamente. Pero era erróneo. El DWH devolvía los clientes que hoy están en la región Norte — no los que estaban en junio. Porque cada noche, el proceso de carga sobrescribía la tabla maestra de clientes con los valores actuales, borrando cualquier rastro de lo que había antes.\nUn cliente que en junio estaba en la región Norte y en septiembre se trasladó a la región Centro? Para el DWH, ese cliente siempre había estado en la región Centro. La historia no existía.\nEl proyecto y el modelo original #El contexto era un data warehouse en el sector asegurador — gestión de siniestros y cartera de clientes. El sistema fuente contenía un registro maestro por cada cliente: nombre, región, agente asignado, clase de riesgo, tipo de póliza.\nLa dimensión en el DWH estaba modelada así:\nCREATE TABLE dim_cliente ( cliente_id NUMBER(10) NOT NULL, nombre VARCHAR2(100) NOT NULL, region VARCHAR2(50) NOT NULL, agente VARCHAR2(100), clase_riesgo VARCHAR2(20), tipo_poliza VARCHAR2(50), CONSTRAINT pk_dim_cliente PRIMARY KEY (cliente_id) ); El ETL nocturno era un simple MERGE : si el cliente existe, actualiza todos los campos; si no existe, inserta.\nMERGE INTO dim_cliente d USING stg_cliente s ON (d.cliente_id = s.cliente_id) WHEN MATCHED THEN UPDATE SET d.nombre = s.nombre, d.region = s.region, d.agente = s.agente, d.clase_riesgo = s.clase_riesgo, d.tipo_poliza = s.tipo_poliza WHEN NOT MATCHED THEN INSERT ( cliente_id, nombre, region, agente, clase_riesgo, tipo_poliza ) VALUES ( s.cliente_id, s.nombre, s.region, s.agente, s.clase_riesgo, s.tipo_poliza ); Simple, limpio, rápido. Y completamente equivocado para un data warehouse.\nEsto es lo que Kimball llama SCD Tipo 1 — Slowly Changing Dimension de Tipo 1. Sobrescribes el valor antiguo con el nuevo. Sin historia, sin versionado. El valor actual borra el anterior.\nPara un sistema OLTP es perfecto: siempre quieres la dirección actual del cliente, el teléfono actualizado, el email válido. Pero un data warehouse no es un sistema transaccional. Un data warehouse es una máquina del tiempo. Y una máquina del tiempo que sobrescribe el pasado es inútil.\nLo que se pierde con el Tipo 1 #El director comercial no era el único que hacía preguntas que el DWH no podía responder. Aquí va una muestra de las solicitudes que se acumularon en tres meses:\n\u0026quot;¿Cuántos clientes pasaron de la clase de riesgo Alta a Baja en el último año?\u0026quot; — Imposible. La clase anterior ya no existe. \u0026quot;¿El agente Rossi ha perdido clientes respecto al trimestre pasado?\u0026quot; — Imposible. Si un cliente fue reasignado al agente Bianchi, no queda rastro de que alguna vez perteneció a Rossi. \u0026quot;¿La facturación de la región Sur bajó o los clientes se mudaron?\u0026quot; — Imposible de distinguir. Si un cliente de 200K se trasladó de la región Sur a la Centro, la facturación del Sur baja pero no porque el negocio vaya mal — simplemente el cliente cambió de dirección. Cada vez la respuesta era la misma: \u0026ldquo;El sistema no guarda historia.\u0026rdquo; Que traducido al lenguaje empresarial significa: \u0026ldquo;No lo sabemos.\u0026rdquo;\nEn un momento dado, el CFO pidió un informe de análisis trimestral comparando la composición de la cartera de clientes entre Q1 y Q2. El equipo de BI intentó construirlo. Tardaron tres días. El resultado no era fiable porque los datos de Q1 ya no existían — habían sido sobrescritos con los de Q2. El informe comparaba Q2 con Q2 disfrazado de Q1.\nEse fue el momento que desencadenó el proyecto de reestructuración.\nSCD Tipo 2: el principio #El Tipo 2 no sobrescribe. Versiona.\nCuando un atributo cambia, el registro actual se cierra — se le asigna una fecha de fin de validez — y se inserta un nuevo registro con los valores actualizados y una nueva fecha de inicio de validez. El registro antiguo permanece en la base de datos, intacto, con todos los valores que tenía cuando era el registro vigente.\nPara que esto funcione se necesitan tres elementos adicionales en la tabla dimensional:\nUna clave subrogada — un identificador generado por el DWH, distinto de la clave natural del sistema fuente. Es necesaria porque el mismo cliente tendrá múltiples registros (uno por cada versión), así que la clave natural ya no es única. Fechas de validez — valid_from y valid_to — que definen el intervalo temporal en que cada versión del registro era la vigente. Un flag de versión actual — is_current — que permite recuperar rápidamente la versión activa sin filtrar por fechas. La nueva tabla dimensional #CREATE TABLE dim_cliente ( cliente_key NUMBER(10) NOT NULL, cliente_id NUMBER(10) NOT NULL, nombre VARCHAR2(100) NOT NULL, region VARCHAR2(50) NOT NULL, agente VARCHAR2(100), clase_riesgo VARCHAR2(20), tipo_poliza VARCHAR2(50), valid_from DATE NOT NULL, valid_to DATE NOT NULL, is_current CHAR(1) DEFAULT \u0026#39;Y\u0026#39; NOT NULL, CONSTRAINT pk_dim_cliente PRIMARY KEY (cliente_key) ); CREATE INDEX idx_dim_cliente_natural ON dim_cliente (cliente_id, is_current); CREATE INDEX idx_dim_cliente_validity ON dim_cliente (cliente_id, valid_from, valid_to); CREATE SEQUENCE seq_dim_cliente START WITH 1 INCREMENT BY 1; La cliente_key es la clave subrogada — generada por la secuencia, nunca tomada del sistema fuente. La cliente_id es la clave natural — sirve para vincular las diferentes versiones del mismo cliente.\nLa valid_to para el registro actual la fijo en DATE '9999-12-31' — una convención estándar que simplifica las consultas temporales. Cuando buscas el registro válido en una fecha determinada, el filtro WHERE fecha_referencia BETWEEN valid_from AND valid_to funciona sin casos especiales.\nLa lógica ETL #El ETL del Tipo 2 tiene dos fases: primero cierra los registros que han cambiado, luego inserta las nuevas versiones. El orden importa — si insertas antes de cerrar, hay un momento en que existen dos versiones \u0026ldquo;actuales\u0026rdquo; del mismo cliente.\nFase 1: identificar y cerrar los registros modificados #MERGE INTO dim_cliente d USING ( SELECT s.cliente_id, s.nombre, s.region, s.agente, s.clase_riesgo, s.tipo_poliza FROM stg_cliente s JOIN dim_cliente d ON s.cliente_id = d.cliente_id AND d.is_current = \u0026#39;Y\u0026#39; WHERE (s.region != d.region OR s.agente != d.agente OR s.clase_riesgo != d.clase_riesgo OR s.tipo_poliza != d.tipo_poliza OR s.nombre != d.nombre) ) changed ON (d.cliente_id = changed.cliente_id AND d.is_current = \u0026#39;Y\u0026#39;) WHEN MATCHED THEN UPDATE SET d.valid_to = TRUNC(SYSDATE) - 1, d.is_current = \u0026#39;N\u0026#39;; El WHERE compara cada atributo rastreado. Si al menos uno es diferente, el registro actual se cierra: la valid_to se establece a ayer y is_current pasa a \u0026lsquo;N\u0026rsquo;.\nUna nota práctica: la comparación con != no gestiona los NULL. Si agente puede ser NULL, se necesitan funciones de comparación NULL-safe. En Oracle uso DECODE:\nWHERE DECODE(s.region, d.region, 0, 1) = 1 OR DECODE(s.agente, d.agente, 0, 1) = 1 OR DECODE(s.clase_riesgo, d.clase_riesgo, 0, 1) = 1 -- ... DECODE trata dos NULL como iguales — exactamente el comportamiento que necesitas.\nFase 2: insertar las nuevas versiones #INSERT INTO dim_cliente ( cliente_key, cliente_id, nombre, region, agente, clase_riesgo, tipo_poliza, valid_from, valid_to, is_current ) SELECT seq_dim_cliente.NEXTVAL, s.cliente_id, s.nombre, s.region, s.agente, s.clase_riesgo, s.tipo_poliza, TRUNC(SYSDATE), DATE \u0026#39;9999-12-31\u0026#39;, \u0026#39;Y\u0026#39; FROM stg_cliente s WHERE NOT EXISTS ( SELECT 1 FROM dim_cliente d WHERE d.cliente_id = s.cliente_id AND d.is_current = \u0026#39;Y\u0026#39; ); Este INSERT captura dos casos: clientes completamente nuevos (que no existen en dim_cliente) y clientes cuya versión actual acaba de ser cerrada en la Fase 1 (que por lo tanto ya no tienen un registro con is_current = 'Y').\nLa valid_from es la fecha de hoy. La valid_to es el \u0026ldquo;fin de los tiempos\u0026rdquo; — 9999-12-31. La cliente_key la genera la secuencia.\nLos datos: antes y después #Veamos un ejemplo concreto. El cliente 2001 — \u0026ldquo;Alfa Seguros Srl\u0026rdquo; — está en la región Norte, asignado al agente Rossi, clase de riesgo Media.\nEn julio el cliente es reasignado al agente Bianchi. En octubre cambia de clase de riesgo de Media a Alta.\nCon el Tipo 1 (el modelo anterior), en octubre dim_cliente contiene una sola fila:\nCLIENTE_ID NOMBRE REGION AGENTE CLASE_RIESGO ---------- ------------------- ------ ------- ------------ 2001 Alfa Seguros Srl Norte Bianchi Alta Ningún rastro de Rossi. Ningún rastro de la clase Media. Para el DWH, este cliente siempre ha pertenecido al agente Bianchi con clase Alta.\nCon el Tipo 2, en octubre dim_cliente contiene tres filas:\nKEY CLIENTE_ID NOMBRE REGION AGENTE CLASE VALID_FROM VALID_TO CURRENT ---- ---------- ------------------- ------ ------- ------ ---------- ---------- ------- 1001 2001 Alfa Seguros Srl Norte Rossi Media 2025-01-15 2025-07-09 N 1002 2001 Alfa Seguros Srl Norte Bianchi Media 2025-07-10 2025-10-04 N 1003 2001 Alfa Seguros Srl Norte Bianchi Alta 2025-10-05 9999-12-31 Y Tres versiones del mismo cliente. Cada versión cuenta un trozo de la historia: quién era el agente, cuál era la clase de riesgo, y en qué período. Las fechas no se solapan. El flag is_current identifica la versión activa.\nLas consultas temporales #Ahora el director comercial puede tener su respuesta.\n¿Cuántos clientes en la región Norte en junio? #SELECT COUNT(DISTINCT cliente_id) AS clientes_norte_junio FROM dim_cliente WHERE region = \u0026#39;Norte\u0026#39; AND DATE \u0026#39;2025-06-15\u0026#39; BETWEEN valid_from AND valid_to; La consulta es directa: toma todos los registros que eran válidos el 15 de junio de 2025 y filtra por región. Sin CASE WHEN, sin lógica condicional, sin aproximaciones.\nClientes que cambiaron de clase de riesgo en el último año #SELECT c1.cliente_id, c1.nombre, c1.clase_riesgo AS clase_anterior, c2.clase_riesgo AS clase_actual, c1.valid_to + 1 AS fecha_cambio FROM dim_cliente c1 JOIN dim_cliente c2 ON c1.cliente_id = c2.cliente_id AND c1.valid_to + 1 = c2.valid_from WHERE c1.clase_riesgo != c2.clase_riesgo AND c1.valid_to \u0026gt;= ADD_MONTHS(TRUNC(SYSDATE), -12) ORDER BY fecha_cambio DESC; Dos versiones consecutivas del mismo cliente, unidas por fecha de transición. Si la clase de riesgo difiere entre las dos versiones, el cliente ha cambiado de clase. La fecha de cambio es el día posterior al cierre de la versión anterior.\nComparación de cartera Q1 vs Q2 #SELECT region, COUNT(DISTINCT CASE WHEN DATE \u0026#39;2025-03-31\u0026#39; BETWEEN valid_from AND valid_to THEN cliente_id END) AS clientes_q1, COUNT(DISTINCT CASE WHEN DATE \u0026#39;2025-06-30\u0026#39; BETWEEN valid_from AND valid_to THEN cliente_id END) AS clientes_q2 FROM dim_cliente WHERE DATE \u0026#39;2025-03-31\u0026#39; BETWEEN valid_from AND valid_to OR DATE \u0026#39;2025-06-30\u0026#39; BETWEEN valid_from AND valid_to GROUP BY region ORDER BY region; Un solo scan de la tabla, dos conteos distintos filtrados por fecha. El CFO tiene su informe trimestral — el real, no el que comparaba Q2 consigo mismo.\nLa tabla de hechos y las claves subrogadas #Un punto que a menudo se subestima: la tabla de hechos debe usar la clave subrogada, no la clave natural.\nCREATE TABLE fact_siniestro ( siniestro_key NUMBER(10) NOT NULL, cliente_key NUMBER(10) NOT NULL, -- FK a la versión específica fecha_key NUMBER(8) NOT NULL, importe NUMBER(15,2), tipo_siniestro VARCHAR2(50), CONSTRAINT pk_fact_siniestro PRIMARY KEY (siniestro_key), CONSTRAINT fk_fact_cliente FOREIGN KEY (cliente_key) REFERENCES dim_cliente (cliente_key) ); La cliente_key en la tabla de hechos apunta a la versión del cliente que era vigente en el momento del siniestro. Si un siniestro ocurre en mayo, cuando el cliente todavía pertenecía al agente Rossi, el hecho apunta a la versión con agente Rossi. Si otro siniestro ocurre en septiembre, con el cliente ya bajo el agente Bianchi, el hecho apunta a la versión con agente Bianchi.\nEl resultado es que cada hecho está asociado al contexto dimensional correcto para el momento en que ocurrió. Consultas los siniestros de mayo y ves al agente Rossi. Consultas los de septiembre y ves al agente Bianchi. Sin ninguna lógica temporal en la consulta — el JOIN directo entre tabla de hechos y dimensión devuelve el contexto correcto.\n-- Siniestros por agente, con el contexto correcto en el momento del siniestro SELECT d.agente, COUNT(*) AS num_siniestros, SUM(f.importe) AS importe_total FROM fact_siniestro f JOIN dim_cliente d ON f.cliente_key = d.cliente_key GROUP BY d.agente ORDER BY importe_total DESC; Sin cláusula temporal. El JOIN por clave subrogada hace todo el trabajo.\nLas dimensiones del Tipo 2 #El coste del Tipo 2 es el crecimiento de la tabla dimensional. Con el Tipo 1, cada cliente es una fila. Con el Tipo 2, cada cliente puede tener N filas — una por cada cambio de atributo rastreado.\nEn el proyecto asegurador los números eran estos:\nMétrica Valor Clientes activos ~120.000 Atributos rastreados 4 (región, agente, clase riesgo, tipo póliza) Tasa de cambio media ~8% de clientes/año Filas dim_cliente tras 1 año ~140.000 Filas dim_cliente tras 3 años ~180.000 Filas dim_cliente tras 5 años ~220.000 De 120K a 220K en cinco años. Un aumento del 83% — que parece mucho en porcentaje pero es despreciable en términos absolutos. 220K filas son nada para Oracle. La consulta con índice sobre la clave subrogada se mantiene en el orden de los milisegundos.\nEl problema se presenta cuando tienes millones de clientes con altas tasas de cambio. En ese caso monitorizas el crecimiento, consideras el particionamiento de la dimensión, y sobre todo eliges con cuidado qué atributos rastrear. No todos los atributos merecen Tipo 2. ¿El teléfono del cliente? Tipo 1, sobrescritura. ¿La región comercial? Tipo 2, porque impacta en el análisis de facturación.\nLa elección de qué atributos rastrear con Tipo 2 es una decisión de negocio, no técnica. Pregunta al negocio: \u0026ldquo;Si este campo cambia, ¿necesitáis saber cuál era el valor anterior?\u0026rdquo; Si la respuesta es sí, es Tipo 2. Si es no, es Tipo 1.\nCuándo no hace falta el Tipo 2 #No todas las dimensiones necesitan historia. He visto proyectos donde cada dimensión era Tipo 2 \u0026ldquo;por si acaso\u0026rdquo; — el resultado era un modelo innecesariamente complejo, ETL lentos, y nadie que jamás consultara la historia de la dimensión \u0026ldquo;tipo_pago\u0026rdquo; o \u0026ldquo;canal_venta\u0026rdquo;.\nEl Tipo 2 tiene un coste: complejidad del ETL, crecimiento de la tabla, necesidad de gestionar claves subrogadas en la tabla de hechos. Es un coste que vale la pena pagar cuando el negocio necesita la historia. Si no la necesita, el Tipo 1 es la elección correcta.\nTambién hay casos en que el Tipo 2 no es suficiente. Si necesitas saber no solo qué cambió sino también quién hizo el cambio y por qué, entonces necesitas un audit trail — una tabla separada con un log completo de modificaciones. El Tipo 2 rastrea versiones, no causas.\nY para dimensiones con cambios muy frecuentes — precios que cambian cada día, puntuaciones que se actualizan cada hora — el Tipo 2 puede generar un crecimiento insostenible. En esos casos se valora el Tipo 6 (una combinación de Tipos 1, 2 y 3) o enfoques de mini-dimensión.\nPero para el caso más común — datos maestros de clientes, productos, empleados, puntos de venta — el Tipo 2 es la herramienta adecuada. Lo suficientemente simple para implementarse sin frameworks exóticos, lo suficientemente potente para devolver al negocio la dimensión que le faltaba: el tiempo.\nLo que aprendí #El director comercial no sabía que necesitaba la historia hasta que la necesitó. Y cuando la necesitó, el DWH no la tenía.\nEse es el punto. No se implementa el Tipo 2 porque \u0026ldquo;es best practice\u0026rdquo; o porque \u0026ldquo;Kimball lo dice en el capítulo 5\u0026rdquo;. Se implementa porque un data warehouse sin historia es una base de datos operativa con un star schema pegado encima. Funciona para los informes del mes actual, pero no responde a la pregunta que tarde o temprano alguien hará: \u0026ldquo;¿Cómo era antes?\u0026rdquo;\nLa pregunta siempre llega. La cuestión es si tu DWH está preparado para responder.\nGlosario #Clave subrogada — Identificador numérico generado por el data warehouse, distinto de la clave natural del sistema fuente. En la SCD Tipo 2 es imprescindible porque el mismo registro puede tener múltiples versiones, y la clave natural ya no es única.\nFact table — Tabla central del star schema que contiene las medidas numéricas (importes, cantidades, conteos) y las claves foráneas hacia las tablas dimensionales. Cada fila representa un evento o una transacción de negocio.\nKimball — Ralph Kimball, autor de la metodología de diseño de data warehouse basada en dimensional modeling, star schemas y procesos ETL bottom-up. Su framework clasifica las Slowly Changing Dimensions en los tipos del 0 al 7.\nMERGE — Instrucción SQL que combina INSERT y UPDATE en una sola operación: si el registro existe lo actualiza, si no existe lo inserta. En Oracle también se conoce como \u0026ldquo;upsert\u0026rdquo; y es el mecanismo base del ETL para las dimensiones SCD.\nStar schema — Modelo de datos típico del data warehouse: una fact table en el centro conectada a múltiples tablas dimensionales mediante claves foráneas. Simplifica las consultas analíticas y optimiza el rendimiento de las agregaciones.\n","date":"11 noviembre 2025","permalink":"https://ivanluminaria.com/es/posts/data-warehouse/scd-tipo-2/","section":"Database Strategy","summary":"\u003cp\u003eEl director comercial se presenta en la reunión del lunes por la mañana con una pregunta sencilla: \u0026ldquo;¿Cuántos clientes teníamos en la región Norte en junio pasado?\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eRespuesta del DWH: silencio.\u003c/p\u003e\n\u003cp\u003eNo porque el sistema estuviera caído, ni porque faltara la tabla. El dato estaba ahí, técnicamente. Pero era erróneo. El DWH devolvía los clientes que \u003cem\u003ehoy\u003c/em\u003e están en la región Norte — no los que estaban en junio. Porque cada noche, el proceso de carga sobrescribía la tabla maestra de clientes con los valores actuales, borrando cualquier rastro de lo que había antes.\u003c/p\u003e","title":"SCD Tipo 2: la historia que el negocio no sabía que necesitaba"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/csv-export/","section":"Tags","summary":"","title":"Csv-Export"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/multi-instance/","section":"Tags","summary":"","title":"Multi-Instance"},{"content":"El ticket decía: \u0026ldquo;Necesitamos un export CSV de la tabla de pedidos del gestional. Antes de las 14:00.\u0026rdquo;\nEran las 11. Tres horas para un SELECT con INTO OUTFILE — cosa de cinco minutos, pensé. Después abrí la VPN, me conecté al servidor y entendí que cinco minutos no iban a alcanzar.\nEl servidor era una máquina CentOS 7 con cuatro instancias MySQL. Cuatro. En el mismo host, con cuatro servicios systemd distintos, cuatro puertos distintos, cuatro sockets Unix distintos, cuatro directorios de datos distintos. Un setup que alguien había montado años atrás — probablemente para ahorrarse un segundo servidor — y que desde entonces nadie había tocado ni documentado.\nEl primer problema no era la query. El primer problema era: ¿a cuál de las cuatro instancias tengo que conectarme?\nEl entorno: cuatro MySQL, un solo servidor #Los entornos multi-instancia en MySQL no son tan raros como se podría pensar. Los encuentro con más frecuencia de la que quisiera, sobre todo en empresas medianas y pequeñas donde los servidores son pocos y las aplicaciones son muchas. La lógica es simple: en vez de comprar cuatro servidores, compras uno potente y haces correr cuatro instancias MySQL, cada una con su base de datos, su puerto, su archivo de configuración.\nEl resultado funciona, hasta que necesitas hacer mantenimiento. Y el mantenimiento en un multi-instancia, sin documentación, es un ejercicio de arqueología informática.\nEn ese servidor, la situación era esta:\nsystemctl list-units --type=service | grep mysql mysqld.service loaded active running MySQL Server (porta 3306) mysqld-app2.service loaded active running MySQL Server (porta 3307) mysqld-reporting.service loaded active running MySQL Server (porta 3308) mysqld-legacy.service loaded active running MySQL Server (porta 3309) Cuatro servicios. Los nombres eran vagamente indicativos — \u0026ldquo;app2\u0026rdquo;, \u0026ldquo;reporting\u0026rdquo;, \u0026ldquo;legacy\u0026rdquo; — pero el ticket hablaba del \u0026ldquo;gestional\u0026rdquo; sin especificar qué instancia alojaba esa base de datos. Ninguna wiki interna, ningún README en el servidor, ningún comentario en los archivos de configuración.\nEncontrar la instancia correcta #El primer paso fue entender qué instancia contenía la base de datos de pedidos. La técnica es siempre la misma: partes del servicio systemd, subes al archivo de configuración, de ahí lees puerto y socket.\nsystemctl cat mysqld-app2.service | grep ExecStart ExecStart=/usr/sbin/mysqld --defaults-file=/etc/mysql/app2.cnf Cada servicio apuntaba a un my.cnf diferente. Revisé los cuatro:\ngrep -E \u0026#34;^(port|socket|datadir)\u0026#34; /etc/mysql/app2.cnf port = 3307 socket = /var/run/mysqld/mysqld-app2.sock datadir = /data/mysql-app2 Para cada instancia, anoté puerto, socket y datadir. Después hice la ronda rápida:\nmysql --socket=/var/run/mysqld/mysqld.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null mysql --socket=/var/run/mysqld/mysqld-app2.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null mysql --socket=/var/run/mysqld/mysqld-reporting.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null mysql --socket=/var/run/mysqld/mysqld-legacy.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null La base de datos gestionale_prod estaba en la segunda instancia — la del puerto 3307 con socket /var/run/mysqld/mysqld-app2.sock.\nUn detalle que parece trivial pero que en un entorno multi-instancia marca la diferencia: cuando te conectas a MySQL especificando solo -h localhost, el cliente no usa TCP. Usa el socket Unix por defecto, que casi siempre es el de la instancia primaria en el puerto 3306. Si la base de datos que buscas está en otra instancia, te conectas a la equivocada sin siquiera darte cuenta.\nLa conexión y la verificación #Una vez identificada la instancia, me conecté especificando explícitamente el socket:\nmysql --socket=/var/run/mysqld/mysqld-app2.sock -u root -p Primera cosa después del login: verificar que estaba en la instancia correcta.\nSHOW VARIABLES LIKE \u0026#39;port\u0026#39;; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | port | 3307 | +---------------+-------+ SELECT DATABASE(); USE gestionale_prod; SHOW TABLES LIKE \u0026#39;%ordini%\u0026#39;; +----------------------------------+ | Tables_in_gestionale_prod | +----------------------------------+ | ordini | | ordini_dettaglio | | ordini_storico | +----------------------------------+ Puerto 3307, base de datos presente, tabla de pedidos en su lugar. La conexión era la correcta.\nEl check del puerto parece paranoia, pero no lo es. En un entorno con cuatro instancias, confundir qué socket apunta a qué puerto es más fácil de lo que parece. Y el error lo descubres solo cuando los datos que exportas no son los que esperabas — o peor, cuando haces una modificación pensando que estás en la base de datos de pruebas y descubres que estabas en producción.\nEl primer intento: INTO OUTFILE #La query era sencilla. El solicitante quería los pedidos del último trimestre con importe, cliente y fecha:\nSELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine; El primer instinto fue usar `INTO OUTFILE` , la manera nativa de MySQL para escribir resultados en archivo:\nSELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine INTO OUTFILE \u0026#39;/tmp/export_ordini.csv\u0026#39; FIELDS TERMINATED BY \u0026#39;,\u0026#39; ENCLOSED BY \u0026#39;\u0026#34;\u0026#39; LINES TERMINATED BY \u0026#39;\\n\u0026#39;; La respuesta de MySQL fue seca:\nERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement Ahí estaba el muro.\nsecure-file-priv : la directiva que bloquea todo (y hace bien) #La variable secure_file_priv es la forma en que MySQL limita las operaciones de lectura y escritura sobre archivos. Controla dónde LOAD DATA INFILE, SELECT INTO OUTFILE y la función LOAD_FILE() pueden operar.\nSHOW VARIABLES LIKE \u0026#39;secure_file_priv\u0026#39;; +------------------+------------------------+ | Variable_name | Value | +------------------+------------------------+ | secure_file_priv | /var/lib/mysql-files/ | +------------------+------------------------+ Esta variable tiene tres modalidades:\nUna ruta específica (ej. /var/lib/mysql-files/): las operaciones sobre archivos funcionan, pero solo dentro de ese directorio Cadena vacía (\u0026quot;\u0026quot;): sin restricciones — MySQL puede leer y escribir donde sea que su usuario de sistema tenga permisos NULL: las operaciones sobre archivos están completamente deshabilitadas Mi instancia estaba configurada con una ruta específica. El intento de escribir en /tmp/ fue bloqueado porque /tmp/ no es /var/lib/mysql-files/.\nLa primera reacción — la que veo hacer a muchos — habría sido: \u0026ldquo;cambiamos secure-file-priv a cadena vacía en el my.cnf y reiniciamos\u0026rdquo;. No. Absolutamente no. En un servidor de producción con cuatro instancias MySQL, reiniciar una instancia a las 11:30 de la mañana por un export CSV no es una opción. Y deshabilitar una protección de seguridad nunca es la respuesta correcta, ni siquiera en emergencia.\nLa alternativa obvia era escribir el archivo en el directorio autorizado:\nSELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine INTO OUTFILE \u0026#39;/var/lib/mysql-files/export_ordini.csv\u0026#39; FIELDS TERMINATED BY \u0026#39;,\u0026#39; ENCLOSED BY \u0026#39;\u0026#34;\u0026#39; LINES TERMINATED BY \u0026#39;\\n\u0026#39;; Pero había otro problema. El directorio /var/lib/mysql-files/ era el de la instancia primaria (puerto 3306). La instancia en el puerto 3307 tenía su datadir separado en /data/mysql-app2/, y su secure_file_priv apuntaba a /data/mysql-app2/files/ — un directorio que no existía y que nadie había creado jamás.\nPodría haber creado el directorio, asignado los permisos correctos al usuario mysql y escrito ahí. Pero a esas alturas ya estaba perdiendo tiempo. Y hay una forma más limpia.\nLa solución: export desde shell con el cliente mysql #Cuando INTO OUTFILE está bloqueado o resulta incómodo, la solución más práctica es saltarse completamente el mecanismo de escritura de archivos de MySQL y usar el cliente desde línea de comandos para redirigir la salida.\nEl truco está en las opciones -B (batch mode) y -e (execute):\nmysql --socket=/var/run/mysqld/mysqld-app2.sock \\ -u root -p \\ -B -e \u0026#34; SELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine \u0026#34; gestionale_prod \u0026gt; /tmp/export_ordini.tsv La opción -B produce una salida separada por tabulaciones sin los bordes ASCII de las tablas. El resultado es un archivo TSV limpio que se abre sin problemas en cualquier hoja de cálculo.\nSi necesitas un verdadero CSV con comas como separador, basta un paso con sed:\nmysql --socket=/var/run/mysqld/mysqld-app2.sock \\ -u root -p \\ -B -N -e \u0026#34; SELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine \u0026#34; gestionale_prod | sed \u0026#39;s/\\t/,/g\u0026#39; \u0026gt; /tmp/export_ordini.csv La opción -N elimina la fila de encabezado con los nombres de las columnas. Si la quieres, quita el flag.\nEl archivo estaba listo en menos de un minuto. 12.400 filas, 1,2 MB. Lo copié a mi máquina con scp, verifiqué que abriera bien en LibreOffice Calc y lo envié al solicitante. Eran las 11:45. El ticket que debía durar cinco minutos había requerido cuarenta y cinco — pero al menos no había reiniciado ninguna instancia.\nPor qué no deshabilitar secure-file-priv #La tentación de configurar secure_file_priv = \u0026quot;\u0026quot; es fuerte, sobre todo en servidores de desarrollo o en máquinas donde \u0026ldquo;total, solo somos nosotros\u0026rdquo;. El problema es que esa protección existe por una razón concreta.\nSin secure_file_priv, un usuario MySQL con el privilegio FILE puede:\nLeer cualquier archivo legible por el usuario de sistema mysql — incluyendo /etc/passwd, archivos de configuración, llaves SSH si los permisos no están blindados Escribir archivos donde sea que el usuario mysql tenga permisos de escritura — incluyendo el webroot de un eventual Apache o Nginx en el mismo servidor En un contexto de SQL injection , el privilegio FILE combinado con un secure_file_priv vacío es una puerta abierta. El atacante puede leer archivos del sistema, escribir web shells, hacer escalación de privilegios. No es teoría — es uno de los vectores de ataque más documentados en penetration tests sobre aplicaciones web con MySQL detrás.\nLa regla es simple: secure_file_priv se configura con una ruta específica, se crean los directorios necesarios para cada instancia al momento del setup, y se dejan ahí. Si necesitas hacer exports ocasionales, el cliente mysql desde shell hace el mismo trabajo sin tocar la configuración de seguridad.\nLecciones de un ticket de cinco minutos #Ese ticket me recordó tres cosas que en treinta años de trabajo con bases de datos he visto confirmadas cientos de veces.\nLa primera: en un entorno multi-instancia, el primer paso es siempre identificar la instancia. Parece obvio, pero la cantidad de errores que nacen de conectarse a la instancia equivocada — pensando que estás en otra — es impresionante. Un SHOW VARIABLES LIKE 'port' después de cada conexión no es paranoia, es higiene operativa.\nLa segunda: secure-file-priv no es un obstáculo, es una protección. Cuando te bloquea, no es el momento de deshabilitarla. Es el momento de usar una ruta alternativa o un método alternativo. La directiva existe porque MySQL en manos de un usuario con el privilegio FILE y sin restricciones sobre el filesystem es un riesgo concreto.\nLa tercera: el cliente mysql desde línea de comandos es más poderoso de lo que la mayoría de los DBA le reconocen. Con -B, -N, -e y un pipe hacia sed o awk, puedes hacer exports, transformaciones y automatizaciones sin tocar jamás INTO OUTFILE. Es menos elegante, quizás. Pero funciona siempre, no requiere permisos especiales y no necesita que alguien haya creado el directorio correcto seis meses antes.\nEl CSV llegó a las 11:45. El solicitante nunca supo que detrás de cinco columnas y 12.400 filas había cuarenta y cinco minutos de arqueología de sistemas. Pero así funcionan los tickets: quien los abre ve el resultado, quien los resuelve ve el camino.\nGlosario #secure-file-priv — Directiva de seguridad MySQL que limita los directorios donde el servidor puede leer y escribir archivos mediante INTO OUTFILE, LOAD DATA INFILE y LOAD_FILE().\nUnix Socket — Mecanismo de comunicación local entre procesos en sistemas Linux, usado por MySQL como método de conexión predeterminado al conectarse a localhost.\nINTO OUTFILE — Cláusula SQL de MySQL para exportar resultados de queries directamente a un archivo en el filesystem del servidor. Sujeta a las restricciones de secure-file-priv.\nsystemd — Gestor de servicios en Linux moderno, usado para gestionar múltiples instancias MySQL en el mismo servidor mediante unit files separados.\nSQL Injection — Técnica de ataque que inserta código SQL malicioso en los inputs de una aplicación. La directiva secure-file-priv contribuye a mitigar su impacto.\n","date":"4 noviembre 2025","permalink":"https://ivanluminaria.com/es/posts/mysql/mysql-multi-istanza-secure-file-priv/","section":"Database Strategy","summary":"\u003cp\u003eEl ticket decía: \u0026ldquo;Necesitamos un export CSV de la tabla de pedidos del gestional. Antes de las 14:00.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eEran las 11. Tres horas para un SELECT con INTO OUTFILE — cosa de cinco minutos, pensé. Después abrí la VPN, me conecté al servidor y entendí que cinco minutos no iban a alcanzar.\u003c/p\u003e\n\u003cp\u003eEl servidor era una máquina CentOS 7 con cuatro instancias MySQL. Cuatro. En el mismo host, con cuatro servicios \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Sistema de inicio y gestor de servicios en Linux, usado para gestionar múltiples instancias MySQL/MariaDB en el mismo servidor mediante unit files separados.\" data-glossary-url=\"/es/glossary/systemd/\" data-glossary-more=\"Leer más →\"\u003esystemd\u003c/span\u003e\n distintos, cuatro puertos distintos, cuatro sockets Unix distintos, cuatro directorios de datos distintos. Un setup que alguien había montado años atrás — probablemente para ahorrarse un segundo servidor — y que desde entonces nadie había tocado ni documentado.\u003c/p\u003e","title":"MySQL multi-instancia: un ticket, un CSV y el muro de secure-file-priv"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/secure-file-priv/","section":"Tags","summary":"","title":"Secure-File-Priv"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/socket/","section":"Tags","summary":"","title":"Socket"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/systemd/","section":"Tags","summary":"","title":"Systemd"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/troubleshooting/","section":"Tags","summary":"","title":"Troubleshooting"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/explain/","section":"Tags","summary":"","title":"Explain"},{"content":"El otro dia un colega me manda una captura de pantalla por Teams. Una query corriendo sobre una tabla de 2 millones de filas, 45 segundos de ejecucion. Me escribe:\n\u0026ldquo;Hice EXPLAIN ANALYZE, pero no entiendo que esta mal. El plan parece correcto.\u0026rdquo;\nSpoiler: el plan no era correcto en absoluto. El optimizer habia elegido un nested loop join donde hacia falta un hash join , y la razon era trivial — estadisticas desactualizadas. Pero para llegar a eso tuve que leer el plan linea por linea, y ahi me di cuenta de que la mayoria de los DBA que conozco usan EXPLAIN ANALYZE como un oraculo binario: si el tiempo es alto, la query es lenta. Fin del analisis.\nNo. EXPLAIN ANALYZE es una herramienta de diagnostico, no un veredicto. Hay que saber leerlo.\n🔧 EXPLAIN, EXPLAIN ANALYZE, EXPLAIN (ANALYZE, BUFFERS): tres cosas distintas #Empecemos por lo basico, porque la confusion esta mas extendida de lo que parece.\nEXPLAIN solo muestra el plan estimado. El optimizer decide que haria, pero no ejecuta nada. Util para entender la estrategia, inutil para entender la realidad.\nEXPLAIN SELECT * FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.created_at \u0026gt; \u0026#39;2025-01-01\u0026#39;; EXPLAIN ANALYZE ejecuta la query y agrega los tiempos reales. Ahora ves cuanto tardo cada nodo, cuantas filas devolvio realmente. Pero falta una pieza.\nEXPLAIN ANALYZE SELECT * FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.created_at \u0026gt; \u0026#39;2025-01-01\u0026#39;; EXPLAIN (ANALYZE, BUFFERS) es lo que uso siempre. Agrega la informacion sobre cuantas paginas de disco se leyeron, cuantas estaban en cache (shared hit) y cuantas hubo que cargar desde disco (shared read). Sin BUFFERS estas manejando de noche sin luces.\nEXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.created_at \u0026gt; \u0026#39;2025-01-01\u0026#39;; Regla personal: si alguien me manda un EXPLAIN sin BUFFERS, se lo devuelvo.\n📖 Anatomia de un nodo: que leer y en que orden #Un plan de ejecucion es un arbol. Cada nodo tiene esta estructura:\n-\u0026gt; Hash Join (cost=1234.56..5678.90 rows=50000 width=120) (actual time=12.345..89.012 rows=48750 loops=1) Buffers: shared hit=1200 read=3400 Esto es lo que hay que mirar:\ncost — son dos numeros separados por ... El primero es el costo de startup (cuanto antes de devolver la primera fila), el segundo es el costo total estimado. Son unidades arbitrarias del optimizer, no milisegundos. Sirven para comparar planes alternativos, no para medir rendimiento absoluto.\nrows — las filas estimadas por el optimizer. Comparalas con actual rows. Si hay un orden de magnitud de diferencia, encontraste el problema.\nactual time — tiempo real en milisegundos. Tambien dos valores: startup y total. Atencion al campo loops: si loops=10, el tiempo total se multiplica por 10.\nBuffers — shared hit son las paginas encontradas en memoria, shared read las leidas desde disco. Si read domina, tu working set no cabe en RAM.\n🚨 La senal de alarma numero uno: filas estimadas vs filas reales #Vuelvo al caso de mi colega. El plan mostraba:\n-\u0026gt; Nested Loop (cost=0.87..45678.12 rows=150 width=200) (actual time=0.034..44890.123 rows=1950000 loops=1) El optimizer estimaba 150 filas. En realidad llegaron casi 2 millones.\nCuando la estimacion falla por 4 ordenes de magnitud, el plan esta inevitablemente mal. El optimizer eligio un nested loop porque pensaba iterar sobre 150 filas. Un nested loop sobre 150 filas es rapidisimo. Sobre 2 millones es un desastre.\nUn hash join o merge join habrian sido la eleccion correcta. Pero el optimizer no podia saberlo con las estadisticas que tenia.\nRegla practica: si la relacion entre filas estimadas y reales supera 10x, tienes un problema de estadisticas. Por encima de 100x, el plan esta casi seguramente mal.\n🔍 Por que las estadisticas mienten #PostgreSQL mantiene estadisticas sobre las tablas en pg_statistic (legibles a traves de pg_stats). Estas estadisticas incluyen:\ndistribucion de valores (most common values) histograma de valores numero de valores distintos porcentaje de NULL El optimizer usa esta informacion para estimar la selectividad de cada condicion WHERE y la cardinalidad de cada join.\nEl problema? Las estadisticas se actualizan con `ANALYZE` — que puede ser manual o gestionado por autovacuum. Pero el autovacuum lanza ANALYZE solo cuando el numero de filas modificadas supera un umbral:\nthreshold = autovacuum_analyze_threshold + autovacuum_analyze_scale_factor × n_live_tuples Por defecto: 50 filas + 10% de las filas vivas. En una tabla de 2 millones de filas, se necesitan 200.000 modificaciones antes de que se dispare el ANALYZE automatico.\nEn el caso de mi colega, la tabla orders habia crecido de 500.000 a 2 millones de filas en tres semanas — una importacion masiva desde un sistema legacy. El autovacuum no habia actualizado las estadisticas porque el 10% de 500.000 (el tamano conocido) era 50.000, y las filas habian sido insertadas en lotes que individualmente no superaban el umbral.\nResultado: el optimizer seguia razonando como si la tabla tuviera 500.000 filas con la vieja distribucion de valores.\n🛠️ Actualizar estadisticas: lo primero que hacer #La solucion inmediata era obvia:\nANALYZE orders; Despues del ANALYZE, volvi a lanzar la query con EXPLAIN (ANALYZE, BUFFERS):\n-\u0026gt; Hash Join (cost=8500.00..32000.00 rows=1940000 width=200) (actual time=120.000..2800.000 rows=1950000 loops=1) Buffers: shared hit=28000 read=4500 De 45 segundos a menos de 3 segundos. El optimizer habia elegido un hash join, la estimacion de filas era correcta, y el plan era completamente distinto.\nPero no me quede ahi. Si el problema se presento una vez, se va a presentar de nuevo.\n📊 default_statistics_target: cuando 100 no alcanza #PostgreSQL recopila 100 valores de muestra por columna por defecto. Para tablas pequenas o con distribucion uniforme, es suficiente. Para tablas grandes con distribucion no uniforme, 100 muestras pueden dar una representacion distorsionada.\nEn el caso de la tabla orders, la columna customer_id tenia una distribucion muy sesgada: el 5% de los clientes generaba el 60% de los pedidos. Con 100 muestras, el optimizer no captaba esta asimetria.\nLa solucion:\nALTER TABLE orders ALTER COLUMN customer_id SET STATISTICS 500; ANALYZE orders; Despues de subir el target a 500, las estimaciones de cardinalidad del optimizer para los joins con customers se volvieron mucho mas precisas.\nRegla: si una columna se usa frecuentemente en WHERE o JOIN y tiene distribucion no uniforme, sube el target. 500 es un buen punto de partida. Puedes llegar a 1000, pero mas alla raramente ayuda y ralentiza el ANALYZE mismo.\n⚠️ Cuando forzar el planner: enable_nestloop y enable_hashjoin #A veces, incluso con estadisticas actualizadas, el optimizer toma un camino equivocado. Pasa con queries complejas, muchas tablas en join, o cuando la correlacion entre columnas engana las estimaciones.\nPostgreSQL ofrece parametros para deshabilitar estrategias especificas:\nSET enable_nestloop = off; Esto fuerza al optimizer a no usar nested loop. No es una solucion, es un parche diagnostico. Si deshabilitas el nested loop y la query pasa de 45 segundos a 3 segundos, confirmaste que el problema era la eleccion del join. Pero no puedes dejar enable_nestloop = off en produccion porque hay mil queries donde el nested loop es la eleccion correcta.\nUso estos parametros solo en dos escenarios:\nDiagnostico: para confirmar cual estrategia de join es el problema Emergencia: cuando el negocio esta parado y necesitas que una query critica vuelva a funcionar mientras buscas la solucion real Despues del diagnostico, el fix correcto siempre es sobre estadisticas, indices o reescritura de la query.\n📋 Mi workflow cuando una query es lenta #Despues de treinta anos haciendo este trabajo, mi proceso se ha vuelto casi mecanico:\n1. EXPLAIN (ANALYZE, BUFFERS) — siempre con BUFFERS. Guardo el output completo, no solo las ultimas lineas.\n2. Busco la discrepancia de filas — comparo rows= estimado con actual rows= real en cada nodo. Empiezo por los nodos hoja y subo hacia la raiz. La primera discrepancia significativa es casi siempre la causa.\n3. Reviso las estadisticas — miro pg_stats para las columnas involucradas. Verifico last_autoanalyze y last_analyze en pg_stat_user_tables. Si el ultimo ANALYZE es viejo, lo lanzo y reevaluo.\n4. Evaluo BUFFERS — si shared read es muy alto respecto a shared hit, el problema podria ser I/O, no el plan. En ese caso el fix es shared_buffers o el working set simplemente no cabe en RAM.\n5. Pruebo alternativas — si las estadisticas estan actualizadas pero el plan sigue mal, uso enable_nestloop, enable_hashjoin, enable_mergejoin para entender cual estrategia funciona mejor. Luego intento guiar al optimizer hacia esa estrategia con indices o reescritura.\nNada espectacular. Ningun truco magico. Solo lectura sistematica del plan, una linea a la vez.\n💬 La leccion de aquel dia #Mi colega, despues de ver la diferencia, me dijo: \u0026ldquo;Entonces bastaba con un ANALYZE?\u0026rdquo;\nSi y no. En ese caso especifico, si. Pero el punto no es el comando. El punto es saber leer el plan para entender donde mirar. EXPLAIN ANALYZE te da los datos. Te toca a ti interpretarlos.\nHe visto DBA con anos de experiencia lanzar EXPLAIN ANALYZE, mirar el tiempo total al final, y decir \u0026ldquo;la query es lenta\u0026rdquo;. Es como tomarle la temperatura a un paciente y decir \u0026ldquo;tiene fiebre\u0026rdquo;. Si, pero de que?\nEl plan de ejecucion te dice de que. Cada nodo es un organo. Las filas estimadas contra las reales son los valores de laboratorio. Los buffers son las radiografias. Y el ANALYZE es el antibiotico que resuelve el 70% de los casos.\nPero para ese 30% restante, hay que leer. Linea por linea. Nodo por nodo. No hay atajo.\nGlosario #Execution Plan — la secuencia de operaciones (scan, join, sort) que la base de datos elige para resolver una consulta SQL. Se visualiza con EXPLAIN y EXPLAIN ANALYZE.\nNested Loop — estrategia de join que por cada fila de la tabla externa busca las correspondencias en la tabla interna. Ideal para pocas filas, desastrosa en grandes volúmenes cuando es elegida por error por el optimizer.\nHash Join — estrategia de join que construye una hash table a partir de la tabla más pequeña y luego escanea la más grande buscando correspondencias con lookups O(1). Eficiente en grandes volúmenes sin índices.\nANALYZE — comando PostgreSQL que recopila estadísticas sobre la distribución de datos en las tablas, usadas por el optimizer para estimar la cardinalidad y elegir el plan de ejecución.\ndefault_statistics_target — parámetro PostgreSQL que define cuántas muestras recopilar por columna durante el ANALYZE. El valor por defecto es 100; en columnas con distribución asimétrica conviene subirlo a 500-1000.\n","date":"28 octubre 2025","permalink":"https://ivanluminaria.com/es/posts/postgresql/explain-analyze-postgresql/","section":"Database Strategy","summary":"\u003cp\u003eEl otro dia un colega me manda una captura de pantalla por Teams. Una query corriendo sobre una tabla de 2 millones de filas, 45 segundos de ejecucion. Me escribe:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Hice EXPLAIN ANALYZE, pero no entiendo que esta mal. El plan parece correcto.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eSpoiler: el plan no era correcto en absoluto. El optimizer habia elegido un \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Nested Loop Join — la estrategia de join que escanea la tabla interna por cada fila de la tabla externa, ideal para datasets pequenos con indice.\" data-glossary-url=\"/es/glossary/nested-loop/\" data-glossary-more=\"Leer más →\"\u003enested loop\u003c/span\u003e\n join donde hacia falta un \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Hash Join — estrategia de join optimizada para grandes volumenes de datos, basada en una hash table construida en memoria.\" data-glossary-url=\"/es/glossary/hash-join/\" data-glossary-more=\"Leer más →\"\u003ehash join\u003c/span\u003e\n, y la razon era trivial — estadisticas desactualizadas. Pero para llegar a eso tuve que leer el plan linea por linea, y ahi me di cuenta de que la mayoria de los DBA que conozco usan EXPLAIN ANALYZE como un oraculo binario: si el tiempo es alto, la query es lenta. Fin del analisis.\u003c/p\u003e","title":"EXPLAIN ANALYZE no basta: como leer realmente un plan de ejecucion PostgreSQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/optimizer/","section":"Tags","summary":"","title":"Optimizer"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/fact-table/","section":"Tags","summary":"","title":"Fact-Table"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/grain/","section":"Tags","summary":"","title":"Grain"},{"content":"La reunión había empezado bien. El director comercial de una empresa de distribución industrial — unos sesenta millones de facturación, tres mil clientes activos, un catálogo con doce mil referencias — había abierto la presentación del nuevo data warehouse con una sonrisa. Los números cuadraban, los dashboards lucían bien, los totales mensuales por agente y por zona coincidían con contabilidad.\nLuego alguien hizo la pregunta equivocada. O mejor dicho, la correcta.\n\u0026quot;¿Puedo ver cuánto compró el cliente Bianchi en marzo, línea por línea, producto por producto?\u0026quot;\nSilencio.\nEl responsable de BI me miró. Yo miré la pantalla. La pantalla mostraba una fact table con una fila por cliente por mes: importe total facturado, cantidad total, número de facturas. Ningún detalle. Ninguna línea de factura. Ningún producto.\nEsa fact table respondía a una sola pregunta: ¿cuánto facturó cada cliente en un mes determinado? Todo lo demás — por producto, por familia de productos, por factura individual — quedaba fuera de alcance.\n🔍 El grain: la decisión que determina todo #En el modelado dimensional , el grain (la granularidad) de la fact table es la primera decisión que se toma. No la segunda, no una entre tantas: la primera. Kimball lo repite en cada capítulo, y tiene razón.\nEl grain responde a la pregunta: ¿qué representa una fila individual de la fact table?\nEn el proyecto que describí, quien diseñó el modelo había elegido un grain mensual-cliente: una fila = un cliente en un mes. Las razones parecían razonables: el sistema fuente exportaba un resumen mensual, la carga era rápida, las tablas eran pequeñas, las consultas simples.\nPero el grain determina las preguntas que el data warehouse puede responder. Si la granularidad es el resumen mensual por cliente, no puedes bajar de ese nivel. No puedes hacer drill-down por producto. No puedes saber si el cliente Bianchi compró diez veces el mismo artículo o diez artículos diferentes. No puedes comparar márgenes por familia de productos.\nTienes un total. Punto.\n📊 Los números del problema #La fact table original tenía esta estructura:\nCREATE TABLE fact_facturacion_mensual ( sk_cliente INT NOT NULL, sk_tiempo INT NOT NULL, -- mes (YYYYMM) sk_agente INT NOT NULL, sk_zona INT NOT NULL, importe_total DECIMAL(15,2), cantidad_total INT, num_facturas INT, num_lineas INT, FOREIGN KEY (sk_cliente) REFERENCES dim_cliente(sk_cliente), FOREIGN KEY (sk_tiempo) REFERENCES dim_tiempo(sk_tiempo) ); Filas por año: unas 180.000 (3.000 clientes × 12 meses × alguna variación). Pequeña, rápida, fácil de cargar. El ETL corría en menos de cinco minutos.\n¿El problema? Las medidas aditivas ya estaban agregadas. importe_total era la suma de todas las líneas de factura del mes. Imposible rastrear la composición. Como tener el total de un ticket sin saber qué compraste.\n🏗️ La reestructuración: bajar a la línea de factura #La solución era una sola: cambiar el grain. Llevar la fact table al nivel más bajo disponible en el sistema fuente — la línea individual de factura.\nCREATE TABLE fact_facturacion_linea ( sk_linea_factura INT PRIMARY KEY, sk_factura INT NOT NULL, sk_cliente INT NOT NULL, sk_producto INT NOT NULL, sk_tiempo INT NOT NULL, -- día (YYYYMMDD) sk_agente INT NOT NULL, sk_zona INT NOT NULL, sk_familia INT NOT NULL, cantidad INT, precio_unitario DECIMAL(12,4), importe_linea DECIMAL(15,2), descuento_pct DECIMAL(5,2), importe_neto DECIMAL(15,2), coste_producto DECIMAL(15,2), margen DECIMAL(15,2), FOREIGN KEY (sk_cliente) REFERENCES dim_cliente(sk_cliente), FOREIGN KEY (sk_producto) REFERENCES dim_producto(sk_producto), FOREIGN KEY (sk_tiempo) REFERENCES dim_tiempo(sk_tiempo) ); Filas por año: unos 2,4 millones (3.000 clientes × ~800 líneas/año en promedio). Un orden de magnitud más. Pero cada fila llevaba consigo el detalle completo: qué producto, qué factura, qué precio, qué descuento, qué margen.\n⚡ El impacto en el ETL #El cambio de grain tuvo un efecto en cascada sobre el ETL que nadie había previsto — o mejor dicho, que quien eligió el grain agregado había evitado enfrentar.\nNuevas dimensiones necesarias:\nDimensión Cardinalidad Notas dim_producto ~12.000 No existía: antes no era necesaria dim_familia ~180 Jerarquía de productos a 3 niveles dim_factura ~45.000/año Cabecera de factura con datos maestros Nueva ventana de carga:\nFase Antes Después Extracción 40 seg 3 min Transformación 1 min 8 min Carga fact 30 seg 4 min Total ~2 min ~15 min Quince minutos contra dos. Un precio aceptable para un data warehouse que ahora respondía preguntas reales.\n🔬 Las consultas que antes eran imposibles #Con el nuevo grain, las consultas que el negocio quería se volvieron triviales:\nDetalle de compras de un cliente por producto:\nSELECT c.razon_social, p.codigo_producto, p.descripcion, SUM(f.cantidad) AS piezas, SUM(f.importe_neto) AS facturado_neto, SUM(f.margen) AS margen_total FROM fact_facturacion_linea f JOIN dim_cliente c ON f.sk_cliente = c.sk_cliente JOIN dim_producto p ON f.sk_producto = p.sk_producto JOIN dim_tiempo t ON f.sk_tiempo = t.sk_tiempo WHERE c.razon_social = \u0026#39;Bianchi Srl\u0026#39; AND t.anio = 2024 AND t.mes = 3 GROUP BY c.razon_social, p.codigo_producto, p.descripcion ORDER BY facturado_neto DESC; Top 10 productos por margen en un trimestre:\nSELECT p.codigo_producto, p.descripcion, fm.desc_familia, SUM(f.importe_neto) AS facturado, SUM(f.margen) AS margen, ROUND(SUM(f.margen) / NULLIF(SUM(f.importe_neto), 0) * 100, 1) AS margen_pct FROM fact_facturacion_linea f JOIN dim_producto p ON f.sk_producto = p.sk_producto JOIN dim_familia fm ON f.sk_familia = fm.sk_familia JOIN dim_tiempo t ON f.sk_tiempo = t.sk_tiempo WHERE t.anio = 2024 AND t.trimestre = 1 GROUP BY p.codigo_producto, p.descripcion, fm.desc_familia ORDER BY margen DESC LIMIT 10; Comparación entre agentes: facturación media por línea:\nSELECT a.nombre_agente, COUNT(*) AS num_lineas, SUM(f.importe_neto) AS facturado_total, ROUND(AVG(f.importe_neto), 2) AS media_por_linea FROM fact_facturacion_linea f JOIN dim_agente a ON f.sk_agente = a.sk_agente JOIN dim_tiempo t ON f.sk_tiempo = t.sk_tiempo WHERE t.anio = 2024 GROUP BY a.nombre_agente ORDER BY facturado_total DESC; Ninguna de estas consultas era posible con el grain mensual-cliente. Ninguna. No era un problema de tuning o de índices — era un problema estructural, escrito en el ADN del modelo.\n📋 La regla de Kimball que habíamos ignorado #Ralph Kimball lo dice claramente: \u0026ldquo;siempre modelar al nivel de detalle más fino disponible en el sistema fuente.\u0026rdquo;\nNo es una sugerencia. No es una opción entre varias. Es el principio fundacional del modelado dimensional. Y la razón es simple: siempre se puede agregar del detalle al total, pero nunca se puede desagregar un total en su detalle.\nLa agregación es una operación irreversible. Como mezclar colores: del rojo y el amarillo puedes obtener el naranja, pero del naranja nunca vuelves a los colores originales.\nEn nuestro proyecto, la elección del grain agregado fue dictada por pereza de diseño, no por una restricción técnica. El sistema fuente tenía el detalle por línea de factura — simplemente nadie había querido enfrentar la complejidad de modelarlo, gestionar las dimensiones adicionales, extender la ventana del ETL.\n¿El resultado? Un data warehouse que tuvo que reconstruirse desde cero seis meses después del go-live.\n🎯 Cuándo el grain agregado tiene sentido #La granularidad fina no siempre es la única respuesta. Hay casos legítimos para fact tables agregadas:\nTablas de agregación (aggregate fact table) junto a la tabla de detalle, para acelerar las consultas más frecuentes Snapshots periódicos donde el negocio razona por período (saldo mensual de una cuenta, inventario a fin de semana) Restricciones de origen cuando el sistema fuente no expone el detalle y no hay forma de obtenerlo Pero la regla es: parte del detalle, luego agrega. Nunca al revés. Las aggregate fact tables son una optimización, no un sustituto de la granularidad fina.\nEn nuestro caso, después de la reestructuración, también creamos una vista materializada con el resumen mensual por cliente — la misma estructura de antes — para los dashboards ejecutivos que no necesitaban el detalle. Lo mejor de ambos mundos, sin sacrificar nada.\nLo que aprendí #Ese proyecto me enseñó algo que llevo conmigo en cada encargo posterior: la primera media hora de diseño de un data warehouse, aquella en la que se decide el grain, vale más que todas las optimizaciones que vendrán después. Un ETL perfecto, índices calibrados, hardware potente — nada de esto compensa un grain equivocado.\nSi tu fact table no responde las preguntas del negocio, no es culpa de las consultas. Es culpa del modelo. Y el modelo se decide en el grain.\nGlosario #Grain — El nivel de detalle (granularidad) de una fact table en el data warehouse. Determina qué representa cada fila y qué preguntas puede responder el modelo. Es la primera decisión en el diseño dimensional.\nFact table — Tabla central del star schema que contiene las medidas numéricas (importes, cantidades, márgenes) y las claves foráneas hacia las dimensiones. Su granularidad determina el nivel de análisis posible.\nAdditive Measure — Medida numérica que puede sumarse a lo largo de todas las dimensiones (ej. importe, cantidad). Una vez agregada a nivel superior, el detalle original se pierde irreversiblemente.\nDrill-down — Navegación en reportes desde el nivel agregado al detalle, a lo largo de una jerarquía. Solo posible si la fact table contiene datos a un nivel de granularidad suficiente.\nStar Schema — Modelo de datos con una fact table central y tablas dimensionales enlazadas. La estructura más usada en data warehouses por la simplicidad de las consultas analíticas.\nETL — Extract, Transform, Load: el proceso de extracción, transformación y carga de datos en el data warehouse. Un cambio de grain impacta directamente tiempos y complejidad del ETL.\n","date":"21 octubre 2025","permalink":"https://ivanluminaria.com/es/posts/data-warehouse/fatto-grana-sbagliata/","section":"Database Strategy","summary":"\u003cp\u003eLa reunión había empezado bien. El director comercial de una empresa de distribución industrial — unos sesenta millones de facturación, tres mil clientes activos, un catálogo con doce mil referencias — había abierto la presentación del nuevo data warehouse con una sonrisa. Los números cuadraban, los dashboards lucían bien, los totales mensuales por agente y por zona coincidían con contabilidad.\u003c/p\u003e\n\u003cp\u003eLuego alguien hizo la pregunta equivocada. O mejor dicho, la correcta.\u003c/p\u003e","title":"Granularidad equivocada: cuando la fact table no responde las preguntas correctas"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/granularity/","section":"Tags","summary":"","title":"Granularity"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/binary-log/","section":"Tags","summary":"","title":"Binary-Log"},{"content":"La alerta llegó un lunes por la mañana, entre tres reuniones y un café todavía caliente. \u0026ldquo;Filesystem /mysql al 85% en el nodo primario.\u0026rdquo; En otro nodo estaba al 66%, en el tercero al 25%. En un cluster, cuando los números no cuadran entre los nodos, siempre hay algo debajo.\nLa primera pregunta que te viene a la cabeza es \u0026ldquo;¿cuánto espacio necesitamos?\u0026rdquo;. Pero es la pregunta equivocada. La correcta es: \u0026ldquo;¿por qué se está llenando?\u0026rdquo;\nLa causa: binary logs en el volumen equivocado #Verificar fue rápido:\nSHOW VARIABLES LIKE \u0026#39;log_bin\u0026#39;; Resultado: ON. Los binary logs estaban activos — como se espera en un cluster. Pero el path era el problema:\nSHOW VARIABLES LIKE \u0026#39;log_bin_basename\u0026#39;; /mysql/bin_log/binlog Los binlogs estaban en el mismo volumen que los datos: /mysql. Un volumen de unos 3 TB que en un nodo ya iba por el 85%.\nTambién comprobé la retención:\nSHOW VARIABLES LIKE \u0026#39;binlog_expire_logs_seconds\u0026#39;; 2592000 Treinta días. Después quise entender cuánto pesaba realmente esta configuración. Comprobé el tamaño de los archivos binlog individuales y el ritmo de escritura: cada archivo pesaba aproximadamente 1 GB, y el servidor generaba uno cada dos horas. Doce archivos al día, por treinta días de retención: unos 360 GB de binary logs en el volumen principal. En un volumen de 3 TB compartido con los datos, los binlogs por sí solos ocupaban más del 10% del espacio. Y esos archivos no están solo en el primary — en Group Replication cada nodo escribe sus propios binlogs locales para la sincronización, así que el problema se multiplicaba en los tres nodos.\nEl cuadro era claro: los binary logs estaban devorando el filesystem principal. No un bug, no una tabla descontrolada. Solo una elección arquitectónica hecha en la instalación y nunca revisada.\n¿Qué tipo de cluster es exactamente? #Antes de tocar cualquier cosa en un servidor MySQL — antes siquiera de pensar en mover un archivo — necesitas saber qué tienes delante. \u0026ldquo;Es un cluster\u0026rdquo; no basta. MySQL tiene al menos cuatro formas distintas de hacer alta disponibilidad, y cada una tiene sus propias reglas.\nEmpecé con la replicación clásica:\nSHOW SLAVE STATUS\\G Empty set en los dos nodos que comprobé. Ninguna replicación tradicional activa.\nDespués probé con SHOW REPLICA STATUS — pero en MySQL 8.0.20 ese comando todavía no existe. Se introdujo en la 8.0.22. Un detalle que la documentación online suele olvidar mencionar, dejándote persiguiendo un error de sintaxis que no es tal.\nSiguiente paso — Group Replication:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; Y ahí estaba la respuesta:\nMEMBER_HOST MEMBER_STATE MEMBER_ROLE dbcluster01 ONLINE SECONDARY dbcluster02 ONLINE SECONDARY dbcluster03 ONLINE PRIMARY Tres nodos. Todos ONLINE. Un primary, dos secondary. Group Replication en modo single-primary.\nConfirmación final desde los plugins:\nSHOW PLUGINS; En la lista: group_replication | ACTIVE | GROUP REPLICATION | group_replication.so. Y desde la configuración:\nSHOW VARIABLES LIKE \u0026#39;group_replication_single_primary_mode\u0026#39;; ON Ahora sabía exactamente lo que tenía delante. No una réplica clásica, no un Galera, no un NDB Cluster. Un MySQL Group Replication single-primary con tres nodos, GTID habilitados, formato de binlog ROW. El panorama completo.\nLa tentación siempre es saltarse esta fase. \u0026ldquo;Ya sé que es un cluster, vamos.\u0026rdquo; Pero saltarse el diagnóstico en un cluster es como operar sin un TAC: puede que tengas suerte, o puede que provoques un desastre.\nLa solución: un volumen dedicado para los binary logs #La estrategia era sencilla: los binlogs necesitan su propio volumen. No en el mismo filesystem que los datos, no en un symlink improvisado, no en un directorio compartido. Un volumen dedicado, montado en el mismo path en los tres nodos.\nPedí a los administradores de sistemas que crearan un nuevo volumen de 600 GB con punto de montaje /mysql/binary_logs en cada uno de los tres nodos.\nCuando el volumen estuvo listo, verifiqué en los tres:\ndf -h /mysql/binary_logs Nodo /mysql /mysql/binary_logs dbcluster03 (PRIMARY) 85% 1% dbcluster02 (SECONDARY) 66% 1% dbcluster01 (SECONDARY) 25% 1% Espacio limpio y dedicado. Cada volumen en un disco local de la VM correspondiente — tres discos, tres volúmenes, mismo mountpoint en los tres nodos. Los administradores habían hecho un trabajo limpio.\nLos checks antes de tocar MySQL #Antes de parar el primer nodo, ejecuté tres comprobaciones que considero obligatorias.\nPermisos del directorio. MySQL no arranca si no puede escribir en el directorio de binlogs. Parece obvio, pero es una de las causas más frecuentes de \u0026ldquo;¿por qué no reinicia después del cambio de configuración?\u0026rdquo;\nls -ld /mysql/binary_logs En los tres nodos los permisos eran 755. Funciona, pero no es ideal para la seguridad — los binlogs pueden contener datos sensibles. Los cambié a 750:\nchmod 750 /mysql/binary_logs Resultado: drwxr-x--- mysql mysql. Solo el usuario mysql puede leer y escribir.\nTest de escritura real. Antes de dejar que MySQL escriba ahí, verifiqué que el filesystem respondiera:\ntouch /mysql/binary_logs/testfile ls -l /mysql/binary_logs/testfile rm -f /mysql/binary_logs/testfile Si el touch falla, el problema es del storage o de los permisos — y mejor descubrirlo ahora que después de un restart de MySQL.\nEstado del cluster. La última comprobación antes de proceder:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; Tres nodos ONLINE. Quórum intacto. Se puede empezar.\nLa estrategia: un nodo a la vez, el primary de último #En un Group Replication de tres nodos, el quórum es dos. Si paras un nodo, los otros dos mantienen el grupo. Si paras dos — has perdido el cluster.\nLa regla es simple: un nodo a la vez, esperando a que el anterior reingrese al grupo antes de tocar el siguiente. Y el primary se hace de último.\n¿Por qué? Porque cuando paras el primary, sucede algo importante: el cluster lanza una elección automática y uno de los secondary se convierte en el nuevo primary. Durante esos segundos — pocos, si todo está sano — las conexiones activas pueden caerse, las transacciones en curso pueden fallar. Es una interrupción breve, pero es una interrupción. Hay que comunicarla.\nEl orden que seguí:\ndbcluster01 (SECONDARY) dbcluster02 (SECONDARY) dbcluster03 (PRIMARY) El procedimiento, nodo por nodo #En cada nodo la secuencia es idéntica:\nA. Verificar el rol del nodo. Antes de pararlo, confirma que es lo que piensas:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; B. Parar MySQL:\nsystemctl stop mysqld C. Modificar la configuración. En el my.cnf, cambiar el parámetro log_bin:\nDe:\nlog_bin=/mysql/bin_log/binlog A:\nlog_bin=/mysql/binary_logs/mysql-bin Una línea. Un solo cambio. No toques los parámetros de Group Replication, no cambies el server_id, no reinventes el motor a vapor mientras cambias una rueda.\nD. Arrancar MySQL:\nsystemctl start mysqld E. Verificar. Tres cosas que comprobar:\nEl nuevo path:\nSHOW VARIABLES LIKE \u0026#39;log_bin_basename\u0026#39;; Debe devolver /mysql/binary_logs/mysql-bin.\nEl reingreso al grupo:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; El nodo debe volver a ONLINE.\nLos nuevos binlogs en el nuevo path:\nls -lh /mysql/binary_logs/ Deben aparecer los nuevos archivos mysql-bin.000001.\nSolo cuando el nodo está ONLINE y el cluster muestra de nuevo tres nodos activos se pasa al siguiente. No antes.\nPara el primary — dbcluster03 — el procedimiento es idéntico, pero antes de pararlo verifiqué que ambos secondary estuvieran ONLINE y ya migrados. En el momento del stop, el cluster lanzó la elección. Uno de los secondary se convirtió en primary. Breve interrupción, como estaba previsto.\nQué no hacer #Desde mi experiencia, estas son las trampas más comunes en este tipo de intervención:\nNo copies los binlogs viejos al nuevo path. En Group Replication no hace falta hacer arqueología binaria. Los nuevos binlogs se crearán en el nuevo directorio después del reinicio. Los viejos solo se necesitan si requieres point-in-time recovery — y en ese caso ya sabes dónde encontrarlos.\nNo toques dos nodos a la vez. Con tres nodos el quórum es sagrado. Un nodo a la vez, sin excepciones. Si paras dos juntos, estás jugando a Jenga con los ojos vendados.\nNo empieces por el primary. Siempre los secondary primero, el primary de último. Hacerlo al revés es la forma elegante de invitar al caos a cenar.\nNo borres los binlogs viejos inmediatamente. Después del cambio, el path antiguo /mysql/bin_log/ ya no se usará para los nuevos archivos. Pero no hagas rm -rf /mysql/bin_log/* corriendo. Espera. Verifica que el cluster esté estable, que los nuevos binlogs se escriban en el nuevo mount, que no haya errores en el log de MySQL. Solo después de unos días de observación, piensa en la limpieza.\nNo te fíes solo de que \u0026ldquo;MySQL arrancó\u0026rdquo;. MySQL puede arrancar pero no reincorporarse al grupo. Necesitas verificar tres cosas: log_bin_basename apunta al nuevo path, el nodo está ONLINE en replication_group_members, y los archivos binlog se están escribiendo realmente en el nuevo directorio.\nLo que esta operación enseña #Un filesystem al 92% no es una emergencia — es una señal. El problema real no era el espacio en disco, sino una elección arquitectónica hecha en el momento de la instalación y nunca revisada: binlogs y datos en el mismo volumen.\nSeparar los binary logs en un volumen dedicado no es solo un fix. Es endurecimiento de la infraestructura. Es la diferencia entre un sistema que \u0026ldquo;funciona\u0026rdquo; y uno que está diseñado para seguir funcionando cuando las cosas crecen.\nY la parte más importante de toda la intervención no fue el cambio en el my.cnf — eso es una línea. La parte importante fue el diagnóstico: entender qué tipo de cluster tenía delante, verificar el estado de cada nodo, preparar el storage, probar los permisos, planificar el orden de ejecución. Todo antes de tocar un solo parámetro.\nUn DBA senior y un DBA junior conocen ambos el comando systemctl stop mysqld. La diferencia está en todo lo que sucede antes.\nGlosario #Group Replication — Mecanismo nativo de MySQL para la replicación síncrona multi-nodo con failover automático y gestión de quórum. Soporta modos single-primary y multi-primary.\nBinary log — Registro binario secuencial de MySQL que rastrea todas las modificaciones de datos (INSERT, UPDATE, DELETE, DDL), usado para la replicación y el point-in-time recovery.\nGTID — Global Transaction Identifier — identificador único asignado a cada transacción en MySQL, que simplifica la gestión de la replicación y el seguimiento de transacciones entre los nodos del cluster.\nQuorum — Número mínimo de nodos que deben estar activos y en comunicación para que un cluster pueda seguir operando. En un cluster de 3 nodos, el quórum es 2.\nSingle-primary — Modo de Group Replication en el que solo un nodo acepta escrituras mientras los demás son de solo lectura con failover automático.\n","date":"14 octubre 2025","permalink":"https://ivanluminaria.com/es/posts/mysql/mysql-group-replication-binlog-migration/","section":"Database Strategy","summary":"\u003cp\u003eLa alerta llegó un lunes por la mañana, entre tres reuniones y un café todavía caliente. \u0026ldquo;Filesystem /mysql al 85% en el nodo primario.\u0026rdquo; En otro nodo estaba al 66%, en el tercero al 25%. En un cluster, cuando los números no cuadran entre los nodos, siempre hay algo debajo.\u003c/p\u003e\n\u003cp\u003eLa primera pregunta que te viene a la cabeza es \u0026ldquo;¿cuánto espacio necesitamos?\u0026rdquo;. Pero es la pregunta equivocada. La correcta es: \u0026ldquo;¿por qué se está llenando?\u0026rdquo;\u003c/p\u003e","title":"Disco lleno en un cluster MySQL: binary logs, Group Replication y una migración que no admite errores"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/group-replication/","section":"Tags","summary":"","title":"Group-Replication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/tags/innodb-cluster/","section":"Tags","summary":"","title":"Innodb-Cluster"},{"content":"Una additive measure (medida aditiva) es un valor numérico en una fact table que puede sumarse legítimamente a lo largo de cualquier dimensión: por cliente, por producto, por período, por zona.\nCómo funciona #Las medidas en las fact tables se clasifican en tres categorías:\nAditivas: pueden sumarse a lo largo de todas las dimensiones (ej. importe de venta, cantidad, coste). Son las más comunes y las más útiles Semi-aditivas: pueden sumarse a lo largo de algunas dimensiones pero no a lo largo del tiempo (ej. saldo de una cuenta: sumable por sucursal, no por mes) No aditivas: no pueden sumarse de ninguna manera (ej. porcentajes, ratios, promedios precalculados) Para qué sirve #Las medidas aditivas son el corazón de toda fact table porque permiten las agregaciones que el negocio requiere: totales por período, por región, por producto. La regla clave: almacenar siempre los valores atómicos (el detalle), nunca los agregados. De un importe por línea de factura puedes obtener el total mensual; del total mensual no puedes reconstruir las líneas individuales.\nCuándo se usa #Al diseñar la fact table, cada medida debe clasificarse como aditiva, semi-aditiva o no aditiva. Esto determina qué agregaciones son válidas en los reportes y cuáles producirían resultados incorrectos. Un error común es tratar una medida semi-aditiva (como un saldo) como si fuera aditiva — sumando saldos mensuales para obtener un \u0026ldquo;total\u0026rdquo; que no tiene significado de negocio.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/additive-measure/","section":"Glosario","summary":"\u003cp\u003eUna \u003cstrong\u003eadditive measure\u003c/strong\u003e (medida aditiva) es un valor numérico en una fact table que puede sumarse legítimamente a lo largo de cualquier dimensión: por cliente, por producto, por período, por zona.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLas medidas en las fact tables se clasifican en tres categorías:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAditivas\u003c/strong\u003e: pueden sumarse a lo largo de todas las dimensiones (ej. importe de venta, cantidad, coste). Son las más comunes y las más útiles\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSemi-aditivas\u003c/strong\u003e: pueden sumarse a lo largo de algunas dimensiones pero no a lo largo del tiempo (ej. saldo de una cuenta: sumable por sucursal, no por mes)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNo aditivas\u003c/strong\u003e: no pueden sumarse de ninguna manera (ej. porcentajes, ratios, promedios precalculados)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"para-qué-sirve\" class=\"relative group\"\u003ePara qué sirve \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#para-qu%c3%a9-sirve\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLas medidas aditivas son el corazón de toda fact table porque permiten las agregaciones que el negocio requiere: totales por período, por región, por producto. La regla clave: almacenar siempre los valores atómicos (el detalle), nunca los agregados. De un importe por línea de factura puedes obtener el total mensual; del total mensual no puedes reconstruir las líneas individuales.\u003c/p\u003e","title":"Additive Measure"},{"content":"El AI Manager es el rol profesional que gobierna la introducción y el uso de la inteligencia artificial dentro de un proyecto u organización. No es quien usa la IA — es quien decide dónde, cómo y con qué precauciones integrarla en las arquitecturas existentes.\nCómo funciona #El AI Manager responde a preguntas que ningún modelo puede responder: ¿dónde la IA genera valor real y dónde genera solo entusiasmo? ¿Cuánto cuesta mantenerla, no solo implementarla? ¿Qué pasa cuando el modelo se equivoca? ¿Cómo se integra con las arquitecturas mission-critical sin comprometer su estabilidad?\nPara qué sirve #Separa la señal del ruido. En un mercado donde cada proveedor promete ROI de tres cifras, el AI Manager identifica los tres ámbitos donde la IA genera valor concreto: aceleración del análisis, reducción del ruido decisional y knowledge transfer automatizado. Todo lo demás son demos que brillan.\nPor qué es crítico #Sin alguien que gobierne la IA, las organizaciones la sufren en lugar de aprovecharla. La IA se integra sin verificar la procedencia de los datos de training, sin plan de fallback, sin governance. En ámbitos regulados (banca, administración pública, sanidad) esto es un riesgo que puede costar mucho más que la propia IA.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/ai-manager/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eAI Manager\u003c/strong\u003e es el rol profesional que gobierna la introducción y el uso de la inteligencia artificial dentro de un proyecto u organización. No es quien usa la IA — es quien decide dónde, cómo y con qué precauciones integrarla en las arquitecturas existentes.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl AI Manager responde a preguntas que ningún modelo puede responder: ¿dónde la IA genera valor real y dónde genera solo entusiasmo? ¿Cuánto cuesta mantenerla, no solo implementarla? ¿Qué pasa cuando el modelo se equivoca? ¿Cómo se integra con las arquitecturas mission-critical sin comprometer su estabilidad?\u003c/p\u003e","title":"AI Manager"},{"content":"ANALYZE es el comando PostgreSQL que recopila estadisticas sobre la distribucion de los datos en las tablas y las almacena en el catalogo pg_statistic (legible a traves de la vista pg_stats). El optimizer usa estas estadisticas para estimar la cardinalidad — cuantas filas devolvera cada operacion — y elegir el plan de ejecucion mas eficiente.\nQue recopila #Las estadisticas recopiladas por ANALYZE incluyen:\nMost common values: los valores mas frecuentes por cada columna y su porcentaje Histogramas de distribucion: como se distribuyen los valores restantes Numero de valores distintos: cuantos valores unicos tiene cada columna Porcentaje de NULL: cuantas filas tienen valor NULL por cada columna La calidad de estas estadisticas depende del numero de muestras recopiladas, controlado por el parametro default_statistics_target.\nPor que es critico #Sin estadisticas actualizadas, el optimizer se ve obligado a adivinar. Las estimaciones erroneas llevan a planes de ejecucion desastrosos — como elegir un nested loop sobre millones de filas pensando que son cientos, o ignorar un indice perfectamente adecuado.\nCuando ejecutarlo #PostgreSQL ejecuta ANALYZE automaticamente a traves del autovacuum, pero el umbral por defecto (50 filas + 10% de las filas vivas) puede ser demasiado alto para tablas que crecen rapidamente. Situaciones donde un ANALYZE manual es necesario:\nDespues de importaciones masivas o bulk load Despues de cambios significativos en la distribucion de los datos Cuando EXPLAIN ANALYZE muestra estimaciones de cardinalidad muy diferentes de las filas reales Despues de modificar el default_statistics_target de una columna ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/postgresql-analyze/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eANALYZE\u003c/strong\u003e es el comando PostgreSQL que recopila estadisticas sobre la distribucion de los datos en las tablas y las almacena en el catalogo \u003ccode\u003epg_statistic\u003c/code\u003e (legible a traves de la vista \u003ccode\u003epg_stats\u003c/code\u003e). El optimizer usa estas estadisticas para estimar la cardinalidad — cuantas filas devolvera cada operacion — y elegir el plan de ejecucion mas eficiente.\u003c/p\u003e\n\u003ch2 id=\"que-recopila\" class=\"relative group\"\u003eQue recopila \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#que-recopila\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLas estadisticas recopiladas por ANALYZE incluyen:\u003c/p\u003e","title":"ANALYZE"},{"content":"El Anonymous User (usuario anónimo) es una cuenta MySQL/MariaDB con username vacío (''@'localhost') que se crea automáticamente durante la instalación. No tiene nombre y frecuentemente no tiene contraseña.\nCómo funciona #Cuando un usuario se conecta, MySQL busca la correspondencia más específica en la tabla mysql.user. El usuario anónimo ''@'localhost' es más específico que 'mario'@'%' para una conexión desde localhost, porque 'localhost' gana sobre '%' en la jerarquía de especificidad. En consecuencia, Mario que se conecta desde local es autenticado como usuario anónimo y pierde todos sus privilegios.\nPara qué sirve #El usuario anónimo fue pensado para instalaciones de desarrollo donde se quería permitir conexiones sin credenciales. En producción no tiene utilidad y representa un riesgo de seguridad: puede capturar conexiones destinadas a otros usuarios y conceder acceso no autorizado.\nCuándo se usa #Nunca en producción. La primera operación en cualquier instalación MySQL/MariaDB de producción es verificar y eliminar los usuarios anónimos con SELECT user, host FROM mysql.user WHERE user = '' seguido de DROP USER ''@'localhost'.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/anonymous-user/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eAnonymous User\u003c/strong\u003e (usuario anónimo) es una cuenta MySQL/MariaDB con username vacío (\u003ccode\u003e''@'localhost'\u003c/code\u003e) que se crea automáticamente durante la instalación. No tiene nombre y frecuentemente no tiene contraseña.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando un usuario se conecta, MySQL busca la correspondencia más específica en la tabla \u003ccode\u003emysql.user\u003c/code\u003e. El usuario anónimo \u003ccode\u003e''@'localhost'\u003c/code\u003e es más específico que \u003ccode\u003e'mario'@'%'\u003c/code\u003e para una conexión desde localhost, porque \u003ccode\u003e'localhost'\u003c/code\u003e gana sobre \u003ccode\u003e'%'\u003c/code\u003e en la jerarquía de especificidad. En consecuencia, Mario que se conecta desde local es autenticado como usuario anónimo y pierde todos sus privilegios.\u003c/p\u003e","title":"Anonymous User"},{"content":"ASH (Active Session History) es un componente de Oracle Database que muestrea el estado de cada sesion activa una vez por segundo y almacena los datos en un buffer circular en memoria (vista V$ACTIVE_SESSION_HISTORY).\nComo funciona #Cada segundo Oracle registra para cada sesion activa:\nSQL en ejecucion (SQL_ID) Wait event actual Programa y modulo llamante Plan de ejecucion utilizado (SQL_PLAN_HASH_VALUE) Los datos mas antiguos se descargan automaticamente en las tablas AWR (DBA_HIST_ACTIVE_SESS_HISTORY) y se conservan durante el periodo configurado.\nPara que sirve #ASH es el microscopio del DBA: donde AWR muestra promedios sobre intervalos de una hora, ASH permite reconstruir que estaba haciendo una sesion concreta en un instante preciso. Es la herramienta ideal para:\nIdentificar quien esta ejecutando un SQL problematico Entender cuando empezo un problema (al segundo) Correlacionar sesiones, programas y wait events en tiempo real Cuando se usa #Se usa cuando el informe AWR ya ha identificado un SQL o un wait event dominante y se necesita detalle: que sesion, que programa, a que hora exacta. La regla empirica: AWR para entender que cambio, ASH para entender por que.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/ash/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eASH\u003c/strong\u003e (Active Session History) es un componente de Oracle Database que muestrea el estado de cada sesion activa una vez por segundo y almacena los datos en un buffer circular en memoria (vista \u003ccode\u003eV$ACTIVE_SESSION_HISTORY\u003c/code\u003e).\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada segundo Oracle registra para cada sesion activa:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSQL en ejecucion (\u003ccode\u003eSQL_ID\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003eWait event actual\u003c/li\u003e\n\u003cli\u003ePrograma y modulo llamante\u003c/li\u003e\n\u003cli\u003ePlan de ejecucion utilizado (\u003ccode\u003eSQL_PLAN_HASH_VALUE\u003c/code\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eLos datos mas antiguos se descargan automaticamente en las tablas AWR (\u003ccode\u003eDBA_HIST_ACTIVE_SESS_HISTORY\u003c/code\u003e) y se conservan durante el periodo configurado.\u003c/p\u003e","title":"ASH"},{"content":"Un Authentication Plugin es el módulo que MySQL o MariaDB usa para verificar las credenciales de un usuario al momento de la conexión. Cada usuario en el sistema está asociado a un plugin específico que determina cómo la contraseña es hasheada, transmitida y verificada.\nCómo funciona #Los plugins principales son: mysql_native_password (default en MySQL 5.7 y MariaDB), que usa un hash SHA1 doble; caching_sha2_password (default en MySQL 8.0+), que usa SHA-256 con caching para mejorar seguridad y rendimiento. Cuando un cliente se conecta, debe soportar el plugin del usuario al que intenta autenticarse.\nPara qué sirve #El conocimiento de los plugins de autenticación es esencial durante las migraciones entre versiones o entre MySQL y MariaDB. Un cliente que solo soporta mysql_native_password no logra conectarse a un usuario con caching_sha2_password — y el error resultante es frecuentemente críptico y difícil de diagnosticar.\nCuándo se usa #El plugin se especifica al momento de crear el usuario (CREATE USER ... IDENTIFIED WITH \u0026lt;plugin\u0026gt; BY 'password') o se puede verificar y modificar con ALTER USER. Cuando se escriben scripts de provisioning que deben funcionar en versiones diferentes de MySQL/MariaDB, es importante especificar explícitamente el plugin.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/authentication-plugin/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eAuthentication Plugin\u003c/strong\u003e es el módulo que MySQL o MariaDB usa para verificar las credenciales de un usuario al momento de la conexión. Cada usuario en el sistema está asociado a un plugin específico que determina cómo la contraseña es hasheada, transmitida y verificada.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLos plugins principales son: \u003ccode\u003emysql_native_password\u003c/code\u003e (default en MySQL 5.7 y MariaDB), que usa un hash SHA1 doble; \u003ccode\u003ecaching_sha2_password\u003c/code\u003e (default en MySQL 8.0+), que usa SHA-256 con caching para mejorar seguridad y rendimiento. Cuando un cliente se conecta, debe soportar el plugin del usuario al que intenta autenticarse.\u003c/p\u003e","title":"Authentication Plugin"},{"content":"El Autovacuum es un daemon de PostgreSQL que ejecuta automáticamente VACUUM y ANALYZE en las tablas cuando el número de dead tuples supera un umbral calculado como: threshold + scale_factor × n_live_tup. Con los valores por defecto (threshold=50, scale_factor=0.2), en una tabla con 10 millones de filas se activa tras 2 millones de dead tuples.\nCómo funciona #El daemon comprueba periódicamente pg_stat_user_tables y lanza un worker por cada tabla que supera el umbral. El número máximo de workers simultáneos se controla con autovacuum_max_workers (por defecto 3). El parámetro autovacuum_vacuum_cost_delay controla cuánto se autofrena el vacuum para no sobrecargar el I/O.\nPara qué sirve #Es el custodio silencioso que impide que las tablas se hinchen por acumulación de dead tuples. Nunca debe deshabilitarse — es lo peor que se puede hacer a un PostgreSQL en producción. Debe configurarse por tabla: las tablas de alto tráfico necesitan scale_factors bajos (0.01-0.05) y cost_delay reducidos.\nQué puede salir mal #Con los valores por defecto, el autovacuum es demasiado conservador para tablas de alto tráfico. 3 workers para decenas de tablas activas no bastan. Un scale_factor del 20% en tablas grandes genera millones de dead tuples antes de la intervención. El tuning por tabla con ALTER TABLE ... SET (autovacuum_vacuum_scale_factor = 0.01) es esencial.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/autovacuum/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eAutovacuum\u003c/strong\u003e es un daemon de PostgreSQL que ejecuta automáticamente VACUUM y ANALYZE en las tablas cuando el número de dead tuples supera un umbral calculado como: \u003ccode\u003ethreshold + scale_factor × n_live_tup\u003c/code\u003e. Con los valores por defecto (threshold=50, scale_factor=0.2), en una tabla con 10 millones de filas se activa tras 2 millones de dead tuples.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl daemon comprueba periódicamente \u003ccode\u003epg_stat_user_tables\u003c/code\u003e y lanza un worker por cada tabla que supera el umbral. El número máximo de workers simultáneos se controla con \u003ccode\u003eautovacuum_max_workers\u003c/code\u003e (por defecto 3). El parámetro \u003ccode\u003eautovacuum_vacuum_cost_delay\u003c/code\u003e controla cuánto se autofrena el vacuum para no sobrecargar el I/O.\u003c/p\u003e","title":"Autovacuum"},{"content":"AWR (Automatic Workload Repository) es un componente integrado en Oracle Database que recopila automaticamente estadisticas de rendimiento del sistema a intervalos regulares (por defecto cada 60 minutos) y las conserva durante un periodo configurable.\nComo funciona #AWR captura snapshots periodicos que incluyen:\nEstadisticas de sesiones y wait events Metricas SQL (top SQL por tiempo de ejecucion, I/O, CPU) Estadisticas de estructuras de memoria (SGA, PGA) Estadisticas I/O por datafile y tablespace Para que sirve #El informe AWR es la herramienta principal para diagnosticar problemas de rendimiento en Oracle. Comparando dos snapshots se pueden identificar:\nQueries que consumen demasiados recursos Cambios en los planes de ejecucion Cuellos de botella en I/O, CPU o memoria Regresiones de rendimiento tras despliegues aplicativos Cuando se usa #AWR es la primera herramienta a consultar cuando se recibe una notificacion de lentitud. Junto con ASH (Active Session History), permite reconstruir lo que paso en la base de datos durante un intervalo de tiempo especifico, incluso despues de que el problema se haya resuelto.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/awr/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eAWR\u003c/strong\u003e (Automatic Workload Repository) es un componente integrado en Oracle Database que recopila automaticamente estadisticas de rendimiento del sistema a intervalos regulares (por defecto cada 60 minutos) y las conserva durante un periodo configurable.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eAWR captura snapshots periodicos que incluyen:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEstadisticas de sesiones y wait events\u003c/li\u003e\n\u003cli\u003eMetricas SQL (top SQL por tiempo de ejecucion, I/O, CPU)\u003c/li\u003e\n\u003cli\u003eEstadisticas de estructuras de memoria (SGA, PGA)\u003c/li\u003e\n\u003cli\u003eEstadisticas I/O por datafile y tablespace\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"para-que-sirve\" class=\"relative group\"\u003ePara que sirve \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#para-que-sirve\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl informe AWR es la herramienta principal para diagnosticar problemas de rendimiento en Oracle. Comparando dos snapshots se pueden identificar:\u003c/p\u003e","title":"AWR"},{"content":"El B-Tree (Balanced Tree) es la estructura de datos más común para índices en bases de datos relacionales y es el tipo de índice predeterminado en PostgreSQL, MySQL y Oracle. Mantiene los datos ordenados en una estructura de árbol balanceado que garantiza tiempos de búsqueda logarítmicos.\nCómo funciona #Un B-Tree organiza las claves en nodos ordenados, con cada nodo conteniendo punteros a nodos hijos. La búsqueda parte de la raíz y desciende hacia las hojas, dividiendo a la mitad el espacio de búsqueda en cada nivel. Para una tabla de 6 millones de filas, un B-Tree requiere típicamente 3-4 niveles de profundidad, es decir 3-4 lecturas de página para encontrar un valor.\nPara qué sirve #Los B-Tree son óptimos para búsquedas de igualdad (WHERE col = 'valor'), rangos (WHERE col BETWEEN x AND y), ordenamiento y búsquedas con prefijo (LIKE 'ABC%'). Sin embargo, no pueden usarse para búsquedas con wildcard inicial (LIKE '%ABC%'), porque el ordenamiento del B-Tree no ayuda a encontrar subcadenas en posiciones arbitrarias.\nCuándo se usa #El B-Tree es la elección correcta para la mayoría de los índices. Cuando se necesita una búsqueda \u0026ldquo;contiene\u0026rdquo; en texto, hay que pasar a un índice GIN con la extensión pg_trgm. La elección entre B-Tree y GIN depende del tipo de query y del perfil de carga de la tabla.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/b-tree/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eB-Tree\u003c/strong\u003e (Balanced Tree) es la estructura de datos más común para índices en bases de datos relacionales y es el tipo de índice predeterminado en PostgreSQL, MySQL y Oracle. Mantiene los datos ordenados en una estructura de árbol balanceado que garantiza tiempos de búsqueda logarítmicos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn B-Tree organiza las claves en nodos ordenados, con cada nodo conteniendo punteros a nodos hijos. La búsqueda parte de la raíz y desciende hacia las hojas, dividiendo a la mitad el espacio de búsqueda en cada nivel. Para una tabla de 6 millones de filas, un B-Tree requiere típicamente 3-4 niveles de profundidad, es decir 3-4 lecturas de página para encontrar un valor.\u003c/p\u003e","title":"B-Tree"},{"content":"Una Bicicleta Plegable es una bicicleta diseñada para plegarse en dimensiones compactas (típicamente 60×55×25 cm) en pocos segundos, convirtiéndose en transportable como equipaje. La Brompton es el modelo más conocido, con mecanismo de plegado en 10-20 segundos.\nCómo funciona #Un sistema de bisagras y enganches rápidos permite plegar cuadro, manillar y pedales en un paquete compacto. Una vez plegada, se lleva a la oficina bajo el escritorio, se sube al metro o se mete en el maletero. En la versión eléctrica, combina las ventajas del pedaleo asistido con la portabilidad total.\nPara qué sirve #Elimina completamente el problema del aparcamiento — que en Roma puede costar 35€ al día y una hora y media de búsqueda. No hay riesgo de robo porque la bici siempre está contigo. Y en los días de lluvia fuerte, se pliega y se lleva en el metro sin problemas.\nPor qué es crítico #La bicicleta plegable es el \u0026ldquo;superpoder\u0026rdquo; que hace practicable el commuting en bici incluso para quien no tiene aparcamiento dedicado, quien necesita transporte público para parte del trayecto, o quien trabaja en una oficina sin aparcabicis. Es la solución a la última milla que el coche no puede ofrecer.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/bicicletta-pieghevole/","section":"Glosario","summary":"\u003cp\u003eUna \u003cstrong\u003eBicicleta Plegable\u003c/strong\u003e es una bicicleta diseñada para plegarse en dimensiones compactas (típicamente 60×55×25 cm) en pocos segundos, convirtiéndose en transportable como equipaje. La Brompton es el modelo más conocido, con mecanismo de plegado en 10-20 segundos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn sistema de bisagras y enganches rápidos permite plegar cuadro, manillar y pedales en un paquete compacto. Una vez plegada, se lleva a la oficina bajo el escritorio, se sube al metro o se mete en el maletero. En la versión eléctrica, combina las ventajas del pedaleo asistido con la portabilidad total.\u003c/p\u003e","title":"Bicicleta Plegable"},{"content":"El binary log (o binlog) es un registro secuencial en formato binario donde MySQL escribe todos los eventos que modifican datos: INSERT, UPDATE, DELETE y operaciones DDL. Los archivos se numeran progresivamente (mysql-bin.000001, mysql-bin.000002, etc.) y se gestionan mediante un archivo índice.\nCómo funciona #Desde MySQL 8.0 el binary log está habilitado por defecto mediante el parámetro log_bin. MySQL crea un nuevo archivo binlog cuando el servidor se inicia, cuando el archivo actual alcanza max_binlog_size, o cuando se ejecuta FLUSH BINARY LOGS. Soporta tres formatos de registro: STATEMENT (registra las instrucciones SQL), ROW (registra los cambios fila por fila) y MIXED (elección automática).\nPara qué sirve #El binary log tiene dos funciones fundamentales:\nReplicación: en una arquitectura master-slave, el slave lee los binlog del master para replicar las mismas operaciones Point-in-time recovery: después de restaurar un backup, los binlog permiten reaplicar los cambios hasta un momento preciso Cuándo se usa #El binary log está activo por defecto en cualquier instalación MySQL 8.0+. La gestión activa (retención, purge, monitorización del espacio) es necesaria para evitar que los archivos acumulados llenen el disco. El comando PURGE BINARY LOGS es la forma correcta de eliminar archivos obsoletos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/binary-log/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003ebinary log\u003c/strong\u003e (o binlog) es un registro secuencial en formato binario donde MySQL escribe todos los eventos que modifican datos: INSERT, UPDATE, DELETE y operaciones DDL. Los archivos se numeran progresivamente (\u003ccode\u003emysql-bin.000001\u003c/code\u003e, \u003ccode\u003emysql-bin.000002\u003c/code\u003e, etc.) y se gestionan mediante un archivo índice.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eDesde MySQL 8.0 el binary log está habilitado por defecto mediante el parámetro \u003ccode\u003elog_bin\u003c/code\u003e. MySQL crea un nuevo archivo binlog cuando el servidor se inicia, cuando el archivo actual alcanza \u003ccode\u003emax_binlog_size\u003c/code\u003e, o cuando se ejecuta \u003ccode\u003eFLUSH BINARY LOGS\u003c/code\u003e. Soporta tres formatos de registro: STATEMENT (registra las instrucciones SQL), ROW (registra los cambios fila por fila) y MIXED (elección automática).\u003c/p\u003e","title":"Binary log"},{"content":"El Bloat es la acumulación de espacio muerto dentro de una tabla o índice PostgreSQL, causada por dead tuples aún no eliminados por VACUUM. Una tabla con un 50% de bloat ocupa el doble del espacio necesario y obliga a los escaneos secuenciales a leer el doble de páginas.\nCómo funciona #El bloat se mide comparando el tamaño efectivo de la tabla con el tamaño esperado basado en las filas vivas. La extensión pgstattuple proporciona el campo dead_tuple_percent. Un bloat por encima del 20-30% es una señal de alarma; por encima del 50% es una emergencia.\nPara qué sirve #Monitorizar el bloat es esencial para entender si el autovacuum está manteniendo el ritmo. La consulta a pg_stat_user_tables con n_dead_tup y last_autovacuum es la primera herramienta diagnóstica. Si el bloat está fuera de control, pg_repack reconstruye la tabla online sin locks exclusivos prolongados — al contrario que VACUUM FULL.\nQué puede salir mal #VACUUM normal recupera el espacio de los dead tuples pero no compacta la tabla — el espacio fragmentado persiste. Si el bloat alcanza el 50-70%, VACUUM solo no es suficiente. Las opciones son VACUUM FULL (lock exclusivo, bloquea todo) o pg_repack (online, pero requiere instalación). La verdadera solución es no llegar ahí, con un autovacuum bien configurado.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/bloat/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eBloat\u003c/strong\u003e es la acumulación de espacio muerto dentro de una tabla o índice PostgreSQL, causada por dead tuples aún no eliminados por VACUUM. Una tabla con un 50% de bloat ocupa el doble del espacio necesario y obliga a los escaneos secuenciales a leer el doble de páginas.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl bloat se mide comparando el tamaño efectivo de la tabla con el tamaño esperado basado en las filas vivas. La extensión \u003ccode\u003epgstattuple\u003c/code\u003e proporciona el campo \u003ccode\u003edead_tuple_percent\u003c/code\u003e. Un bloat por encima del 20-30% es una señal de alarma; por encima del 50% es una emergencia.\u003c/p\u003e","title":"Bloat"},{"content":"Un Branch (rama) es una línea de desarrollo independiente en un repositorio Git. Cada branch contiene una copia del código sobre la que se puede trabajar sin afectar el branch principal (main) o el trabajo de otros desarrolladores.\nCómo funciona #Cuando un desarrollador crea un branch (ej. fix/issue-234-error-calculo), Git crea un puntero a la versión actual del código. Desde ese momento, los cambios hechos en el branch quedan aislados. Al terminar el trabajo, los cambios se proponen al equipo mediante Pull Request y, tras la aprobación, se unen (merge) al branch principal.\nPara qué sirve #Los branches eliminan el problema de las sobreescrituras accidentales y los conflictos no gestionados. Cada desarrollador trabaja en su propia área aislada: no sobrescribe el trabajo de los demás ni rompe el código funcional. El branch principal se mantiene siempre en un estado \u0026ldquo;bueno\u0026rdquo; porque solo recibe código aprobado.\nCuándo se usa #Se crea un branch para cada tarea, corrección de bug o funcionalidad. La convención de naming ayuda a identificar el propósito: fix/ para bugs, feature/ para nuevas funcionalidades, hotfix/ para correcciones urgentes. El branch se elimina después del merge para mantener el repositorio limpio.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/branch/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eBranch\u003c/strong\u003e (rama) es una línea de desarrollo independiente en un repositorio Git. Cada branch contiene una copia del código sobre la que se puede trabajar sin afectar el branch principal (main) o el trabajo de otros desarrolladores.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando un desarrollador crea un branch (ej. \u003ccode\u003efix/issue-234-error-calculo\u003c/code\u003e), Git crea un puntero a la versión actual del código. Desde ese momento, los cambios hechos en el branch quedan aislados. Al terminar el trabajo, los cambios se proponen al equipo mediante Pull Request y, tras la aprobación, se unen (merge) al branch principal.\u003c/p\u003e","title":"Branch"},{"content":"La Brompton es una bicicleta plegable fabricada en Londres desde 1975, considerada la referencia mundial en su categoría. Se pliega en 10-20 segundos alcanzando dimensiones de aproximadamente 58×56×27 cm — lo suficientemente compacta para caber bajo un escritorio o en el maletero de un utilitario.\nCómo funciona #El mecanismo patentado permite plegar la bici en tres movimientos: cuadro, manillar y sillín. En la versión eléctrica (Brompton Electric), un motor en el buje delantero proporciona pedaleo asistido hasta 25 km/h con una autonomía de 40-70 km. La batería es extraíble y se carga en 4 horas.\nPara qué sirve #Es la solución ideal para el pendularismo multimodal: se pedalea hasta la estación, se pliega, se sube al metro o tren, se despliega y se pedalea hasta la oficina. Una vez allí, se guarda bajo el escritorio. Cero aparcamiento, cero robo, cero restricciones.\nPor qué es crítico #En la comparación directa coche vs Brompton en Roma (Appio Latino → Prati), la Brompton tarda 18 minutos frente a los 50 del coche más 90 minutos de aparcamiento. Coste diario: 0€ frente a 35€. La Brompton se amortiza en menos de un año solo con el ahorro en aparcamiento.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/brompton/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eBrompton\u003c/strong\u003e es una bicicleta plegable fabricada en Londres desde 1975, considerada la referencia mundial en su categoría. Se pliega en 10-20 segundos alcanzando dimensiones de aproximadamente 58×56×27 cm — lo suficientemente compacta para caber bajo un escritorio o en el maletero de un utilitario.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl mecanismo patentado permite plegar la bici en tres movimientos: cuadro, manillar y sillín. En la versión eléctrica (Brompton Electric), un motor en el buje delantero proporciona pedaleo asistido hasta 25 km/h con una autonomía de 40-70 km. La batería es extraíble y se carga en 4 horas.\u003c/p\u003e","title":"Brompton"},{"content":"BYOL (Bring Your Own License) es un programa de Oracle que permite a las empresas transferir las licencias de software adquiridas para la infraestructura on-premises a Oracle Cloud Infrastructure (OCI), sin necesidad de comprar nuevas licencias cloud.\nComo funciona #Cuando una empresa ya tiene licencias Oracle — tipicamente Enterprise Edition con opciones como RAC, Data Guard o Partitioning — puede \u0026ldquo;llevarlas consigo\u0026rdquo; en la migracion a OCI. El contrato de soporte (Software Update License \u0026amp; Support) se mantiene, y las licencias se asocian a los recursos cloud en lugar de a los servidores fisicos.\nEn OCI, cada OCPU corresponde a una processor license, con una relacion 1:1 transparente. Esto hace que el calculo sea predecible y conforme a las politicas de licensing de Oracle.\nPor que es importante en las migraciones #El BYOL es a menudo el factor decisivo en la eleccion de OCI frente a otros proveedores cloud. En AWS o Azure, Oracle aplica reglas de licensing diferentes: cada vCPU cuenta como medio procesador, y opciones como RAC no estan soportadas o requieren licencias adicionales. Una auditoria Oracle en un cloud que no sea OCI puede convertir un ahorro aparente en un coste imprevisto muy significativo.\nQue cubre # Oracle Database (todas las ediciones) Opciones del database (RAC, Data Guard, Partitioning, Advanced Compression, etc.) Oracle Middleware y otros productos Oracle con licencias elegibles El BYOL no es automatico: debe solicitarse y configurarse en el momento del provisioning de los recursos OCI, especificando las licencias existentes en el contrato.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/byol/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eBYOL\u003c/strong\u003e (Bring Your Own License) es un programa de Oracle que permite a las empresas transferir las licencias de software adquiridas para la infraestructura on-premises a Oracle Cloud Infrastructure (OCI), sin necesidad de comprar nuevas licencias cloud.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando una empresa ya tiene licencias Oracle — tipicamente Enterprise Edition con opciones como RAC, Data Guard o Partitioning — puede \u0026ldquo;llevarlas consigo\u0026rdquo; en la migracion a OCI. El contrato de soporte (Software Update License \u0026amp; Support) se mantiene, y las licencias se asocian a los recursos cloud en lugar de a los servidores fisicos.\u003c/p\u003e","title":"BYOL"},{"content":"El Carbon Footprint (huella de carbono) es la cantidad total de gases de efecto invernadero — principalmente CO₂ — emitidos directa o indirectamente por una actividad, producto o individuo, expresada en toneladas de CO₂ equivalente.\nCómo funciona #Para el pendularismo urbano, el cálculo es directo: un coche parado en el tráfico de Roma produce en promedio 120-150 g de CO₂ por kilómetro. En tráfico congestionado incluso más, porque el motor funciona al ralentí consumiendo sin moverse. Una bicicleta produce cero emisiones directas.\nPara qué sirve #Cuantifica el impacto ambiental de las elecciones de movilidad. Si solo el 10% de los pendulares romanos cambiara a la bici, se ahorrarían unas 150.000 toneladas de CO₂ al año — el equivalente a plantar 7 millones de árboles. No es idealismo, es aritmética.\nPor qué es crítico #La huella de carbono del pendularismo es un coste externalizado que nadie paga directamente pero que todos sufren: contaminación del aire, cambio climático, costes sanitarios. La elección entre coche y bici no es solo personal — tiene un impacto colectivo medible.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/carbon-footprint/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eCarbon Footprint\u003c/strong\u003e (huella de carbono) es la cantidad total de gases de efecto invernadero — principalmente CO₂ — emitidos directa o indirectamente por una actividad, producto o individuo, expresada en toneladas de CO₂ equivalente.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePara el pendularismo urbano, el cálculo es directo: un coche parado en el tráfico de Roma produce en promedio 120-150 g de CO₂ por kilómetro. En tráfico congestionado incluso más, porque el motor funciona al ralentí consumiendo sin moverse. Una bicicleta produce cero emisiones directas.\u003c/p\u003e","title":"Carbon Footprint"},{"content":"CDC (Change Data Capture) es una técnica para interceptar las modificaciones de datos (INSERT, UPDATE, DELETE) en el momento en que ocurren y propagarlas hacia otros sistemas en tiempo real o casi real. A diferencia de los enfoques batch tradicionales (ETL periódicos), el CDC captura los cambios de forma continua e incremental.\nCómo funciona #El enfoque más difundido es el log-based CDC: un componente externo lee los logs de transacciones de la base de datos (binary log en MySQL, WAL en PostgreSQL, redo log en Oracle) y convierte los eventos en un flujo de datos consumible por otros sistemas. Herramientas como Debezium, Maxwell y Canal implementan este enfoque para MySQL leyendo directamente los binary log.\nPara qué sirve #El CDC se usa para:\nSincronizar datos entre bases de datos diferentes en tiempo real Alimentar data warehouses y data lakes con actualizaciones incrementales Poblar cachés e índices de búsqueda (Elasticsearch, Redis) Implementar arquitecturas event-driven y microservicios Cuándo se usa #El CDC requiere que el binary log esté activo y en formato ROW (que registra los cambios fila por fila). Desactivar los binary log o usar el formato STATEMENT elimina la posibilidad de utilizar herramientas de CDC, haciendo imposible la integración en tiempo real con sistemas externos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/cdc/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eCDC\u003c/strong\u003e (Change Data Capture) es una técnica para interceptar las modificaciones de datos (INSERT, UPDATE, DELETE) en el momento en que ocurren y propagarlas hacia otros sistemas en tiempo real o casi real. A diferencia de los enfoques batch tradicionales (ETL periódicos), el CDC captura los cambios de forma continua e incremental.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl enfoque más difundido es el \u003cstrong\u003elog-based CDC\u003c/strong\u003e: un componente externo lee los logs de transacciones de la base de datos (binary log en MySQL, WAL en PostgreSQL, redo log en Oracle) y convierte los eventos en un flujo de datos consumible por otros sistemas. Herramientas como Debezium, Maxwell y Canal implementan este enfoque para MySQL leyendo directamente los binary log.\u003c/p\u003e","title":"CDC"},{"content":"El churn de una tabla es la medida de cuánto cambian sus datos después de la inserción. Una tabla con alto churn sufre frecuentes UPDATE y DELETE; una tabla con bajo churn es predominantemente append-only (solo INSERT).\nCómo funciona #En PostgreSQL, cada UPDATE crea una nueva versión de la fila (debido al modelo MVCC) y la versión antigua se convierte en una dead tuple. Los DELETE también crean dead tuples. Cuanto mayor es el churn, más trabajo deben hacer VACUUM y los índices para mantener el rendimiento. Un índice GIN en una tabla de alto churn puede degradar significativamente el rendimiento de escritura.\nPara qué sirve #Evaluar el churn antes de crear un índice es esencial para evitar resolver un problema de lectura creando uno de escritura. En una tabla append-only (cero UPDATE, cero DELETE, cero dead tuples), un índice GIN tiene impacto mínimo en las escrituras. En una tabla de alto churn, el mismo índice podría convertirse en un cuello de botella.\nCuándo se usa #El churn se analiza verificando las estadísticas de la tabla: número de UPDATE y DELETE diarios, dead tuples, frecuencia de VACUUM. En PostgreSQL, pg_stat_user_tables proporciona estas métricas. La decisión de añadir un índice GIN o trigram debería siempre partir de este análisis.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/churn/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003echurn\u003c/strong\u003e de una tabla es la medida de cuánto cambian sus datos después de la inserción. Una tabla con alto churn sufre frecuentes UPDATE y DELETE; una tabla con bajo churn es predominantemente append-only (solo INSERT).\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn PostgreSQL, cada UPDATE crea una nueva versión de la fila (debido al modelo MVCC) y la versión antigua se convierte en una dead tuple. Los DELETE también crean dead tuples. Cuanto mayor es el churn, más trabajo deben hacer VACUUM y los índices para mantener el rendimiento. Un índice GIN en una tabla de alto churn puede degradar significativamente el rendimiento de escritura.\u003c/p\u003e","title":"Churn"},{"content":"La clave subrogada (surrogate key) es un identificador numérico secuencial generado internamente por el data warehouse, sin ningún significado de negocio. Es distinta de la clave natural — la que proviene del sistema fuente (ej. el código de cliente, el número de empleado).\nPor qué es necesaria #En la SCD Tipo 2, el mismo cliente puede tener múltiples filas en la tabla dimensional — una por cada versión histórica. La clave natural (cliente_id) ya no es única, así que se necesita un identificador que distinga cada versión individual: la clave subrogada (cliente_key).\nCómo funciona #Se genera típicamente con una sequence (Oracle) o una columna SERIAL/IDENTITY (PostgreSQL, MySQL). Nunca se expone a los usuarios finales y no tiene significado fuera del data warehouse.\nLa tabla de hechos usa la clave subrogada como clave foránea, apuntando a la versión específica de la dimensión que era vigente en el momento del hecho. Esto garantiza que cada transacción esté asociada al contexto dimensional correcto para ese momento en el tiempo.\nVentajas # Permite el versionado de las dimensiones (SCD Tipo 2) Los joins entre hechos y dimensiones son sobre enteros, por lo tanto rápidos Aísla el DWH de los cambios en las claves de los sistemas fuente Soporta la carga desde múltiples fuentes con claves naturales potencialmente duplicadas ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/chiave-surrogata/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eclave subrogada\u003c/strong\u003e (surrogate key) es un identificador numérico secuencial generado internamente por el data warehouse, sin ningún significado de negocio. Es distinta de la clave natural — la que proviene del sistema fuente (ej. el código de cliente, el número de empleado).\u003c/p\u003e\n\u003ch2 id=\"por-qué-es-necesaria\" class=\"relative group\"\u003ePor qué es necesaria \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#por-qu%c3%a9-es-necesaria\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn la SCD Tipo 2, el mismo cliente puede tener múltiples filas en la tabla dimensional — una por cada versión histórica. La clave natural (\u003ccode\u003ecliente_id\u003c/code\u003e) ya no es única, así que se necesita un identificador que distinga cada versión individual: la clave subrogada (\u003ccode\u003ecliente_key\u003c/code\u003e).\u003c/p\u003e","title":"Clave subrogada"},{"content":"COALESCE es una función SQL estándar que acepta una lista de expresiones y devuelve la primera que no es NULL. Si todas las expresiones son NULL, devuelve NULL.\nSintaxis #COALESCE(expresion1, expresion2, expresion3, ...) Equivale a una cadena de CASE WHEN:\nCASE WHEN expresion1 IS NOT NULL THEN expresion1 WHEN expresion2 IS NOT NULL THEN expresion2 WHEN expresion3 IS NOT NULL THEN expresion3 ELSE NULL END Uso en las jerarquías #En el contexto de las ragged hierarchies, COALESCE se usa a menudo para rellenar los niveles faltantes:\nCOALESCE(top_group_name, group_name, client_name) AS top_group_name Esto funciona como workaround en los reportes, pero tiene limitaciones importantes: debe repetirse en cada consulta, no distingue los valores originales de los de fallback, y complica el código.\nAlternativas por base de datos # Oracle: NVL(a, b) para dos valores, COALESCE para más de dos MySQL: IFNULL(a, b) para dos valores, COALESCE para más de dos PostgreSQL: solo COALESCE (SQL estándar) Enfoque recomendado en el DWH #En un data warehouse, es preferible usar COALESCE en el ETL para poblar la tabla dimensional con valores NOT NULL (self-parenting), en lugar de usarla repetidamente en los reportes. La lógica de gestión de NULLs debe estar en el modelo, no en la presentación.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/coalesce/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eCOALESCE\u003c/strong\u003e es una función SQL estándar que acepta una lista de expresiones y devuelve la primera que no es NULL. Si todas las expresiones son NULL, devuelve NULL.\u003c/p\u003e\n\u003ch2 id=\"sintaxis\" class=\"relative group\"\u003eSintaxis \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#sintaxis\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eCOALESCE\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e...)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eEquivale a una cadena de CASE WHEN:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eCASE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eIS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion1\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e     \u003c/span\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eIS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e     \u003c/span\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eIS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexpresion3\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e     \u003c/span\u003e\u003cspan class=\"k\"\u003eELSE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eEND\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"uso-en-las-jerarquías\" class=\"relative group\"\u003eUso en las jerarquías \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#uso-en-las-jerarqu%c3%adas\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn el contexto de las ragged hierarchies, COALESCE se usa a menudo para rellenar los niveles faltantes:\u003c/p\u003e","title":"COALESCE"},{"content":"La Code Review es la práctica por la cual un colega examina el código escrito por otro desarrollador antes de que se incorpore al branch principal. En GitHub ocurre dentro de las Pull Requests.\nCómo funciona #El desarrollador abre una Pull Request con sus cambios. Un reviewer asignado examina el diff del código, deja comentarios, sugiere mejoras y finalmente aprueba o solicita cambios. El proceso es asíncrono: no hacen falta reuniones, la revisión ocurre en la herramienta. Solo después de la aprobación el código se fusiona en el branch principal.\nPara qué sirve #La code review captura bugs que los tests automáticos no encuentran, mejora la calidad del código, y — aspecto frecuentemente subestimado — difunde el conocimiento del codebase en el equipo. Si solo una persona conoce un módulo y se va, el proyecto tiene un problema. Con las code reviews, al menos dos personas conocen cada pieza de código.\nCuándo se usa #En cada Pull Request, sin excepciones. No es una formalidad: es una inversión en calidad. El tiempo gastado en review es siempre menor que el tiempo que se gastaría corrigiendo bugs en producción descubiertos demasiado tarde.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/code-review/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eCode Review\u003c/strong\u003e es la práctica por la cual un colega examina el código escrito por otro desarrollador antes de que se incorpore al branch principal. En GitHub ocurre dentro de las Pull Requests.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl desarrollador abre una Pull Request con sus cambios. Un reviewer asignado examina el diff del código, deja comentarios, sugiere mejoras y finalmente aprueba o solicita cambios. El proceso es asíncrono: no hacen falta reuniones, la revisión ocurre en la herramienta. Solo después de la aprobación el código se fusiona en el branch principal.\u003c/p\u003e","title":"Code Review"},{"content":"La Compliance (cumplimiento normativo) es la adhesión de una organización a las leyes, regulaciones y estándares del sector aplicables a su actividad. En el contexto AI, incluye GDPR, regulaciones bancarias (SOX, PCI-DSS), normativas sanitarias y políticas internas sobre el uso de datos.\nCómo funciona #La compliance se verifica a través de auditorías, controles documentales y monitorización continua. Para los proyectos AI, requiere la trazabilidad de los datos usados para el training, la documentación de las decisiones automatizadas y la capacidad de explicar cómo el modelo llegó a un determinado output (explainability).\nPara qué sirve #Garantiza que la organización opere dentro de los límites legales y regulatorios. En un proyecto AI, la compliance no es opcional — es una restricción de diseño. Un modelo entrenado con datos sujetos a GDPR sin consentimiento no es solo un riesgo técnico, es una infracción.\nPor qué es crítico #En el triángulo Governance-Compliance-Automatización, la compliance es el vértice que nunca puede sacrificarse. El AI Manager debe garantizar que cada automatización respete las restricciones normativas — y esto requiere una comprensión profunda tanto de la tecnología como del contexto regulatorio. No basta que la IA funcione: debe funcionar dentro de las reglas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/compliance/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eCompliance\u003c/strong\u003e (cumplimiento normativo) es la adhesión de una organización a las leyes, regulaciones y estándares del sector aplicables a su actividad. En el contexto AI, incluye GDPR, regulaciones bancarias (SOX, PCI-DSS), normativas sanitarias y políticas internas sobre el uso de datos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa compliance se verifica a través de auditorías, controles documentales y monitorización continua. Para los proyectos AI, requiere la trazabilidad de los datos usados para el training, la documentación de las decisiones automatizadas y la capacidad de explicar cómo el modelo llegó a un determinado output (explainability).\u003c/p\u003e","title":"Compliance"},{"content":"CTAS (Create Table As Select) es un comando SQL Oracle que crea una nueva tabla y la puebla en una única operación con los resultados de un SELECT. Es la técnica estándar para migrar datos de una estructura a otra en tablas de gran tamaño.\nCómo funciona #El comando combina DDL y DML: crea la tabla con la estructura derivada del SELECT e inserta los datos en un solo paso. Con el hint PARALLEL y el modo NOLOGGING, la copia de cientos de GB puede completarse en pocas horas. Después de la copia, se renombra la tabla original, se renombra la nueva, y el downtime se limita a los pocos segundos del rename.\nPara qué sirve #CTAS es fundamental cuando se necesita reestructurar una tabla sin poder usar ALTER TABLE directamente — por ejemplo, añadir partitioning a una tabla existente con miles de millones de filas. Permite trabajar en la nueva estructura mientras el sistema está activo en la antigua.\nCuándo se usa #Se usa para migraciones a tablas particionadas, reorganización de datos fragmentados, y creación de copias de tablas con estructuras diferentes. En producción, debe combinarse siempre con NOLOGGING (para reducir los redo logs) y seguirse de un backup RMAN inmediato.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/ctas/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eCTAS\u003c/strong\u003e (Create Table As Select) es un comando SQL Oracle que crea una nueva tabla y la puebla en una única operación con los resultados de un SELECT. Es la técnica estándar para migrar datos de una estructura a otra en tablas de gran tamaño.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl comando combina DDL y DML: crea la tabla con la estructura derivada del SELECT e inserta los datos en un solo paso. Con el hint \u003ccode\u003ePARALLEL\u003c/code\u003e y el modo \u003ccode\u003eNOLOGGING\u003c/code\u003e, la copia de cientos de GB puede completarse en pocas horas. Después de la copia, se renombra la tabla original, se renombra la nueva, y el downtime se limita a los pocos segundos del rename.\u003c/p\u003e","title":"CTAS"},{"content":"El cutover es el momento en que un sistema de produccion se traslada de la vieja infraestructura a la nueva. Es la fase mas visible de una migracion — la que todos recuerdan, para bien o para mal.\nAnatomia de un cutover #Un cutover bien planificado sigue un runbook detallado con pasos numerados, tiempos estimados, criterios de exito y procedimientos de rollback para cada paso. Los componentes tipicos:\nStop aplicativo — cierre de conexiones y verificacion de que ninguna sesion esta activa Sincronizacion final — en una migracion Data Guard, verificacion de que transport lag y apply lag estan a cero Switchover/migracion — la operacion tecnica que transfiere el servicio Validacion — pruebas de conectividad, consultas de verificacion, pruebas funcionales Apertura gradual — readmision progresiva de los usuarios Downtime y ventanas #El downtime de un cutover es el tiempo entre la desconexion del ultimo usuario y la reconexion del primero. Con Data Guard switchover, el downtime puede ser del orden de minutos. Con Data Pump, puede ser de horas o dias.\nLa ventana de cutover se planifica en los momentos de menor utilizacion: noches, fines de semana, festivos. Pero \u0026ldquo;menor utilizacion\u0026rdquo; no significa \u0026ldquo;cero utilizacion\u0026rdquo; — en empresas manufactureras con turnos 24/7, no existe un momento en que la base de datos no la necesite nadie.\nRollback #Todo cutover debe tener un plan de rollback. Con Data Guard, el rollback es un segundo switchover — relativamente sencillo. Con Data Pump, el rollback significa reiniciar la base de datos original y aceptar la perdida de las transacciones ocurridas despues del inicio de la migracion. La calidad del plan de rollback es inversamente proporcional a la probabilidad de necesitarlo — pero cuidado con no tenerlo.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/cutover/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003ecutover\u003c/strong\u003e es el momento en que un sistema de produccion se traslada de la vieja infraestructura a la nueva. Es la fase mas visible de una migracion — la que todos recuerdan, para bien o para mal.\u003c/p\u003e\n\u003ch2 id=\"anatomia-de-un-cutover\" class=\"relative group\"\u003eAnatomia de un cutover \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#anatomia-de-un-cutover\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn cutover bien planificado sigue un runbook detallado con pasos numerados, tiempos estimados, criterios de exito y procedimientos de rollback para cada paso. Los componentes tipicos:\u003c/p\u003e","title":"Cutover"},{"content":"El Daily Standup es una reunión diaria breve (máximo 15 minutos) donde cada miembro del equipo responde a tres preguntas: qué hice ayer, qué haré hoy, hay algo que me bloquea. El propósito es sincronizar al equipo, no resolver problemas.\nCómo funciona #Cada persona tiene aproximadamente dos minutos para su actualización. Los problemas se señalan pero no se discuten: la resolución ocurre después, entre las personas involucradas. La restricción temporal es lo que hace efectivo el standup — sin ella, degenera en una reunión de estado de 45 minutos.\nPara qué sirve #Mantiene al equipo alineado sobre el estado del proyecto, hace emerger los bloqueos antes de que se vuelvan críticos y crea un ritmo diario que da estructura al trabajo. Un standup bien gestionado reemplaza decenas de emails y mensajes de Slack.\nQué puede salir mal #El patrón de degeneración es predecible: la primera semana dura 15 minutos, la tercera 35, la cuarta el equipo empieza a saltárselo. Las causas más comunes son los \u0026ldquo;thread killers\u0026rdquo; (discusiones técnicas entre dos personas mientras los demás esperan), demos improvisados y managers que hacen preguntas de profundización.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/daily-standup/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eDaily Standup\u003c/strong\u003e es una reunión diaria breve (máximo 15 minutos) donde cada miembro del equipo responde a tres preguntas: qué hice ayer, qué haré hoy, hay algo que me bloquea. El propósito es sincronizar al equipo, no resolver problemas.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada persona tiene aproximadamente dos minutos para su actualización. Los problemas se señalan pero no se discuten: la resolución ocurre después, entre las personas involucradas. La restricción temporal es lo que hace efectivo el standup — sin ella, degenera en una reunión de estado de 45 minutos.\u003c/p\u003e","title":"Daily Standup"},{"content":"La Data Governance es el conjunto de políticas, procesos, roles y estándares que una organización adopta para garantizar que sus datos sean precisos, seguros, conformes a las normativas y utilizados de forma coherente.\nCómo funciona #Define quién es responsable de los datos (data owner, data steward), qué reglas de calidad aplicar, cómo clasificar los datos por sensibilidad y cómo rastrear su procedencia (data lineage). En un contexto AI, incluye también la verificación de la procedencia y calidad de los datos usados para el training de los modelos.\nPara qué sirve #Sin data governance, una organización no sabe qué datos tiene, dónde están, quién puede acceder y si son fiables. En proyectos con componentes AI, la governance es el prerequisito para evitar que los modelos sean entrenados con datos sucios, no autorizados o sujetos a restricciones normativas como el GDPR.\nPor qué es crítico #En cada proyecto AI en ámbito regulado, el triángulo Governance-Compliance-Automatización debe mantenerse en equilibrio. Una automatización AI eficiente que viola las políticas de data governance es un riesgo. Una governance perfecta que bloquea la automatización detiene el proyecto. El AI Manager mantiene en equilibrio estos tres vértices.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/data-governance/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eData Governance\u003c/strong\u003e es el conjunto de políticas, procesos, roles y estándares que una organización adopta para garantizar que sus datos sean precisos, seguros, conformes a las normativas y utilizados de forma coherente.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eDefine quién es responsable de los datos (data owner, data steward), qué reglas de calidad aplicar, cómo clasificar los datos por sensibilidad y cómo rastrear su procedencia (data lineage). En un contexto AI, incluye también la verificación de la procedencia y calidad de los datos usados para el training de los modelos.\u003c/p\u003e","title":"Data Governance"},{"content":"Data Guard es la tecnologia Oracle que mantiene una o mas copias sincronizadas (standby) de una base de datos de produccion (primario). El standby recibe y aplica continuamente los redo logs generados por el primario, manteniendose alineado en tiempo real o casi.\nComo funciona #El primario genera redo logs con cada transaccion. Estos logs se transmiten al standby por red, donde se aplican de dos formas posibles:\nPhysical standby: aplica los redo a nivel de bloque (replica exacta, byte a byte) Logical standby: reconstruye las instrucciones SQL desde los redo y las rejecuta En caso de fallo del primario, el standby puede convertirse en el nuevo primario mediante switchover (planificado) o failover (de emergencia).\nActive Data Guard #La variante Active Data Guard permite abrir el standby en modo solo lectura mientras sigue aplicando los redo. Esto permite usarlo para informes, backups y consultas analiticas, aligerando la carga del primario.\nModos de proteccion # Modo Comportamiento Perdida de datos MaxPerformance Replica asincrona, sin impacto en el rendimiento del primario Posible (pocos segundos) MaxAvailability Replica sincrona, degrada a MaxPerformance si el standby no es alcanzable Cero en condiciones normales MaxProtection Replica sincrona, el primario se detiene si el standby no confirma Cero garantizado ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/data-guard/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eData Guard\u003c/strong\u003e es la tecnologia Oracle que mantiene una o mas copias sincronizadas (standby) de una base de datos de produccion (primario). El standby recibe y aplica continuamente los redo logs generados por el primario, manteniendose alineado en tiempo real o casi.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl primario genera redo logs con cada transaccion. Estos logs se transmiten al standby por red, donde se aplican de dos formas posibles:\u003c/p\u003e","title":"Data Guard"},{"content":"Un Data Warehouse (DWH) es un sistema de almacenamiento de datos diseñado específicamente para el análisis, el reporting y el soporte a las decisiones empresariales. A diferencia de las bases de datos operacionales (OLTP), un DWH recopila datos de múltiples fuentes, los transforma y los organiza en estructuras optimizadas para consultas analíticas.\nCómo funciona #Los datos se extraen de los sistemas fuente (gestionales, CRM, ERP), se transforman mediante procesos ETL que los limpian, normalizan y enriquecen, y finalmente se cargan en el DWH. El modelo de datos típico es el star schema: una fact table central con las medidas numéricas conectada a tablas dimensionales que describen el contexto (tiempo, cliente, producto, geografía).\nPara qué sirve #Un DWH permite responder a preguntas de negocio que los sistemas operacionales no pueden gestionar: tendencias históricas, análisis comparativos entre períodos, agregaciones cross-system, KPIs empresariales. Separa la carga analítica de la transaccional, evitando que las queries de reporting impacten el rendimiento de las aplicaciones operativas.\nCuándo se usa #Un DWH es necesario cuando una empresa necesita integrar datos de fuentes diversas para producir análisis consolidados. La complejidad y los costes dependen del número de sistemas fuente, el volumen de datos y la frecuencia de actualización requerida.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/data-warehouse/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eData Warehouse\u003c/strong\u003e (DWH) es un sistema de almacenamiento de datos diseñado específicamente para el análisis, el reporting y el soporte a las decisiones empresariales. A diferencia de las bases de datos operacionales (OLTP), un DWH recopila datos de múltiples fuentes, los transforma y los organiza en estructuras optimizadas para consultas analíticas.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLos datos se extraen de los sistemas fuente (gestionales, CRM, ERP), se transforman mediante procesos ETL que los limpian, normalizan y enriquecen, y finalmente se cargan en el DWH. El modelo de datos típico es el star schema: una fact table central con las medidas numéricas conectada a tablas dimensionales que describen el contexto (tiempo, cliente, producto, geografía).\u003c/p\u003e","title":"Data Warehouse"},{"content":"Un Dead Tuple es una fila en una tabla PostgreSQL que ha sido actualizada (UPDATE) o eliminada (DELETE) pero aún no ha sido removida físicamente. Permanece en las páginas de datos, ocupando espacio en disco y ralentizando los escaneos.\nCómo funciona #Cuando PostgreSQL ejecuta un UPDATE, no sobrescribe la fila original: crea una nueva versión y marca la antigua como \u0026ldquo;muerta.\u0026rdquo; La fila antigua permanece físicamente en la página de datos hasta que VACUUM la limpia. Los dead tuples son el precio del modelo MVCC — necesarios para garantizar el aislamiento transaccional.\nPara qué sirve #Los dead tuples son un indicador clave de la salud de una tabla. La vista pg_stat_user_tables muestra n_dead_tup y last_autovacuum — si los dead tuples crecen más rápido de lo que el autovacuum puede limpiar, la tabla tiene un problema. Un dead_tuple_percent por encima del 20-30% es una señal de alarma.\nQué puede salir mal #En una tabla con 500.000 updates al día y los valores por defecto del autovacuum (scale_factor 0.2), VACUUM se activa cada 4 días. Mientras tanto los dead tuples se acumulan, las tablas se hinchan y las queries se ralentizan progresivamente — el patrón \u0026ldquo;lunes bien, viernes desastre\u0026rdquo;.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/dead-tuple/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eDead Tuple\u003c/strong\u003e es una fila en una tabla PostgreSQL que ha sido actualizada (UPDATE) o eliminada (DELETE) pero aún no ha sido removida físicamente. Permanece en las páginas de datos, ocupando espacio en disco y ralentizando los escaneos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando PostgreSQL ejecuta un UPDATE, no sobrescribe la fila original: crea una nueva versión y marca la antigua como \u0026ldquo;muerta.\u0026rdquo; La fila antigua permanece físicamente en la página de datos hasta que VACUUM la limpia. Los dead tuples son el precio del modelo MVCC — necesarios para garantizar el aislamiento transaccional.\u003c/p\u003e","title":"Dead Tuple"},{"content":"DEFAULT PRIVILEGES es un mecanismo de PostgreSQL que permite definir con antelación los privilegios que se asignarán automáticamente a todos los objetos futuros creados en un schema. Se configura con el comando ALTER DEFAULT PRIVILEGES.\nCómo funciona #El comando ALTER DEFAULT PRIVILEGES IN SCHEMA schema1 GRANT SELECT ON TABLES TO srv_monitoreo hace que cada nueva tabla creada en schema1 sea automáticamente legible por srv_monitoreo. Sin esta configuración, las tablas futuras requerirían un GRANT manual cada vez.\nPara qué sirve #Es la parte que la mayoría de los administradores olvida al crear usuarios de solo lectura. Los GRANT sobre ALL TABLES IN SCHEMA cubren solo las tablas existentes. Las tablas creadas después requieren nuevos GRANT — a menos que se usen los DEFAULT PRIVILEGES. Sin ellos, el usuario de monitoreo deja de funcionar con la primera tabla nueva.\nQué puede salir mal #Los DEFAULT PRIVILEGES aplican al ROLE que crea los objetos. Si en un schema varios usuarios crean tablas, los default privileges deben configurarse para cada creador. Este detalle causa frecuentemente errores difíciles de diagnosticar: \u0026ldquo;el GRANT está, pero la nueva tabla no es legible.\u0026rdquo;\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/default-privileges/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eDEFAULT PRIVILEGES\u003c/strong\u003e es un mecanismo de PostgreSQL que permite definir con antelación los privilegios que se asignarán automáticamente a todos los objetos futuros creados en un schema. Se configura con el comando \u003ccode\u003eALTER DEFAULT PRIVILEGES\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl comando \u003ccode\u003eALTER DEFAULT PRIVILEGES IN SCHEMA schema1 GRANT SELECT ON TABLES TO srv_monitoreo\u003c/code\u003e hace que cada nueva tabla creada en \u003ccode\u003eschema1\u003c/code\u003e sea automáticamente legible por \u003ccode\u003esrv_monitoreo\u003c/code\u003e. Sin esta configuración, las tablas futuras requerirían un GRANT manual cada vez.\u003c/p\u003e","title":"DEFAULT PRIVILEGES"},{"content":"default_statistics_target es el parametro PostgreSQL que define el numero de muestras recopiladas por el comando ANALYZE para construir las estadisticas de cada columna. El valor por defecto es 100.\nComo funciona #PostgreSQL muestrea un cierto numero de valores por cada columna y los usa para construir dos estructuras:\nMost common values (MCV): la lista de los valores mas frecuentes, con sus respectivas frecuencias Histograma: la distribucion de los valores restantes, dividida en buckets de igual poblacion El parametro default_statistics_target determina cuantos elementos tendran estas estructuras. Con el valor 100 (por defecto), el histograma tendra 100 buckets y la lista MCV contendra hasta 100 valores.\nCuando aumentarlo #Para tablas pequenas o con distribucion uniforme, 100 muestras son suficientes. Para tablas grandes con distribucion asimetrica (skewed) — donde pocos valores dominan la mayoria de las filas — 100 muestras pueden dar una representacion distorsionada, llevando al optimizer a estimaciones de cardinalidad erroneas.\nSe puede aumentar el target a nivel de columna individual:\nALTER TABLE orders ALTER COLUMN status SET STATISTICS 500; ANALYZE orders; Valores entre 500 y 1000 mejoran sensiblemente la calidad de las estimaciones en columnas con distribucion no uniforme.\nLimites practicos #Por encima de 1000 el beneficio es marginal y el ANALYZE mismo se vuelve mas lento, porque necesita muestrear mas filas y construir estructuras mas grandes. Es un ajuste fino: hay que aplicarlo solo a las columnas que efectivamente causan estimaciones erroneas, no a todas las columnas de todas las tablas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/postgresql-default-statistics-target/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003edefault_statistics_target\u003c/strong\u003e es el parametro PostgreSQL que define el numero de muestras recopiladas por el comando \u003ccode\u003eANALYZE\u003c/code\u003e para construir las estadisticas de cada columna. El valor por defecto es 100.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePostgreSQL muestrea un cierto numero de valores por cada columna y los usa para construir dos estructuras:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMost common values (MCV)\u003c/strong\u003e: la lista de los valores mas frecuentes, con sus respectivas frecuencias\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eHistograma\u003c/strong\u003e: la distribucion de los valores restantes, dividida en buckets de igual poblacion\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eEl parametro \u003ccode\u003edefault_statistics_target\u003c/code\u003e determina cuantos elementos tendran estas estructuras. Con el valor 100 (por defecto), el histograma tendra 100 buckets y la lista MCV contendra hasta 100 valores.\u003c/p\u003e","title":"default_statistics_target"},{"content":"La Directiva 2011/7/UE es la normativa europea sobre morosidad en las transacciones comerciales. Establece reglas claras: plazo estándar de 30 días, máximo 60 entre empresas (con acuerdo explícito), 30 para la administración pública, e intereses de demora automáticos al tipo BCE + 8%.\nCómo funciona #La directiva fue transpuesta al derecho italiano mediante el D.Lgs. 231/2002 (modificado en 2012). Sobre el papel las reglas existen: 30 días estándar, intereses automáticos, compensación forfetaria de 40€ por factura pagada con retraso. En la práctica italiana es como si no existieran — el DSO medio italiano es de 80 días, muy por encima del máximo de 60.\nPara qué sirve #Debería proteger a los proveedores — especialmente pequeñas empresas y freelancers — de la morosidad estructural. En países como Alemania (DSO 24 días) y Países Bajos (DSO 27 días) la directiva funciona. En Italia la brecha entre norma y realidad es abismal.\nPor qué es crítico #La directiva demuestra que el problema de la morosidad en Italia no es legislativo — las leyes existen. Es cultural y estructural: el coste reputacional de hacer valer los propios derechos supera el beneficio económico, y el sistema se sostiene sobre la docilidad del acreedor.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/direttiva-2011-7-ue/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eDirectiva 2011/7/UE\u003c/strong\u003e es la normativa europea sobre morosidad en las transacciones comerciales. Establece reglas claras: plazo estándar de 30 días, máximo 60 entre empresas (con acuerdo explícito), 30 para la administración pública, e intereses de demora automáticos al tipo BCE + 8%.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa directiva fue transpuesta al derecho italiano mediante el D.Lgs. 231/2002 (modificado en 2012). Sobre el papel las reglas existen: 30 días estándar, intereses automáticos, compensación forfetaria de 40€ por factura pagada con retraso. En la práctica italiana es como si no existieran — el DSO medio italiano es de 80 días, muy por encima del máximo de 60.\u003c/p\u003e","title":"Directiva 2011/7/UE"},{"content":"El drill-down es la operación de navegación en reportes que permite pasar de un nivel agregado a un nivel de mayor detalle, descendiendo por una jerarquía.\nCómo funciona #En una jerarquía Top Group → Group → Client:\nSe parte del nivel más alto: facturación total por Top Group Se hace clic en un Top Group para ver sus Groups (drill-down de primer nivel) Se hace clic en un Group para ver los Clients individuales (drill-down de segundo nivel) La operación inversa — subir del detalle al agregado — se llama drill-up (o roll-up).\nRequisitos para un drill-down correcto #Para funcionar sin errores, el drill-down requiere:\nUna jerarquía completa: ningún nivel faltante (sin NULLs) Coherencia de totales: la suma de los valores a nivel de detalle debe corresponder al total del nivel superior Estructura balanceada: todas las ramas de la jerarquía deben tener la misma profundidad Si la jerarquía está desequilibrada (ragged hierarchy), el drill-down produce resultados incompletos o erróneos. El self-parenting resuelve esto balanceando la estructura aguas arriba.\nDrill-down vs filtro #El drill-down no es un simple filtro: es una navegación estructurada a lo largo de una jerarquía predefinida. Un filtro muestra un subconjunto de datos; un drill-down muestra el siguiente nivel de detalle dentro de un contexto jerárquico.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/drill-down/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003edrill-down\u003c/strong\u003e es la operación de navegación en reportes que permite pasar de un nivel agregado a un nivel de mayor detalle, descendiendo por una jerarquía.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn una jerarquía Top Group → Group → Client:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eSe parte del nivel más alto: facturación total por Top Group\u003c/li\u003e\n\u003cli\u003eSe hace clic en un Top Group para ver sus Groups (drill-down de primer nivel)\u003c/li\u003e\n\u003cli\u003eSe hace clic en un Group para ver los Clients individuales (drill-down de segundo nivel)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eLa operación inversa — subir del detalle al agregado — se llama \u003cstrong\u003edrill-up\u003c/strong\u003e (o roll-up).\u003c/p\u003e","title":"Drill-down"},{"content":"El DSO (Days Sales Outstanding) es la métrica que mide el número medio de días que una empresa tarda en cobrar sus créditos tras la emisión de la factura. Es el indicador principal de la velocidad de pago en un mercado.\nCómo funciona #Se calcula como: (Créditos comerciales / Facturación) × Días del periodo. Un DSO de 30 significa que en promedio los clientes pagan en un mes. En Italia el DSO medio es de 80 días según el European Payment Report — casi tres veces la media del norte de Europa (24-27 días).\nPara qué sirve #Para un consultor freelance, el DSO determina la necesidad de capital circulante. Con un DSO de 90 días y una facturación de 5.500€/mes, se necesitan al menos 16.500€ de reserva para cubrir los primeros tres meses sin cobros. Sin reserva, el consultor está financiando a su cliente a coste cero.\nPor qué es crítico #Italia está fuera de escala respecto a la Directiva UE que fija el plazo máximo en 60 días. Un DSO de 80 días no es solo un problema financiero — es un indicador estructural de un mercado donde el poder de negociación está desequilibrado a favor del cliente.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/dso/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eDSO\u003c/strong\u003e (Days Sales Outstanding) es la métrica que mide el número medio de días que una empresa tarda en cobrar sus créditos tras la emisión de la factura. Es el indicador principal de la velocidad de pago en un mercado.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSe calcula como: \u003ccode\u003e(Créditos comerciales / Facturación) × Días del periodo\u003c/code\u003e. Un DSO de 30 significa que en promedio los clientes pagan en un mes. En Italia el DSO medio es de 80 días según el European Payment Report — casi tres veces la media del norte de Europa (24-27 días).\u003c/p\u003e","title":"DSO"},{"content":"ETL (Extract, Transform, Load) es el proceso fundamental a traves del cual los datos se mueven desde los sistemas fuente (bases de datos operacionales, archivos, APIs) al data warehouse.\nLas tres fases # Extract: extraccion de datos de los sistemas fuente. Puede ser completa (full load) o incremental (solo datos nuevos o modificados) Transform: limpieza, validacion, estandarizacion y enriquecimiento de los datos. Aqui se aplican las reglas de negocio, las lookup sobre las dimensiones, los calculos derivados Load: carga de los datos transformados en las tablas del data warehouse (fact y dimension) Por que es critico #El ETL es la parte menos visible pero mas critica de un data warehouse. Si los datos se extraen de forma incompleta, se transforman con reglas erroneas o se cargan sin controles, todo lo que esta encima — reportes, dashboards, decisiones — sera incorrecto.\nUn ETL bien disenado tambien determina la ventana de carga: cuanto tiempo se necesita para actualizar el data warehouse. En entornos reales, pasar de 4 horas a 25 minutos puede hacer la diferencia entre datos actualizados por la manana o por la tarde.\nELT vs ETL #Con la llegada de los data warehouses cloud y los motores columnares de alto rendimiento, se ha difundido el patron ELT (Extract, Load, Transform): los datos se cargan sin procesar en el warehouse y se transforman directamente alli, aprovechando la potencia de calculo del motor SQL. El concepto de fondo es el mismo, lo que cambia es donde ocurre la transformacion.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/etl/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eETL\u003c/strong\u003e (Extract, Transform, Load) es el proceso fundamental a traves del cual los datos se mueven desde los sistemas fuente (bases de datos operacionales, archivos, APIs) al data warehouse.\u003c/p\u003e\n\u003ch2 id=\"las-tres-fases\" class=\"relative group\"\u003eLas tres fases \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#las-tres-fases\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eExtract\u003c/strong\u003e: extraccion de datos de los sistemas fuente. Puede ser completa (full load) o incremental (solo datos nuevos o modificados)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTransform\u003c/strong\u003e: limpieza, validacion, estandarizacion y enriquecimiento de los datos. Aqui se aplican las reglas de negocio, las lookup sobre las dimensiones, los calculos derivados\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLoad\u003c/strong\u003e: carga de los datos transformados en las tablas del data warehouse (fact y dimension)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"por-que-es-critico\" class=\"relative group\"\u003ePor que es critico \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#por-que-es-critico\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl ETL es la parte menos visible pero mas critica de un data warehouse. Si los datos se extraen de forma incompleta, se transforman con reglas erroneas o se cargan sin controles, todo lo que esta encima — reportes, dashboards, decisiones — sera incorrecto.\u003c/p\u003e","title":"ETL"},{"content":"El Exchange Partition es una operación DDL de Oracle que permite intercambiar instantáneamente el contenido de una partición con el de una tabla no particionada. No se mueve ni un solo byte de datos — la operación solo modifica los punteros en el data dictionary.\nCómo funciona #El comando ALTER TABLE ... EXCHANGE PARTITION ... WITH TABLE ... modifica los metadatos en el data dictionary de modo que los segmentos físicos de la partición y de la tabla de staging intercambien su propiedad. La tabla de staging se convierte en la partición y viceversa. La operación dura menos de un segundo independientemente del volumen de datos, porque no implica ningún movimiento físico.\nPara qué sirve #En los data warehouses, el exchange partition es la herramienta principal para la carga masiva de datos. El proceso típico es: el ETL carga los datos en una tabla de staging, construye los índices, valida los datos, y luego ejecuta el exchange con la partición objetivo. Durante el exchange, las queries sobre las demás particiones siguen funcionando sin interrupción.\nQué puede salir mal #La cláusula WITHOUT VALIDATION omite la verificación de que los datos de la staging table caigan realmente dentro del rango de la partición — acelera la operación pero requiere que el ETL garantice la corrección de los datos. Si los datos en la staging contienen fechas fuera de rango, acaban en la partición equivocada sin generar ningún error. La cláusula INCLUDING INDEXES requiere que la staging table tenga índices con la misma estructura que los índices locales de la tabla particionada.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/exchange-partition/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eExchange Partition\u003c/strong\u003e es una operación DDL de Oracle que permite intercambiar instantáneamente el contenido de una partición con el de una tabla no particionada. No se mueve ni un solo byte de datos — la operación solo modifica los punteros en el data dictionary.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl comando \u003ccode\u003eALTER TABLE ... EXCHANGE PARTITION ... WITH TABLE ...\u003c/code\u003e modifica los metadatos en el data dictionary de modo que los segmentos físicos de la partición y de la tabla de staging intercambien su propiedad. La tabla de staging se convierte en la partición y viceversa. La operación dura menos de un segundo independientemente del volumen de datos, porque no implica ningún movimiento físico.\u003c/p\u003e","title":"Exchange Partition"},{"content":"Un execution plan (plan de ejecucion) es la secuencia de operaciones que la base de datos elige para resolver una consulta SQL. Cuando escribes un SELECT con JOINs, filtros WHERE y ordenamientos, el optimizer evalua decenas de estrategias posibles y elige una basandose en las estadisticas disponibles.\nComo funciona #El plan se representa como un arbol de nodos: cada nodo es una operacion (scan, join, sort, aggregate) que recibe datos de sus nodos hijos y los pasa al nodo padre. En PostgreSQL se visualiza con EXPLAIN (plan estimado) o EXPLAIN ANALYZE (plan real con tiempos efectivos y conteos de filas).\nEl optimizer decide para cada nodo que estrategia usar: sequential scan o index scan para el acceso a tablas, nested loop, hash join o merge join para las uniones, sort o hash para los agrupamientos.\nPor que es importante #La lectura correcta de un plan de ejecucion es la competencia mas importante para el tuning de consultas. No basta mirar el tiempo total: hay que comparar las filas estimadas con las reales nodo por nodo, verificar los buffers de I/O e identificar donde el optimizer tomo decisiones incorrectas.\nUna estimacion erronea en un solo nodo puede propagarse en cascada por todo el plan, transformando una consulta de milisegundos en una de minutos.\nQue puede salir mal #Los problemas mas frecuentes en los planes de ejecucion:\nEstimaciones de cardinalidad erroneas: el optimizer piensa que una tabla devuelve 100 filas y llegan 2 millones Join equivocado: un nested loop elegido donde hacia falta un hash join, por estadisticas obsoletas Indice ignorado: un sequential scan sobre una tabla grande porque las estadisticas no reflejan la distribucion real de los datos Spill a disco: operaciones de sort o hash que no caben en work_mem y terminan escribiendo en disco ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/execution-plan/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eexecution plan\u003c/strong\u003e (plan de ejecucion) es la secuencia de operaciones que la base de datos elige para resolver una consulta SQL. Cuando escribes un SELECT con JOINs, filtros WHERE y ordenamientos, el optimizer evalua decenas de estrategias posibles y elige una basandose en las estadisticas disponibles.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl plan se representa como un arbol de nodos: cada nodo es una operacion (scan, join, sort, aggregate) que recibe datos de sus nodos hijos y los pasa al nodo padre. En PostgreSQL se visualiza con \u003ccode\u003eEXPLAIN\u003c/code\u003e (plan estimado) o \u003ccode\u003eEXPLAIN ANALYZE\u003c/code\u003e (plan real con tiempos efectivos y conteos de filas).\u003c/p\u003e","title":"Execution Plan"},{"content":"El Facilitador es la persona encargada de guiar el desarrollo de una reunión. No es quien decide — es quien garantiza que la decisión se tome de manera ordenada, en los tiempos previstos y con la contribución de todos los participantes.\nCómo funciona #El facilitador controla el tiempo, gestiona los turnos de palabra, corta las discusiones fuera de tema (\u0026ldquo;lo anoto en el parking lot, lo hablamos después\u0026rdquo;) y se asegura de que el standup no supere los 15 minutos. El rol puede ser fijo o rotativo en el equipo.\nPara qué sirve #Sin facilitador, las reuniones se expanden naturalmente. Alguien habla más de lo debido, alguien más nunca habla, y los temas se multiplican sin control. El facilitador es el guardián del tiempo de todos — no es autoritario, es respetuoso.\nPor qué es crítico #El mejor facilitador es el que corta con naturalidad: \u0026ldquo;Interesante, lo hablamos justo después. Marco, te toca.\u0026rdquo; Sin esta figura, el standup degenera en tres semanas. La diferencia entre un standup de 15 minutos y uno de 45 es casi siempre la presencia (o ausencia) de un facilitador con firmeza.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/facilitatore/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eFacilitador\u003c/strong\u003e es la persona encargada de guiar el desarrollo de una reunión. No es quien decide — es quien garantiza que la decisión se tome de manera ordenada, en los tiempos previstos y con la contribución de todos los participantes.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl facilitador controla el tiempo, gestiona los turnos de palabra, corta las discusiones fuera de tema (\u0026ldquo;lo anoto en el parking lot, lo hablamos después\u0026rdquo;) y se asegura de que el standup no supere los 15 minutos. El rol puede ser fijo o rotativo en el equipo.\u003c/p\u003e","title":"Facilitador"},{"content":"La fact table (tabla de hechos) es la tabla central de un star schema en el data warehouse. Contiene las medidas numéricas — importes, cantidades, conteos, duraciones — y las claves foráneas que la conectan con las tablas dimensionales.\nEstructura #Cada fila de la fact table representa un evento o una transacción de negocio: una venta, un siniestro, un envío, un acceso. Las columnas se dividen en dos categorías:\nClaves foráneas (foreign keys): apuntan a las tablas dimensionales (quién, qué, dónde, cuándo) Medidas: los valores numéricos a agregar (importe, cantidad, margen) Tipos de fact tables # Transaction fact: una fila por cada evento (ej. cada venta) Periodic snapshot: una fila por período por entidad (ej. saldo mensual por cuenta) Accumulating snapshot: una fila por proceso, actualizada en cada milestone (ej. ciclo pedido-envío-facturación) Relación con las SCD #Cuando las dimensiones usan SCD Tipo 2, la fact table apunta a la clave subrogada de la dimensión — no a la clave natural. Esto garantiza que cada hecho esté asociado a la versión de la dimensión correcta para el momento en que ocurrió.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/fact-table/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003efact table\u003c/strong\u003e (tabla de hechos) es la tabla central de un star schema en el data warehouse. Contiene las medidas numéricas — importes, cantidades, conteos, duraciones — y las claves foráneas que la conectan con las tablas dimensionales.\u003c/p\u003e\n\u003ch2 id=\"estructura\" class=\"relative group\"\u003eEstructura \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#estructura\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada fila de la fact table representa un evento o una transacción de negocio: una venta, un siniestro, un envío, un acceso. Las columnas se dividen en dos categorías:\u003c/p\u003e","title":"Fact table"},{"content":"El Float Financiero es la liquidez que una empresa genera de la diferencia entre los tiempos de cobro de sus clientes (más cortos) y los tiempos de pago a sus proveedores (más largos). Es de hecho un préstamo a coste cero obtenido a expensas de los proveedores.\nCómo funciona #Una empresa de consultoría cobra del cliente final a 30 días pero paga a sus consultores a 90 días. La diferencia de 60 días genera un float: por cada 100.000€ de facturación mensual, la empresa dispone de ~200.000€ de liquidez gratuita que puede invertir o usar como capital circulante.\nPara qué sirve #Para las grandes empresas es una palanca financiera estructural. Para los consultores freelance es el mecanismo perverso por el que se encuentran financiando a sus clientes sin intereses, sin garantías y sin alternativa — porque el mercado \u0026ldquo;funciona así.\u0026rdquo;\nPor qué es crítico #El float financiero es una transferencia de riqueza invisible del proveedor al cliente. Un consultor que trabaja en octubre y cobra en febrero está otorgando un préstamo de cuatro meses. Nadie lo llama así — lo llaman \u0026ldquo;términos contractuales.\u0026rdquo; Pero económicamente es idéntico.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/float-finanziario/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eFloat Financiero\u003c/strong\u003e es la liquidez que una empresa genera de la diferencia entre los tiempos de cobro de sus clientes (más cortos) y los tiempos de pago a sus proveedores (más largos). Es de hecho un préstamo a coste cero obtenido a expensas de los proveedores.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUna empresa de consultoría cobra del cliente final a 30 días pero paga a sus consultores a 90 días. La diferencia de 60 días genera un float: por cada 100.000€ de facturación mensual, la empresa dispone de ~200.000€ de liquidez gratuita que puede invertir o usar como capital circulante.\u003c/p\u003e","title":"Float Financiero"},{"content":"FLUSH PRIVILEGES es un comando MySQL/MariaDB que fuerza al servidor a recargar en memoria las tablas de privilegios desde la base de datos mysql. Hace inmediatamente efectivos los cambios en los permisos.\nCómo funciona #MySQL mantiene en memoria una caché de las tablas de grant (mysql.user, mysql.db, mysql.tables_priv). Cuando se usan CREATE USER y GRANT, MySQL actualiza tanto las tablas como la caché automáticamente. Pero si las tablas de grant se modifican directamente con INSERT, UPDATE o DELETE, la caché no se actualiza. FLUSH PRIVILEGES fuerza la recarga de la caché desde las tablas.\nPara qué sirve #El comando es necesario después de: eliminación directa de usuarios de la tabla mysql.user, cambios manuales de privilegios vía DML, o después de un DROP USER de usuarios anónimos como parte del hardening de seguridad. Sin el FLUSH, los cambios no tienen efecto hasta el próximo reinicio del servidor.\nCuándo se usa #Después de cualquier modificación directa a las tablas de grant. Si se usan exclusivamente CREATE USER, GRANT, REVOKE y DROP USER, el FLUSH no es técnicamente necesario porque estos comandos actualizan la caché automáticamente. Sin embargo, ejecutarlo después de un DROP USER de usuarios anónimos es buena práctica para garantizar la consistencia.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/flush-privileges/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eFLUSH PRIVILEGES\u003c/strong\u003e es un comando MySQL/MariaDB que fuerza al servidor a recargar en memoria las tablas de privilegios desde la base de datos \u003ccode\u003emysql\u003c/code\u003e. Hace inmediatamente efectivos los cambios en los permisos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eMySQL mantiene en memoria una caché de las tablas de grant (\u003ccode\u003emysql.user\u003c/code\u003e, \u003ccode\u003emysql.db\u003c/code\u003e, \u003ccode\u003emysql.tables_priv\u003c/code\u003e). Cuando se usan \u003ccode\u003eCREATE USER\u003c/code\u003e y \u003ccode\u003eGRANT\u003c/code\u003e, MySQL actualiza tanto las tablas como la caché automáticamente. Pero si las tablas de grant se modifican directamente con \u003ccode\u003eINSERT\u003c/code\u003e, \u003ccode\u003eUPDATE\u003c/code\u003e o \u003ccode\u003eDELETE\u003c/code\u003e, la caché no se actualiza. \u003ccode\u003eFLUSH PRIVILEGES\u003c/code\u003e fuerza la recarga de la caché desde las tablas.\u003c/p\u003e","title":"FLUSH PRIVILEGES"},{"content":"Full Table Scan (o TABLE ACCESS FULL) es una operacion en la que la base de datos lee todos los bloques de datos de una tabla, de principio a fin, sin pasar por ningun indice.\nComo funciona #Oracle solicita bloques del disco (o de la cache) en secuencia, usando lecturas multi-bloque (db file scattered read). Cada fila de la tabla es examinada, independientemente de si cumple o no los criterios de la query.\nCuando es un problema #Un full table scan sobre una tabla grande es frecuentemente senal de un indice faltante, estadisticas obsoletas o un plan de ejecucion modificado. En el informe AWR aparece como db file scattered read en la seccion Top Wait Events, con porcentajes elevados de DB time.\nCuando es legitimo #En tablas pequenas (unos pocos miles de filas) o cuando la query realmente necesita leer la mayor parte de los datos, el full table scan puede ser mas eficiente que un acceso por indice. El problema surge cuando Oracle lo elige en tablas con millones de filas para extraer pocos registros.\nComo se identifica #En el plan de ejecucion (EXPLAIN PLAN o DBMS_XPLAN) aparece como operacion TABLE ACCESS FULL. En los wait events de AWR/ASH se manifiesta como db file scattered read dominante.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/full-table-scan/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eFull Table Scan\u003c/strong\u003e (o TABLE ACCESS FULL) es una operacion en la que la base de datos lee todos los bloques de datos de una tabla, de principio a fin, sin pasar por ningun indice.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOracle solicita bloques del disco (o de la cache) en secuencia, usando lecturas multi-bloque (\u003ccode\u003edb file scattered read\u003c/code\u003e). Cada fila de la tabla es examinada, independientemente de si cumple o no los criterios de la query.\u003c/p\u003e","title":"Full Table Scan"},{"content":"Un GIN Index (Generalized Inverted Index) es un tipo de índice PostgreSQL diseñado para indexar valores compuestos: arrays, documentos JSONB, texto con trigramas y búsquedas full-text. A diferencia del B-Tree, un GIN crea un mapping inverso: de cada elemento (palabra, trigrama, clave JSON) a los registros que lo contienen.\nCómo funciona #Para cada valor distinto en el dato indexado, GIN mantiene una lista de punteros a las filas que contienen ese valor. En el caso de pg_trgm, el texto se descompone en trigramas (secuencias de 3 caracteres) y cada trigrama se indexa. Una búsqueda LIKE '%ABC%' se traduce en una intersección de trigramas, evitando el escaneo secuencial.\nPara qué sirve #GIN resuelve el problema de las búsquedas \u0026ldquo;contiene\u0026rdquo; (LIKE '%valor%') en columnas de texto, que con un B-Tree requerirían un escaneo secuencial de toda la tabla. En tablas de millones de filas, la diferencia es entre segundos y milisegundos.\nCuándo se usa #GIN es ideal en tablas append-only o con bajo churn (pocos UPDATE/DELETE), ya que el coste de mantenimiento del índice es más alto que el de un B-Tree. La creación en producción debe hacerse con CREATE INDEX CONCURRENTLY para evitar locks en las escrituras.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/gin-index/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eGIN Index\u003c/strong\u003e (Generalized Inverted Index) es un tipo de índice PostgreSQL diseñado para indexar valores compuestos: arrays, documentos JSONB, texto con trigramas y búsquedas full-text. A diferencia del B-Tree, un GIN crea un mapping inverso: de cada elemento (palabra, trigrama, clave JSON) a los registros que lo contienen.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePara cada valor distinto en el dato indexado, GIN mantiene una lista de punteros a las filas que contienen ese valor. En el caso de \u003ccode\u003epg_trgm\u003c/code\u003e, el texto se descompone en trigramas (secuencias de 3 caracteres) y cada trigrama se indexa. Una búsqueda \u003ccode\u003eLIKE '%ABC%'\u003c/code\u003e se traduce en una intersección de trigramas, evitando el escaneo secuencial.\u003c/p\u003e","title":"GIN Index"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/es/glossary/","section":"Glosario","summary":"","title":"Glosario"},{"content":"El grain (granularidad) es el nivel de detalle de una fact table en un data warehouse. Define qué representa una fila individual: una transacción, un resumen diario, un total mensual, una línea de factura.\nCómo funciona #La elección del grain es la primera decisión al diseñar una fact table. Todas las demás decisiones — medidas, dimensiones, ETL — derivan de ella:\nGrain fino (ej. línea de factura): máxima flexibilidad en consultas, más filas a gestionar Grain agregado (ej. total mensual por cliente): menos filas, consultas más rápidas, pero imposibilidad de bajar al detalle El principio fundamental de Kimball: siempre modelar al nivel de detalle más fino disponible en el sistema fuente.\nPara qué sirve #El grain determina:\nQué preguntas puede responder el data warehouse Qué dimensiones son necesarias (un grain a nivel de línea requiere dim_producto, un grain mensual no) Qué tan grande es la fact table y cuánto dura el ETL Si el drill-down en los reportes es posible o no Cuándo se usa #El grain se define en la fase de diseño del modelo dimensional, antes de escribir cualquier DDL o ETL. Cambiar el grain después del go-live equivale a reconstruir el data warehouse desde cero — razón por la cual la elección inicial es tan crítica.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/grain/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003egrain\u003c/strong\u003e (granularidad) es el nivel de detalle de una fact table en un data warehouse. Define qué representa una fila individual: una transacción, un resumen diario, un total mensual, una línea de factura.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa elección del grain es la primera decisión al diseñar una fact table. Todas las demás decisiones — medidas, dimensiones, ETL — derivan de ella:\u003c/p\u003e","title":"Grain"},{"content":"GRANT es el comando SQL usado para asignar privilegios a un usuario o rol sobre objetos específicos de la base de datos. En MySQL y MariaDB, los privilegios se asignan al par 'usuario'@'host', no solo al nombre de usuario.\nCómo funciona #La sintaxis básica es GRANT \u0026lt;privilegios\u0026gt; ON \u0026lt;base_de_datos\u0026gt;.\u0026lt;tabla\u0026gt; TO 'usuario'@'host'. Los privilegios pueden ser granulares (SELECT, INSERT, UPDATE, DELETE) o globales (ALL PRIVILEGES). En MySQL 8, GRANT ya no crea usuarios implícitamente: se necesita primero un CREATE USER explícito, luego el GRANT. En MySQL 5.7 y MariaDB, GRANT con IDENTIFIED BY crea el usuario y asigna privilegios en un solo comando.\nPara qué sirve #GRANT es el mecanismo fundamental para implementar el control de acceso en bases de datos MySQL/MariaDB. Combinado con el modelo usuario@host, permite calibrar los privilegios según el origen de la conexión: acceso completo desde localhost para el DBA, solo lectura desde el application server.\nCuándo se usa #Cada vez que se crea un usuario o se modifican los permisos. La best practice es asignar siempre el mínimo privilegio necesario (principio del least privilege) y usar SHOW GRANTS FOR 'usuario'@'host' para verificar los privilegios efectivos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/grant/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eGRANT\u003c/strong\u003e es el comando SQL usado para asignar privilegios a un usuario o rol sobre objetos específicos de la base de datos. En MySQL y MariaDB, los privilegios se asignan al par \u003ccode\u003e'usuario'@'host'\u003c/code\u003e, no solo al nombre de usuario.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa sintaxis básica es \u003ccode\u003eGRANT \u0026lt;privilegios\u0026gt; ON \u0026lt;base_de_datos\u0026gt;.\u0026lt;tabla\u0026gt; TO 'usuario'@'host'\u003c/code\u003e. Los privilegios pueden ser granulares (SELECT, INSERT, UPDATE, DELETE) o globales (ALL PRIVILEGES). En MySQL 8, GRANT ya no crea usuarios implícitamente: se necesita primero un \u003ccode\u003eCREATE USER\u003c/code\u003e explícito, luego el GRANT. En MySQL 5.7 y MariaDB, GRANT con \u003ccode\u003eIDENTIFIED BY\u003c/code\u003e crea el usuario y asigna privilegios en un solo comando.\u003c/p\u003e","title":"GRANT"},{"content":"Group Replication es el mecanismo nativo de MySQL para crear clusters de alta disponibilidad con replicación síncrona entre múltiples nodos. A diferencia de la replicación clásica (asíncrona, master-slave), Group Replication garantiza que cada transacción sea confirmada por la mayoría de los nodos antes de considerarse committed.\nCómo funciona #Los nodos se comunican mediante un protocolo de grupo (GCS — Group Communication System) que gestiona el consenso distribuido. Cada nodo mantiene una copia completa de los datos. Las transacciones son certificadas por el grupo: si no hay conflictos, se aplican en todos los nodos. Si hay un conflicto, la transacción se revierte en el nodo que la originó.\nModos operativos #MySQL Group Replication soporta dos modos: single-primary (solo un nodo acepta escrituras, los demás son de solo lectura) y multi-primary (todos los nodos aceptan escrituras). El modo single-primary es el más usado en producción porque evita los conflictos de escritura concurrente.\nPor qué es crítico #Group Replication gestiona automáticamente el failover: si el primary cae, el cluster elige un nuevo primary entre los secondary en pocos segundos. Esto lo hace adecuado para entornos que requieren alta disponibilidad sin intervención manual. Requiere un mínimo de tres nodos para mantener el quórum.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/group-replication/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eGroup Replication\u003c/strong\u003e es el mecanismo nativo de MySQL para crear clusters de alta disponibilidad con replicación síncrona entre múltiples nodos. A diferencia de la replicación clásica (asíncrona, master-slave), Group Replication garantiza que cada transacción sea confirmada por la mayoría de los nodos antes de considerarse committed.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLos nodos se comunican mediante un protocolo de grupo (GCS — Group Communication System) que gestiona el consenso distribuido. Cada nodo mantiene una copia completa de los datos. Las transacciones son certificadas por el grupo: si no hay conflictos, se aplican en todos los nodos. Si hay un conflicto, la transacción se revierte en el nodo que la originó.\u003c/p\u003e","title":"Group Replication"},{"content":"GTID (Global Transaction Identifier) es un identificador único asignado automáticamente a cada transacción confirmada en un servidor MySQL. El formato es server_uuid:transaction_id — por ejemplo 3E11FA47-71CA-11E1-9E33-C80AA9429562:23.\nCómo funciona #Cuando el GTID está habilitado (gtid_mode = ON), cada transacción recibe un identificador que la hace rastreable en cualquier servidor del cluster de replicación. La réplica sabe exactamente qué transacciones ya ejecutó y cuáles necesita recibir, sin necesidad de especificar manualmente posiciones de binlog (archivo + offset).\nEl conjunto de todos los GTID ejecutados en un servidor se almacena en la variable gtid_executed. Cuando una réplica se conecta al origen, compara su propio gtid_executed con el del origen para determinar qué transacciones faltan.\nPara qué sirve #El GTID simplifica radicalmente la gestión de la replicación MySQL:\nFailover automático: cuando el origen cae, una réplica puede convertirse en el nuevo origen y las demás réplicas se realinean automáticamente Verificación de consistencia: es posible verificar si dos servidores han ejecutado exactamente las mismas transacciones Backup y restore: herramientas como mysqldump y mydumper deben gestionar correctamente los GTID para evitar conflictos de replicación después del restore Cuándo crea problemas #Los GTID requieren atención durante las operaciones de backup y restore. Si se restaura un dump en un servidor con GTID activo sin configurar correctamente --set-gtid-purged, se pueden generar conflictos que rompen la cadena de replicación.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/gtid/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eGTID\u003c/strong\u003e (Global Transaction Identifier) es un identificador único asignado automáticamente a cada transacción confirmada en un servidor MySQL. El formato es \u003ccode\u003eserver_uuid:transaction_id\u003c/code\u003e — por ejemplo \u003ccode\u003e3E11FA47-71CA-11E1-9E33-C80AA9429562:23\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando el GTID está habilitado (\u003ccode\u003egtid_mode = ON\u003c/code\u003e), cada transacción recibe un identificador que la hace rastreable en cualquier servidor del cluster de replicación. La réplica sabe exactamente qué transacciones ya ejecutó y cuáles necesita recibir, sin necesidad de especificar manualmente posiciones de binlog (archivo + offset).\u003c/p\u003e","title":"GTID"},{"content":"Hash join es una estrategia de join disenada para grandes volumenes de datos. Funciona en dos fases: primero construye una estructura de datos en memoria, luego la usa para encontrar las correspondencias de forma eficiente.\nComo funciona #La base de datos lee la tabla mas pequena (build side) y construye una hash table en memoria, indexando las filas por la columna de join. Luego escanea la tabla mas grande (probe side) y para cada fila busca la correspondencia en la hash table con un lookup O(1).\nLa complejidad es lineal — proporcional a la suma de las filas de ambas tablas, no al producto como en el nested loop. No se necesitan indices: la hash table sustituye temporalmente al indice.\nCuando es la eleccion correcta #El optimizer elige hash join cuando ambas tablas son grandes y no hay indices utiles, o cuando las estadisticas indican que el numero de filas a combinar es demasiado alto para un nested loop eficiente. Es una de las estrategias mas comunes en data warehouses y reportes que agregan millones de filas.\nQue puede salir mal #El punto debil es la memoria. La hash table debe caber en work_mem: si la tabla mas pequena no cabe, la base de datos escribe lotes en disco (batched hash join), con una degradacion significativa del rendimiento.\nwork_mem demasiado bajo: la hash table se divide en lotes en disco, multiplicando el I/O Estimaciones erroneas: el optimizer elige como build side la tabla equivocada porque las estadisticas indican menos filas de las reales Skew en los datos: si un valor en la columna de join domina la mayoria de las filas, un bucket de la hash table se vuelve enorme mientras los demas quedan vacios ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/hash-join/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eHash join\u003c/strong\u003e es una estrategia de join disenada para grandes volumenes de datos. Funciona en dos fases: primero construye una estructura de datos en memoria, luego la usa para encontrar las correspondencias de forma eficiente.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa base de datos lee la tabla mas pequena (build side) y construye una hash table en memoria, indexando las filas por la columna de join. Luego escanea la tabla mas grande (probe side) y para cada fila busca la correspondencia en la hash table con un lookup O(1).\u003c/p\u003e","title":"Hash Join"},{"content":"El Hot Desk (hot desking) es un modelo de organización de espacios de trabajo donde los escritorios no están asignados a empleados individuales. Quien va a la oficina ocupa un puesto libre, típicamente reservable a través de un sistema digital.\nCómo funciona #En lugar de 50 puestos fijos para 50 empleados, la empresa dispone 15-20 puestos compartidos (hot desks) equipados con monitor, docking station y conectividad. Los empleados reservan el puesto los días que deben ir a la oficina, usando los demás días en smart working.\nPara qué sirve #Reduce drásticamente los costes inmobiliarios: de 50 puestos a 15 se ahorra aproximadamente el 70% del espacio y los costes asociados (alquiler, suministros, limpieza, mantenimiento). El espacio ahorrado puede convertirse en salas de reuniones adecuadas y áreas colaborativas.\nQué puede salir mal #Sin un sistema de reserva eficiente, surgen conflictos y frustración. Los empleados que no tienen \u0026ldquo;su propio escritorio\u0026rdquo; pueden sentirse menos arraigados en la empresa. La solución es combinar hot desks con espacios personales (taquillas) y áreas de equipo dedicadas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/hot-desk/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eHot Desk\u003c/strong\u003e (hot desking) es un modelo de organización de espacios de trabajo donde los escritorios no están asignados a empleados individuales. Quien va a la oficina ocupa un puesto libre, típicamente reservable a través de un sistema digital.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn lugar de 50 puestos fijos para 50 empleados, la empresa dispone 15-20 puestos compartidos (hot desks) equipados con monitor, docking station y conectividad. Los empleados reservan el puesto los días que deben ir a la oficina, usando los demás días en smart working.\u003c/p\u003e","title":"Hot Desk"},{"content":"Las Huge Pages son páginas de memoria de 2 MB, frente a los 4 KB estándar de Linux. Para una SGA Oracle de 64 GB, pasar de páginas de 4 KB (16,7 millones de páginas) a Huge Pages de 2 MB (32.768 páginas) reduce en 500 veces el número de entradas en la Page Table.\nCómo funciona #Se configuran mediante el parámetro del kernel vm.nr_hugepages en /etc/sysctl.d/. El número necesario se calcula dividiendo el tamaño de la SGA entre 2 MB y añadiendo un margen del 1,5%. Tras reiniciar la instancia Oracle, la SGA se asigna en Huge Pages, verificable desde /proc/meminfo.\nPara qué sirve #Reducen la presión sobre el TLB (Translation Lookaside Buffer) de la CPU, que solo puede almacenar unas pocas miles de traducciones de dirección. Con páginas normales, el TLB se desborda constantemente y la MMU debe gestionar millones de traducciones — con un impacto medible en latch free waits y library cache contention.\nPor qué es crítico #Es el parámetro individual más impactante para Oracle en Linux, y el que se ignora con más frecuencia. El asistente de instalación no lo configura, la documentación está en una nota MOS, y el sistema \u0026ldquo;funciona sin él.\u0026rdquo; Pero las métricas antes/después hablan claro: library cache hit ratio del 92% al 99,7%, CPU del 78% al 41%.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/huge-pages/","section":"Glosario","summary":"\u003cp\u003eLas \u003cstrong\u003eHuge Pages\u003c/strong\u003e son páginas de memoria de 2 MB, frente a los 4 KB estándar de Linux. Para una SGA Oracle de 64 GB, pasar de páginas de 4 KB (16,7 millones de páginas) a Huge Pages de 2 MB (32.768 páginas) reduce en 500 veces el número de entradas en la Page Table.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSe configuran mediante el parámetro del kernel \u003ccode\u003evm.nr_hugepages\u003c/code\u003e en \u003ccode\u003e/etc/sysctl.d/\u003c/code\u003e. El número necesario se calcula dividiendo el tamaño de la SGA entre 2 MB y añadiendo un margen del 1,5%. Tras reiniciar la instancia Oracle, la SGA se asigna en Huge Pages, verificable desde \u003ccode\u003e/proc/meminfo\u003c/code\u003e.\u003c/p\u003e","title":"Huge Pages"},{"content":"El I/O Scheduler es el componente del kernel Linux que gestiona la cola de solicitudes de lectura y escritura hacia los dispositivos de bloque (discos). Decide el orden de ejecución de las solicitudes para optimizar el throughput y minimizar la latencia.\nCómo funciona #Linux ofrece varios schedulers: cfq (Completely Fair Queuing, para escritorio), deadline/mq-deadline (para servidores y bases de datos), noop/none (para SSD/NVMe). Para Oracle la recomendación es deadline, que sirve las solicitudes minimizando los seeks del disco. Se configura vía /sys/block/sdX/queue/scheduler y se hace permanente vía GRUB.\nPara qué sirve #El cfq por defecto distribuye el I/O equitativamente entre los procesos — ideal para un escritorio, pésimo para una base de datos que necesita prioridad en las solicitudes I/O críticas. deadline garantiza que ninguna solicitud permanezca en cola demasiado tiempo, reduciendo la latencia de los db file sequential read.\nQué puede salir mal #Dejar el valor por defecto (cfq o bfq en algunos sistemas) significa que Oracle compite por el I/O con todos los demás procesos del sistema. En un servidor dedicado a la base de datos es un desperdicio: la base de datos debería tener prioridad absoluta en las operaciones de disco.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/io-scheduler/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eI/O Scheduler\u003c/strong\u003e es el componente del kernel Linux que gestiona la cola de solicitudes de lectura y escritura hacia los dispositivos de bloque (discos). Decide el orden de ejecución de las solicitudes para optimizar el throughput y minimizar la latencia.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLinux ofrece varios schedulers: \u003ccode\u003ecfq\u003c/code\u003e (Completely Fair Queuing, para escritorio), \u003ccode\u003edeadline\u003c/code\u003e/\u003ccode\u003emq-deadline\u003c/code\u003e (para servidores y bases de datos), \u003ccode\u003enoop\u003c/code\u003e/\u003ccode\u003enone\u003c/code\u003e (para SSD/NVMe). Para Oracle la recomendación es \u003ccode\u003edeadline\u003c/code\u003e, que sirve las solicitudes minimizando los seeks del disco. Se configura vía \u003ccode\u003e/sys/block/sdX/queue/scheduler\u003c/code\u003e y se hace permanente vía GRUB.\u003c/p\u003e","title":"I/O Scheduler"},{"content":"Los Intereses de Demora son los intereses que se devengan automáticamente sobre cada factura pagada con retraso respecto al plazo contractual. Según el D.Lgs. 231/2002 italiano (transposición de la Directiva UE 2011/7/UE), el tipo es igual al tipo BCE + 8 puntos porcentuales, sin necesidad de requerimiento formal.\nCómo funciona #Desde el día siguiente al vencimiento de la factura, los intereses se devengan automáticamente. El acreedor tiene derecho también a una compensación forfetaria de 40€ por cada factura pagada con retraso, por gastos de recuperación. No es necesario enviar un requerimiento — el derecho nace de la ley.\nPara qué sirve #Son la herramienta legal principal para desincentivar los retrasos en los pagos. En teoría, deberían hacer desventajoso para el deudor retrasar. En la práctica italiana, casi ningún consultor los reclama por miedo a perder el cliente — lo que hace la herramienta ineficaz.\nQué puede salir mal #El coste reputacional de reclamar los intereses de demora se percibe como superior al beneficio económico. Un consultor que envía una reclamación formal es un consultor que \u0026ldquo;no será llamado de nuevo.\u0026rdquo; El sistema se sostiene sobre la docilidad estructural del proveedor — y funciona, mientras funciona.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/interessi-di-mora/","section":"Glosario","summary":"\u003cp\u003eLos \u003cstrong\u003eIntereses de Demora\u003c/strong\u003e son los intereses que se devengan automáticamente sobre cada factura pagada con retraso respecto al plazo contractual. Según el D.Lgs. 231/2002 italiano (transposición de la Directiva UE 2011/7/UE), el tipo es igual al tipo BCE + 8 puntos porcentuales, sin necesidad de requerimiento formal.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eDesde el día siguiente al vencimiento de la factura, los intereses se devengan automáticamente. El acreedor tiene derecho también a una compensación forfetaria de 40€ por cada factura pagada con retraso, por gastos de recuperación. No es necesario enviar un requerimiento — el derecho nace de la ley.\u003c/p\u003e","title":"Intereses de Demora"},{"content":"INTO OUTFILE es una cláusula SQL de MySQL que permite exportar el resultado de una query directamente a un archivo en el filesystem del servidor de base de datos. Es el método nativo para generar archivos CSV, TSV o con separadores personalizados.\nCómo funciona #La cláusula se añade al final de un SELECT y especifica la ruta del archivo de destino. Los parámetros FIELDS TERMINATED BY, ENCLOSED BY y LINES TERMINATED BY controlan el formato de la salida. El archivo es creado por el usuario de sistema MySQL (no por el usuario que ejecuta la query), por lo que debe estar en un directorio con los permisos correctos.\nPara qué sirve #INTO OUTFILE es útil para exports masivos de datos de la base de datos a archivos de texto estructurados. Es el complemento de LOAD DATA INFILE, que hace la operación inversa (importa datos desde archivos). Juntos forman el mecanismo nativo de MySQL para import/export masivo.\nCuándo se usa #Su uso está vinculado a la directiva secure-file-priv: el archivo de destino debe estar dentro del directorio autorizado. Cuando secure-file-priv bloquea la ruta deseada, la alternativa es usar el cliente mysql desde shell con -B -e y redirigir la salida, que no está sujeta a las mismas restricciones.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/into-outfile/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eINTO OUTFILE\u003c/strong\u003e es una cláusula SQL de MySQL que permite exportar el resultado de una query directamente a un archivo en el filesystem del servidor de base de datos. Es el método nativo para generar archivos CSV, TSV o con separadores personalizados.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa cláusula se añade al final de un \u003ccode\u003eSELECT\u003c/code\u003e y especifica la ruta del archivo de destino. Los parámetros \u003ccode\u003eFIELDS TERMINATED BY\u003c/code\u003e, \u003ccode\u003eENCLOSED BY\u003c/code\u003e y \u003ccode\u003eLINES TERMINATED BY\u003c/code\u003e controlan el formato de la salida. El archivo es creado por el usuario de sistema MySQL (no por el usuario que ejecuta la query), por lo que debe estar en un directorio con los permisos correctos.\u003c/p\u003e","title":"INTO OUTFILE"},{"content":"Un Issue Tracker es un sistema para registrar, asignar, priorizar y monitorizar bugs, solicitudes de funcionalidades y tareas de proyecto. En GitHub está integrado directamente en el repositorio del código.\nCómo funciona #Cada problema o solicitud se crea como \u0026ldquo;issue\u0026rdquo; con título, descripción, etiquetas de categoría/prioridad y asignación a un desarrollador. Las issues pueden vincularse a branches y Pull Requests: cuando una PR que referencia una issue se fusiona, la issue se cierra automáticamente. Esto crea una trazabilidad completa del problema a la solución.\nPara qué sirve #El issue tracker sustituye emails, chat, hojas Excel y señalizaciones verbales con un sistema único y estructurado. Cada bug tiene una historia: quién lo reportó, quién está trabajando en él, cuál es el estado, qué código lo resolvió. En proyectos caóticos, el issue tracker es la herramienta que transforma la confusión en visibilidad.\nCuándo se usa #En cada proyecto software, independientemente del tamaño. La alternativa — reportes dispersos por email, chat y Excel — es la causa principal de la pérdida de información y la duplicación del trabajo. GitHub Issues, Jira y Linear son las plataformas más extendidas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/issue-tracker/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eIssue Tracker\u003c/strong\u003e es un sistema para registrar, asignar, priorizar y monitorizar bugs, solicitudes de funcionalidades y tareas de proyecto. En GitHub está integrado directamente en el repositorio del código.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada problema o solicitud se crea como \u0026ldquo;issue\u0026rdquo; con título, descripción, etiquetas de categoría/prioridad y asignación a un desarrollador. Las issues pueden vincularse a branches y Pull Requests: cuando una PR que referencia una issue se fusiona, la issue se cierra automáticamente. Esto crea una trazabilidad completa del problema a la solución.\u003c/p\u003e","title":"Issue Tracker"},{"content":"IST (Incremental State Transfer) es el mecanismo por el cual un nodo Galera que reingresa al cluster después de una ausencia breve recibe solo las transacciones faltantes, sin necesidad de descargar el dataset entero.\nCómo funciona #Cuando un nodo se reconecta al cluster, el donante verifica si las transacciones faltantes aún están disponibles en su gcache (Galera cache). Si el gap está cubierto por el gcache, se ejecuta un IST: solo las transacciones faltantes se envían al nodo, que las aplica y vuelve al estado Synced. Si el gap supera el gcache, Galera recurre a un SST completo.\nPara qué sirve #IST hace que el reingreso de un nodo al cluster sea mucho más rápido que un SST completo. Un nodo que ha estado offline unos minutos o unas horas puede volver a estar operativo en segundos, sin impacto en el rendimiento del cluster.\nCuándo se usa #IST se activa automáticamente cuando las condiciones lo permiten. El tamaño del gcache (gcache.size) determina cuántas transacciones el cluster puede mantener en memoria para soportar IST. Un gcache más grande permite tiempos de inactividad más largos de un nodo sin necesidad de SST.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/ist/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eIST\u003c/strong\u003e (Incremental State Transfer) es el mecanismo por el cual un nodo Galera que reingresa al cluster después de una ausencia breve recibe solo las transacciones faltantes, sin necesidad de descargar el dataset entero.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando un nodo se reconecta al cluster, el donante verifica si las transacciones faltantes aún están disponibles en su gcache (Galera cache). Si el gap está cubierto por el gcache, se ejecuta un IST: solo las transacciones faltantes se envían al nodo, que las aplica y vuelve al estado Synced. Si el gap supera el gcache, Galera recurre a un SST completo.\u003c/p\u003e","title":"IST"},{"content":"Kimball se refiere a Ralph Kimball y su metodología de diseño de data warehouses, descrita en el libro The Data Warehouse Toolkit (primera edición 1996, tercera edición 2013).\nEl enfoque #La metodología Kimball se basa en tres pilares:\nDimensional modeling: organizar los datos en star schemas con fact tables y dimension tables, optimizados para consultas analíticas Bottom-up: construir el DWH partiendo de los data marts departamentales individuales, integrándolos progresivamente a través de dimensiones conformes (conformed dimensions) Bus architecture: un framework para garantizar coherencia entre los data marts a través de dimensiones y hechos compartidos Slowly Changing Dimensions #Kimball definió la clasificación de las SCD (Slowly Changing Dimensions) en los tipos del 0 al 7, que se ha convertido en el estándar de facto en la industria. El Tipo 2 — con claves subrogadas y fechas de validez — es el más utilizado para rastrear la historia de las dimensiones.\nKimball vs Inmon #La alternativa principal es la metodología de Bill Inmon, que propone un enfoque top-down con un enterprise data warehouse normalizado (3NF) del que se derivan los data marts. Las dos metodologías no son mutuamente excluyentes y muchos proyectos reales adoptan elementos de ambas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/kimball/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eKimball\u003c/strong\u003e se refiere a Ralph Kimball y su metodología de diseño de data warehouses, descrita en el libro \u003cem\u003eThe Data Warehouse Toolkit\u003c/em\u003e (primera edición 1996, tercera edición 2013).\u003c/p\u003e\n\u003ch2 id=\"el-enfoque\" class=\"relative group\"\u003eEl enfoque \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#el-enfoque\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa metodología Kimball se basa en tres pilares:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDimensional modeling\u003c/strong\u003e: organizar los datos en star schemas con fact tables y dimension tables, optimizados para consultas analíticas\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBottom-up\u003c/strong\u003e: construir el DWH partiendo de los data marts departamentales individuales, integrándolos progresivamente a través de dimensiones conformes (conformed dimensions)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBus architecture\u003c/strong\u003e: un framework para garantizar coherencia entre los data marts a través de dimensiones y hechos compartidos\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"slowly-changing-dimensions\" class=\"relative group\"\u003eSlowly Changing Dimensions \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#slowly-changing-dimensions\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eKimball definió la clasificación de las SCD (Slowly Changing Dimensions) en los tipos del 0 al 7, que se ha convertido en el estándar de facto en la industria. El Tipo 2 — con claves subrogadas y fechas de validez — es el más utilizado para rastrear la historia de las dimensiones.\u003c/p\u003e","title":"Kimball"},{"content":"El Knowledge Transfer (transferencia de conocimiento) es el proceso a través del cual competencias, información y know-how se transfieren de quien los posee a quien los necesita — entre colegas, entre equipos, o entre personas y sistemas de documentación.\nCómo funciona #Puede ser formal (documentación, sesiones de formación, wikis) o informal (pair programming, mentoring, acompañamiento). La IA puede acelerar el knowledge transfer generando documentación a partir del código, los commits y las issues — no perfecta, pero suficiente para no perder conocimiento cuando alguien deja el proyecto.\nPara qué sirve #Cada proyecto IT depende del conocimiento tácito de las personas que trabajan en él. Cuando un developer senior deja el equipo sin haber documentado sus decisiones arquitectónicas, el coste de la pérdida es invisible pero enorme: semanas de ingeniería inversa, bugs introducidos por incomprensión, decisiones repetidas porque nadie recuerda el razonamiento.\nPor qué es crítico #Es uno de los tres ámbitos donde la IA genera valor concreto en el project management. Nadie documenta voluntariamente — la IA puede cubrir este vacío. Pero el knowledge transfer no es solo documentación: es también la capacidad de transferir contexto, motivaciones y lecciones aprendidas, no solo instrucciones operativas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/knowledge-transfer/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eKnowledge Transfer\u003c/strong\u003e (transferencia de conocimiento) es el proceso a través del cual competencias, información y know-how se transfieren de quien los posee a quien los necesita — entre colegas, entre equipos, o entre personas y sistemas de documentación.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePuede ser formal (documentación, sesiones de formación, wikis) o informal (pair programming, mentoring, acompañamiento). La IA puede acelerar el knowledge transfer generando documentación a partir del código, los commits y las issues — no perfecta, pero suficiente para no perder conocimiento cuando alguien deja el proyecto.\u003c/p\u003e","title":"Knowledge Transfer"},{"content":"Un KPI (Key Performance Indicator) es una métrica cuantificable usada para evaluar el éxito de una actividad, proyecto u organización respecto a objetivos predefinidos. En el contexto del trabajo remoto, los KPIs sustituyen la presencia física como indicador de productividad.\nCómo funciona #Un KPI efectivo es específico, medible y vinculado a un objetivo concreto. En la consultoría IT: tickets cerrados, código liberado, SLAs cumplidos, clientes satisfechos. No \u0026ldquo;horas en el escritorio\u0026rdquo; — porque las horas no miden el valor producido, solo miden el tiempo transcurrido.\nPara qué sirve #Permite gestionar el trabajo por objetivos en lugar de por presencia. Un consultor que cierra 20 tickets desde casa es más productivo que uno que cierra 8 en la oficina. Los KPIs hacen visible y medible esta diferencia, eliminando espacio para la percepción subjetiva.\nPor qué es crítico #Las empresas que no saben definir KPIs claros no pueden adoptar el smart working de forma seria. Sin métricas objetivas, la dirección recurre al control visual — \u0026ldquo;si te veo en tu escritorio, estás trabajando\u0026rdquo; — que es la suposición errónea en la base del presentismo.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/kpi/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eKPI\u003c/strong\u003e (Key Performance Indicator) es una métrica cuantificable usada para evaluar el éxito de una actividad, proyecto u organización respecto a objetivos predefinidos. En el contexto del trabajo remoto, los KPIs sustituyen la presencia física como indicador de productividad.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn KPI efectivo es específico, medible y vinculado a un objetivo concreto. En la consultoría IT: tickets cerrados, código liberado, SLAs cumplidos, clientes satisfechos. No \u0026ldquo;horas en el escritorio\u0026rdquo; — porque las horas no miden el valor producido, solo miden el tiempo transcurrido.\u003c/p\u003e","title":"KPI"},{"content":"El Least Privilege (principio del privilegio mínimo) es un principio fundamental de la seguridad informática: cada usuario, proceso o sistema debe tener solo los permisos estrictamente necesarios para desempeñar su función, nada más.\nCómo funciona #En el ámbito de bases de datos, el principio se aplica asignando privilegios granulares: SELECT si el usuario solo debe leer, SELECT + INSERT + UPDATE si también debe escribir, nunca ALL PRIVILEGES si no es estrictamente necesario. Combinado con el modelo usuario@host de MySQL, el principio puede aplicarse también según el origen de la conexión.\nPara qué sirve #Limitar los privilegios reduce la superficie de ataque. Si una aplicación es comprometida, el atacante hereda los privilegios del usuario de base de datos de la aplicación. Si ese usuario tiene solo SELECT sobre una base de datos específica, el daño es contenido. Si tiene ALL PRIVILEGES, todo el servidor está en riesgo.\nCuándo se usa #Siempre. El principio del least privilege es aplicable en cada contexto: usuarios de base de datos, usuarios de sistema operativo, roles aplicativos, cuentas de servicio. La tentación de asignar privilegios amplios \u0026ldquo;para no tener problemas\u0026rdquo; es la causa más común de incidentes de seguridad evitables.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/least-privilege/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eLeast Privilege\u003c/strong\u003e (principio del privilegio mínimo) es un principio fundamental de la seguridad informática: cada usuario, proceso o sistema debe tener solo los permisos estrictamente necesarios para desempeñar su función, nada más.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn el ámbito de bases de datos, el principio se aplica asignando privilegios granulares: \u003ccode\u003eSELECT\u003c/code\u003e si el usuario solo debe leer, \u003ccode\u003eSELECT + INSERT + UPDATE\u003c/code\u003e si también debe escribir, nunca \u003ccode\u003eALL PRIVILEGES\u003c/code\u003e si no es estrictamente necesario. Combinado con el modelo \u003ccode\u003eusuario@host\u003c/code\u003e de MySQL, el principio puede aplicarse también según el origen de la conexión.\u003c/p\u003e","title":"Least Privilege"},{"content":"Lift-and-Shift (rehosting) es una estrategia de migración que consiste en trasladar un sistema de un entorno a otro — típicamente de on-premise a cloud — sin modificar su arquitectura, código aplicativo o configuración. Se toma el sistema tal cual y se \u0026ldquo;levanta y traslada\u0026rdquo;.\nCómo funciona #La infraestructura se replica en el entorno de destino: mismas máquinas virtuales, mismas bases de datos, mismo middleware. La ventaja es la velocidad: no hay reescritura de código, no hay rediseño arquitectónico. El riesgo es llevarse todos los problemas del entorno original, incluidas ineficiencias y deuda técnica.\nCuándo se usa #Cuando la prioridad es salir rápidamente de un datacenter (fin de contrato, desmantelamiento de hardware), cuando el presupuesto no permite una rearquitectura, o como primera fase de una migración incremental donde los componentes se modernizan uno a uno.\nQué puede salir mal #Un lift-and-shift al cloud sin optimización puede costar más que la infraestructura on-premise original. Las aplicaciones no diseñadas para cloud no aprovechan la elasticidad, el auto-scaling y los servicios gestionados. El resultado es frecuentemente un datacenter privado reconstruido en el cloud a un precio superior.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/lift-and-shift/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eLift-and-Shift\u003c/strong\u003e (rehosting) es una estrategia de migración que consiste en trasladar un sistema de un entorno a otro — típicamente de on-premise a cloud — sin modificar su arquitectura, código aplicativo o configuración. Se toma el sistema tal cual y se \u0026ldquo;levanta y traslada\u0026rdquo;.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa infraestructura se replica en el entorno de destino: mismas máquinas virtuales, mismas bases de datos, mismo middleware. La ventaja es la velocidad: no hay reescritura de código, no hay rediseño arquitectónico. El riesgo es llevarse todos los problemas del entorno original, incluidas ineficiencias y deuda técnica.\u003c/p\u003e","title":"Lift-and-Shift"},{"content":"Un Local Index es un índice Oracle creado sobre una tabla particionada, que se particiona automáticamente con la misma clave y los mismos límites que la tabla. Cada partición de la tabla tiene una partición de índice correspondiente.\nCómo funciona #Cuando se crea un índice con la cláusula LOCAL, Oracle crea una partición de índice por cada partición de la tabla. Si la tabla tiene 100 particiones mensuales, el índice tendrá 100 particiones correspondientes. Las operaciones DDL sobre una partición (DROP, TRUNCATE, SPLIT) invalidan solo la partición de índice correspondiente, no el índice entero.\nPara qué sirve #El Local Index es la opción preferida para índices en tablas particionadas porque mantiene la independencia de las particiones. Un DROP PARTITION tarda menos de un segundo y no invalida ningún otro índice. Con un índice global, la misma operación invalidaría el índice entero, requiriendo horas de rebuild.\nCuándo se usa #Se usa cuando el índice incluye la clave de partición o cuando las queries siempre filtran por la columna de partición. Para lookups puntuales en columnas que no son la partición (ej. clave primaria), se necesita un índice global. La regla: local donde sea posible, global solo donde sea necesario.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/local-index/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eLocal Index\u003c/strong\u003e es un índice Oracle creado sobre una tabla particionada, que se particiona automáticamente con la misma clave y los mismos límites que la tabla. Cada partición de la tabla tiene una partición de índice correspondiente.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando se crea un índice con la cláusula \u003ccode\u003eLOCAL\u003c/code\u003e, Oracle crea una partición de índice por cada partición de la tabla. Si la tabla tiene 100 particiones mensuales, el índice tendrá 100 particiones correspondientes. Las operaciones DDL sobre una partición (DROP, TRUNCATE, SPLIT) invalidan solo la partición de índice correspondiente, no el índice entero.\u003c/p\u003e","title":"Local Index"},{"content":"MERGE es una instrucción SQL que combina las operaciones de INSERT y UPDATE (y opcionalmente DELETE) en un único statement. Si el registro existe lo actualiza, si no existe lo inserta. Informalmente se conoce como \u0026ldquo;upsert\u0026rdquo;.\nSintaxis Oracle #MERGE INTO tabla_destino d USING tabla_fuente s ON (d.clave = s.clave) WHEN MATCHED THEN UPDATE SET d.campo = s.campo WHEN NOT MATCHED THEN INSERT (clave, campo) VALUES (s.clave, s.campo); Uso en el data warehouse #En el contexto ETL, el MERGE es el mecanismo base para cargar las tablas dimensionales:\nSCD Tipo 1: un solo MERGE que actualiza los registros existentes e inserta los nuevos SCD Tipo 2: el MERGE se usa en la primera fase para cerrar los registros modificados (estableciendo la fecha de fin de validez), seguido de un INSERT para las nuevas versiones Disponibilidad # Oracle: soporte completo desde la versión 9i PostgreSQL: no tiene MERGE nativo hasta la versión 15. La alternativa es INSERT ... ON CONFLICT (upsert) MySQL: usa INSERT ... ON DUPLICATE KEY UPDATE como alternativa SQL Server: soporte completo con sintaxis similar a Oracle ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/merge-sql/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eMERGE\u003c/strong\u003e es una instrucción SQL que combina las operaciones de INSERT y UPDATE (y opcionalmente DELETE) en un único statement. Si el registro existe lo actualiza, si no existe lo inserta. Informalmente se conoce como \u0026ldquo;upsert\u0026rdquo;.\u003c/p\u003e\n\u003ch2 id=\"sintaxis-oracle\" class=\"relative group\"\u003eSintaxis Oracle \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#sintaxis-oracle\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eMERGE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eINTO\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etabla_destino\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eUSING\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etabla_fuente\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eON\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclave\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclave\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMATCHED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eUPDATE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eSET\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMATCHED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eINSERT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eclave\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"k\"\u003eVALUES\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclave\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"uso-en-el-data-warehouse\" class=\"relative group\"\u003eUso en el data warehouse \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#uso-en-el-data-warehouse\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn el contexto ETL, el MERGE es el mecanismo base para cargar las tablas dimensionales:\u003c/p\u003e","title":"MERGE"},{"content":"La Movilidad Sostenible es un enfoque del transporte urbano que privilegia el uso de medios de bajo impacto ambiental — bicicleta, transporte público, vehículos eléctricos, car sharing — frente al coche privado de combustión interna.\nCómo funciona #Se basa en un cambio de paradigma: en lugar de construir más carreteras para más coches, se invierte en infraestructura ciclable, transporte público eficiente e incentivos para la movilidad activa. Ciudades como Ámsterdam, Copenhague y Múnich demuestran que el modelo funciona a gran escala.\nPara qué sirve #Reduce emisiones, tráfico, costes individuales y colectivos, contaminación acústica y ocupación de suelo. Para el pendular individual, significa ahorrar hasta 5.450€ al año y 455 horas de tiempo respecto al coche — dos meses y medio de vida devueltos.\nPor qué es crítico #Roma tiene 300 días de sol al año, un clima templado y distancias urbanas contenidas. Es paradójicamente una de las ciudades italianas más adecuadas para la bicicleta. Faltan las infraestructuras y el coraje de cambiar hábitos. El modelo ideal combina smart working (3 días remotos) con movilidad sostenible (2 días en bici): de 13 horas semanales viajando a 1 hora y 12 minutos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/mobilita-sostenibile/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eMovilidad Sostenible\u003c/strong\u003e es un enfoque del transporte urbano que privilegia el uso de medios de bajo impacto ambiental — bicicleta, transporte público, vehículos eléctricos, car sharing — frente al coche privado de combustión interna.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSe basa en un cambio de paradigma: en lugar de construir más carreteras para más coches, se invierte en infraestructura ciclable, transporte público eficiente e incentivos para la movilidad activa. Ciudades como Ámsterdam, Copenhague y Múnich demuestran que el modelo funciona a gran escala.\u003c/p\u003e","title":"Movilidad Sostenible"},{"content":"MVCC (Multi-Version Concurrency Control) es el modelo de concurrencia usado por PostgreSQL para gestionar el acceso simultáneo a los datos. Cada UPDATE crea una nueva versión de la fila y marca la antigua como \u0026ldquo;muerta\u0026rdquo;; cada DELETE marca la fila como ya no visible. Las lecturas no bloquean las escrituras y viceversa.\nCómo funciona #Cada transacción ve un snapshot consistente de la base de datos en el momento de su inicio. Las filas modificadas por otras transacciones aún no confirmadas son invisibles. Esto elimina la necesidad de locks exclusivos en las lecturas, permitiendo alta concurrencia — pero genera \u0026ldquo;basura\u0026rdquo; en forma de dead tuples que deben ser limpiados por el VACUUM.\nPara qué sirve #MVCC es el compromiso arquitectónico de PostgreSQL: alta concurrencia sin locks, al precio de tener que gestionar la limpieza de las versiones obsoletas. Es un precio razonable — siempre que el autovacuum esté correctamente configurado para mantener el ritmo de modificación de las tablas.\nPor qué es crítico #Si el VACUUM no puede mantener el ritmo de generación de dead tuples, las tablas se hinchan (bloat), los escaneos secuenciales se ralentizan y los índices se vuelven ineficientes. El patrón clásico: el lunes la base de datos va bien, el viernes es un desastre.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/mvcc/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eMVCC\u003c/strong\u003e (Multi-Version Concurrency Control) es el modelo de concurrencia usado por PostgreSQL para gestionar el acceso simultáneo a los datos. Cada UPDATE crea una nueva versión de la fila y marca la antigua como \u0026ldquo;muerta\u0026rdquo;; cada DELETE marca la fila como ya no visible. Las lecturas no bloquean las escrituras y viceversa.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada transacción ve un snapshot consistente de la base de datos en el momento de su inicio. Las filas modificadas por otras transacciones aún no confirmadas son invisibles. Esto elimina la necesidad de locks exclusivos en las lecturas, permitiendo alta concurrencia — pero genera \u0026ldquo;basura\u0026rdquo; en forma de dead tuples que deben ser limpiados por el VACUUM.\u003c/p\u003e","title":"MVCC"},{"content":"mydumper es una herramienta open source de backup lógico para MySQL y MariaDB que implementa paralelismo real: no solo entre tablas diferentes, sino también dentro de la misma tabla, dividiéndola en chunks basados en la primary key.\nCómo funciona #mydumper se conecta al servidor MySQL, adquiere un snapshot consistente con FLUSH TABLES WITH READ LOCK (o --trx-consistency-only para evitar locks globales en InnoDB), luego distribuye el trabajo entre threads múltiples. Cada tabla grande se rompe en chunks — por defecto basados en los rangos de la primary key — y cada chunk se exporta por un thread separado.\nLa salida no es un único archivo SQL sino un directorio con un archivo por cada tabla (o por cada chunk), más los archivos de metadatos, esquema y stored procedures.\nEl restore con myloader #El compañero de mydumper es myloader, que carga los archivos en paralelo desactivando los checks de foreign keys y reconstruyendo los índices al final. Este enfoque hace el restore significativamente más rápido comparado con la carga secuencial de un único archivo SQL.\nCuándo se usa #mydumper es la opción recomendada para bases de datos de producción por encima de 10 GB donde la velocidad de dump y restore es crítica. En una base de datos de 60 GB con 8 threads, un dump que con mysqldump requiere 3-4 horas se completa en 20-25 minutos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/mydumper/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003emydumper\u003c/strong\u003e es una herramienta open source de backup lógico para MySQL y MariaDB que implementa paralelismo real: no solo entre tablas diferentes, sino también dentro de la misma tabla, dividiéndola en chunks basados en la primary key.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emydumper se conecta al servidor MySQL, adquiere un snapshot consistente con \u003ccode\u003eFLUSH TABLES WITH READ LOCK\u003c/code\u003e (o \u003ccode\u003e--trx-consistency-only\u003c/code\u003e para evitar locks globales en InnoDB), luego distribuye el trabajo entre threads múltiples. Cada tabla grande se rompe en chunks — por defecto basados en los rangos de la primary key — y cada chunk se exporta por un thread separado.\u003c/p\u003e","title":"mydumper"},{"content":"mysqlbinlog es la utilidad de línea de comandos proporcionada con MySQL para leer y decodificar el contenido de los archivos binary log. Es la única herramienta capaz de convertir el formato binario de los binlog en salida legible o en instrucciones SQL re-ejecutables.\nCómo funciona #mysqlbinlog lee los archivos binlog y produce salida en formato texto. Soporta varios filtros:\nPor intervalo temporal: --start-datetime y --stop-datetime para limitar la salida a una ventana temporal Por base de datos: --database para filtrar los eventos de una base de datos específica Por posición: --start-position y --stop-position para seleccionar eventos específicos Con formato ROW, el flag --verbose decodifica los cambios fila por fila en formato pseudo-SQL comentado, de lo contrario la salida es un blob binario ilegible.\nPara qué sirve #mysqlbinlog se utiliza en dos escenarios principales:\nPoint-in-time recovery: extraer y reaplicar los eventos desde el backup hasta el momento deseado, enviando la salida directamente al cliente mysql Debug de replicación: analizar los eventos para entender qué se ha replicado, identificar transacciones problemáticas o reconstruir la secuencia de operaciones que causó un problema Cuándo se usa #mysqlbinlog es esencial cada vez que se necesita inspeccionar qué pasó en la base de datos después de un incidente, o cuando se debe ejecutar un point-in-time recovery. Requiere acceso a los archivos binlog en el filesystem del servidor o la posibilidad de conectarse al servidor con --read-from-remote-server.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/mysqlbinlog/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003emysqlbinlog\u003c/strong\u003e es la utilidad de línea de comandos proporcionada con MySQL para leer y decodificar el contenido de los archivos binary log. Es la única herramienta capaz de convertir el formato binario de los binlog en salida legible o en instrucciones SQL re-ejecutables.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emysqlbinlog lee los archivos binlog y produce salida en formato texto. Soporta varios filtros:\u003c/p\u003e","title":"mysqlbinlog"},{"content":"mysqldump es la utilidad de backup lógico incluida de serie en cada instalación de MySQL y MariaDB. Produce un archivo SQL que contiene todas las instrucciones (CREATE TABLE, INSERT) necesarias para reconstruir completamente el esquema y los datos de una base de datos.\nCómo funciona #mysqldump se conecta al servidor MySQL y lee las tablas una por una, generando las instrucciones SQL correspondientes como salida. La operación es rigurosamente single-threaded: una tabla tras otra, una fila tras otra. El archivo producido puede comprimirse externamente (gzip, zstd) pero la herramienta en sí no ofrece compresión nativa.\nCon la opción --single-transaction, el dump ocurre dentro de una transacción con isolation level REPEATABLE READ, que garantiza un snapshot consistente en tablas InnoDB sin adquirir locks sobre las escrituras.\nPara qué sirve #mysqldump es la herramienta estándar para:\nBackup lógico de bases de datos pequeñas y medianas Migraciones entre versiones diferentes de MySQL Exportación de tablas individuales o bases de datos para transferencia entre entornos Creación de dumps legibles e inspeccionables manualmente Cuándo se convierte en problema #En bases de datos por encima de 10-15 GB, el dump single-threaded se convierte en un cuello de botella. Una base de datos de 60 GB puede requerir 3-4 horas de dump y otras tantas de restore. La falta de paralelismo es la limitación estructural: no hay forma de acelerar el proceso si no es pasando a herramientas como mydumper.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/mysqldump/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003emysqldump\u003c/strong\u003e es la utilidad de backup lógico incluida de serie en cada instalación de MySQL y MariaDB. Produce un archivo SQL que contiene todas las instrucciones (CREATE TABLE, INSERT) necesarias para reconstruir completamente el esquema y los datos de una base de datos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emysqldump se conecta al servidor MySQL y lee las tablas una por una, generando las instrucciones SQL correspondientes como salida. La operación es rigurosamente single-threaded: una tabla tras otra, una fila tras otra. El archivo producido puede comprimirse externamente (gzip, zstd) pero la herramienta en sí no ofrece compresión nativa.\u003c/p\u003e","title":"mysqldump"},{"content":"mysqlpump es la utilidad de backup lógico introducida por Oracle en MySQL 5.7 como evolución de mysqldump. La diferencia principal es el soporte para paralelismo a nivel de tabla y compresión nativa del output (zlib, lz4, zstd).\nCómo funciona #mysqlpump puede hacer dump de múltiples tablas simultáneamente usando threads paralelos, configurables con --default-parallelism. La compresión se aplica directamente durante el dump, sin necesidad de pipes externos hacia gzip. También soporta el dump selectivo de usuarios y cuentas MySQL.\nSin embargo, el paralelismo opera solo a nivel de tabla entera: si una sola tabla es mucho más grande que las demás, un thread se arrastra solo mientras los otros ya han terminado.\nEl problema de la consistencia #Con el paralelismo activo, mysqlpump no garantiza consistencia entre tablas diferentes — tablas exportadas por threads diferentes pueden reflejar momentos diferentes en el tiempo. Esta es una limitación crítica para backups de producción en bases de datos relacionales con foreign keys.\nEstado actual #Oracle declaró mysqlpump deprecado en MySQL 8.0.34 y lo eliminó completamente en MySQL 8.4. Para quien busca paralelismo en el backup lógico, mydumper es la alternativa recomendada.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/mysqlpump/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003emysqlpump\u003c/strong\u003e es la utilidad de backup lógico introducida por Oracle en MySQL 5.7 como evolución de mysqldump. La diferencia principal es el soporte para paralelismo a nivel de tabla y compresión nativa del output (zlib, lz4, zstd).\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emysqlpump puede hacer dump de múltiples tablas simultáneamente usando threads paralelos, configurables con \u003ccode\u003e--default-parallelism\u003c/code\u003e. La compresión se aplica directamente durante el dump, sin necesidad de pipes externos hacia gzip. También soporta el dump selectivo de usuarios y cuentas MySQL.\u003c/p\u003e","title":"mysqlpump"},{"content":"Nested loop es la estrategia de join mas simple: por cada fila de la tabla externa, la base de datos busca las filas correspondientes en la tabla interna. Funciona como un doble ciclo for anidado — de ahi el nombre.\nComo funciona #El optimizer elige una tabla como \u0026ldquo;externa\u0026rdquo; (outer) y una como \u0026ldquo;interna\u0026rdquo; (inner). Por cada fila de la tabla externa, ejecuta una busqueda en la tabla interna sobre la columna de join. Si la tabla interna tiene un indice en la columna de join, cada busqueda es un acceso directo via B-tree. Sin indice, cada busqueda se convierte en un sequential scan completo.\nCuando es la eleccion correcta #El nested loop es imbatible cuando la tabla externa tiene pocas filas y la tabla interna tiene un indice en la columna de join. Un join sobre 100 filas externas con un indice B-tree en la tabla interna es practicamente instantaneo: pocas iteraciones, acceso directo, memoria minima.\nEs tambien la estrategia preferida para las lookups de dimensiones en data warehouses, donde se une una fact table filtrada (pocas filas) con una dimension table indexada.\nQue puede salir mal #Se convierte en un desastre cuando el optimizer lo elige en datasets grandes por error — tipicamente porque las estadisticas subestiman el numero de filas. Un nested loop sobre 2 millones de filas externas significa 2 millones de busquedas en la tabla interna. Sin indice, cada busqueda es un scan completo.\nEn estos casos un hash join o un merge join serian ordenes de magnitud mas rapidos. La causa raiz es casi siempre una estimacion de cardinalidad erronea: estadisticas obsoletas o un default_statistics_target demasiado bajo.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/nested-loop/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eNested loop\u003c/strong\u003e es la estrategia de join mas simple: por cada fila de la tabla externa, la base de datos busca las filas correspondientes en la tabla interna. Funciona como un doble ciclo \u003ccode\u003efor\u003c/code\u003e anidado — de ahi el nombre.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl optimizer elige una tabla como \u0026ldquo;externa\u0026rdquo; (outer) y una como \u0026ldquo;interna\u0026rdquo; (inner). Por cada fila de la tabla externa, ejecuta una busqueda en la tabla interna sobre la columna de join. Si la tabla interna tiene un indice en la columna de join, cada busqueda es un acceso directo via B-tree. Sin indice, cada busqueda se convierte en un sequential scan completo.\u003c/p\u003e","title":"Nested Loop"},{"content":"NOLOGGING es un modo Oracle que deshabilita la generación de redo log durante operaciones de carga masiva. Las operaciones se completan mucho más rápido, pero los datos no son recuperables mediante redo en caso de crash antes de un backup.\nCómo funciona #Cuando un segmento (tabla, índice, partición) está en modo NOLOGGING, las operaciones masivas como CTAS, INSERT /*+ APPEND */ y ALTER TABLE MOVE no escriben redo log para los bloques de datos. En una copia de 380 GB, esto elimina la generación de la misma cantidad de redo, evitando saturar el área de archivelog y reduciendo los tiempos de días a horas.\nPara qué sirve #NOLOGGING es esencial para operaciones de migración en tablas de gran tamaño. Sin NOLOGGING, un CTAS de 380 GB generaría 380 GB de redo log, poniendo el sistema en modo archivelog durante días. Con NOLOGGING, la misma operación se completa en pocas horas con impacto mínimo en el sistema.\nCuándo se usa #Se activa antes de la operación masiva y se desactiva inmediatamente después (ALTER TABLE ... LOGGING). Es obligatorio ejecutar un backup RMAN inmediatamente después, porque los segmentos NOLOGGING no son recuperables con un restore desde redo. Nunca dejar NOLOGGING activo permanentemente en tablas de producción.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/nologging/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eNOLOGGING\u003c/strong\u003e es un modo Oracle que deshabilita la generación de redo log durante operaciones de carga masiva. Las operaciones se completan mucho más rápido, pero los datos no son recuperables mediante redo en caso de crash antes de un backup.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando un segmento (tabla, índice, partición) está en modo NOLOGGING, las operaciones masivas como CTAS, \u003ccode\u003eINSERT /*+ APPEND */\u003c/code\u003e y \u003ccode\u003eALTER TABLE MOVE\u003c/code\u003e no escriben redo log para los bloques de datos. En una copia de 380 GB, esto elimina la generación de la misma cantidad de redo, evitando saturar el área de archivelog y reduciendo los tiempos de días a horas.\u003c/p\u003e","title":"NOLOGGING"},{"content":"Un Object Privilege en Oracle es una autorización que permite ejecutar operaciones sobre un objeto específico de la base de datos: una tabla, una vista, una secuencia o un procedimiento PL/SQL. Ejemplos típicos incluyen SELECT ON schema.tabla, INSERT ON schema.tabla y EXECUTE ON schema.procedimiento.\nCómo funciona #Los object privileges se asignan con GRANT especificando la operación y el objeto destino: GRANT SELECT ON app_owner.clientes TO srv_report. Pueden asignarse a usuarios individuales o a roles. A diferencia de los system privileges, operan sobre un único objeto y no confieren poderes globales sobre la base de datos.\nPara qué sirve #Los object privileges son la herramienta principal para implementar el principio del mínimo privilegio en Oracle. Permiten construir modelos de acceso granulares: un usuario de reporting obtiene solo SELECT, un usuario aplicativo obtiene SELECT + INSERT + UPDATE sobre las tablas operativas, y así sucesivamente. Combinados con roles personalizados, crean arquitecturas de seguridad limpias y mantenibles.\nPor qué es crítico #La diferencia entre un GRANT SELECT ON app_owner.clientes y un GRANT DBA es la diferencia entre dar la llave de una habitación y dar las llaves de todo el edificio. En entornos con cientos de tablas, los object privileges se gestionan típicamente mediante bloques PL/SQL que generan los grants automáticamente para todas las tablas de un schema.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/object-privilege/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eObject Privilege\u003c/strong\u003e en Oracle es una autorización que permite ejecutar operaciones sobre un objeto específico de la base de datos: una tabla, una vista, una secuencia o un procedimiento PL/SQL. Ejemplos típicos incluyen \u003ccode\u003eSELECT ON schema.tabla\u003c/code\u003e, \u003ccode\u003eINSERT ON schema.tabla\u003c/code\u003e y \u003ccode\u003eEXECUTE ON schema.procedimiento\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLos object privileges se asignan con \u003ccode\u003eGRANT\u003c/code\u003e especificando la operación y el objeto destino: \u003ccode\u003eGRANT SELECT ON app_owner.clientes TO srv_report\u003c/code\u003e. Pueden asignarse a usuarios individuales o a roles. A diferencia de los system privileges, operan sobre un único objeto y no confieren poderes globales sobre la base de datos.\u003c/p\u003e","title":"Object Privilege"},{"content":"OCI (Oracle Cloud Infrastructure) es la plataforma cloud de Oracle, lanzada en su segunda generacion en 2018. A diferencia de otros proveedores cloud, OCI esta disenada nativamente para cargas de trabajo Oracle Database y ofrece ventajas significativas en licensing y rendimiento.\nPor que OCI para Oracle Database #La ventaja principal es el licensing. En OCI, Oracle reconoce sus propias OCPU (Oracle CPU) con una relacion 1:1 para el conteo de licencias. En otros proveedores cloud como AWS o Azure, la relacion vCPU-licencias es menos favorable y el riesgo de auditoria es real.\nEl programa BYOL (Bring Your Own License) permite reutilizar las licencias on-premises existentes en OCI sin costes adicionales — un factor decisivo para las empresas que ya han invertido en licencias Enterprise Edition.\nServicios principales para DBAs # Bare Metal DB Systems: servidores fisicos dedicados con Oracle Database preinstalado VM DB Systems: instancias virtuales con configuracion flexible (Flex shapes) Exadata Cloud Service: Exadata completo gestionado en cloud Autonomous Database: base de datos completamente gestionada con tuning automatico Networking y conectividad #OCI ofrece FastConnect para conexiones dedicadas de alta banda entre centros de datos on-premises y la region cloud, ademas de VPN site-to-site para escenarios con requisitos de banda menores. La latencia y el ancho de banda del enlace son factores criticos en las migraciones con Data Guard cross-site.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/oci/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eOCI\u003c/strong\u003e (Oracle Cloud Infrastructure) es la plataforma cloud de Oracle, lanzada en su segunda generacion en 2018. A diferencia de otros proveedores cloud, OCI esta disenada nativamente para cargas de trabajo Oracle Database y ofrece ventajas significativas en licensing y rendimiento.\u003c/p\u003e\n\u003ch2 id=\"por-que-oci-para-oracle-database\" class=\"relative group\"\u003ePor que OCI para Oracle Database \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#por-que-oci-para-oracle-database\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa ventaja principal es el licensing. En OCI, Oracle reconoce sus propias OCPU (Oracle CPU) con una relacion 1:1 para el conteo de licencias. En otros proveedores cloud como AWS o Azure, la relacion vCPU-licencias es menos favorable y el riesgo de auditoria es real.\u003c/p\u003e","title":"OCI"},{"content":"OLAP (Online Analytical Processing) indica un enfoque de procesamiento de datos orientado al análisis multidimensional: agregaciones, drill-down, comparaciones temporales, slice-and-dice sobre grandes volúmenes de datos históricos.\nOLAP vs OLTP # Característica OLAP OLTP Propósito Análisis y reporting Transacciones operativas Modelo de datos Star schema, desnormalizado 3NF, normalizado Consulta típica Agregaciones sobre millones de filas Lectura/escritura de pocas filas Usuarios Analistas, management Aplicaciones, operadores Actualización Batch (ETL periódico) Tiempo real Operaciones OLAP #Las operaciones fundamentales del análisis OLAP son:\nDrill-down: del nivel agregado al detalle Drill-up (roll-up): del detalle al agregado Slice: seleccionar una \u0026ldquo;rebanada\u0026rdquo; de datos fijando una dimensión (ej. solo año 2025) Dice: seleccionar un sub-cubo especificando múltiples dimensiones Pivot: rotar las dimensiones de análisis (filas ↔ columnas) Implementaciones # ROLAP (Relational OLAP): los datos permanecen en tablas relacionales, las agregaciones se calculan con consultas SQL. Es el enfoque usado en los data warehouses con star schemas MOLAP (Multidimensional OLAP): los datos se pre-agregan en estructuras multidimensionales (cubos). Más rápido en consultas pero requiere más espacio y tiempo de construcción HOLAP (Hybrid): combinación de ambos enfoques ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/olap/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eOLAP\u003c/strong\u003e (Online Analytical Processing) indica un enfoque de procesamiento de datos orientado al análisis multidimensional: agregaciones, drill-down, comparaciones temporales, slice-and-dice sobre grandes volúmenes de datos históricos.\u003c/p\u003e\n\u003ch2 id=\"olap-vs-oltp\" class=\"relative group\"\u003eOLAP vs OLTP \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#olap-vs-oltp\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaracterística\u003c/th\u003e\n          \u003cth\u003eOLAP\u003c/th\u003e\n          \u003cth\u003eOLTP\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePropósito\u003c/td\u003e\n          \u003ctd\u003eAnálisis y reporting\u003c/td\u003e\n          \u003ctd\u003eTransacciones operativas\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eModelo de datos\u003c/td\u003e\n          \u003ctd\u003eStar schema, desnormalizado\u003c/td\u003e\n          \u003ctd\u003e3NF, normalizado\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eConsulta típica\u003c/td\u003e\n          \u003ctd\u003eAgregaciones sobre millones de filas\u003c/td\u003e\n          \u003ctd\u003eLectura/escritura de pocas filas\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUsuarios\u003c/td\u003e\n          \u003ctd\u003eAnalistas, management\u003c/td\u003e\n          \u003ctd\u003eAplicaciones, operadores\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eActualización\u003c/td\u003e\n          \u003ctd\u003eBatch (ETL periódico)\u003c/td\u003e\n          \u003ctd\u003eTiempo real\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"operaciones-olap\" class=\"relative group\"\u003eOperaciones OLAP \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#operaciones-olap\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLas operaciones fundamentales del análisis OLAP son:\u003c/p\u003e","title":"OLAP"},{"content":"El Outsourcing es la práctica de confiar el desarrollo, el mantenimiento o la gestión de sistemas IT a proveedores externos a la empresa. Puede abarcar proyectos completos (desarrollo de software custom) o servicios continuos (gestión de infraestructura, soporte aplicativo).\nCómo funciona #La empresa cliente define los requisitos y firma un contrato con un proveedor externo que se compromete a realizar el proyecto. Los modelos contractuales más comunes son: a cuerpo (precio fijo por resultado definido), por tiempo y materiales (jornadas-hombre facturadas), o híbridos. El proveedor pone a disposición un equipo de consultores que trabajan en el proyecto, frecuentemente con rotación periódica del personal.\nPara qué sirve #Comprender los riesgos del outsourcing es fundamental para decidir qué externalizar y qué mantener interno. Los riesgos principales son: vendor lock-in, pérdida de know-how, scope creep, rotación de consultores y desalineación de incentivos (el proveedor gana por tiempo, no por resultado).\nCuándo se usa #El outsourcing puede funcionar para actividades commoditizadas o bien definidas. Se vuelve arriesgado para proyectos estratégicos, custom y a largo plazo donde el know-how específico del dominio es crítico. La alternativa frecuentemente más efectiva es un equipo interno pequeño y competente, eventualmente apoyado por consultores para competencias especializadas puntuales.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/outsourcing/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eOutsourcing\u003c/strong\u003e es la práctica de confiar el desarrollo, el mantenimiento o la gestión de sistemas IT a proveedores externos a la empresa. Puede abarcar proyectos completos (desarrollo de software custom) o servicios continuos (gestión de infraestructura, soporte aplicativo).\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa empresa cliente define los requisitos y firma un contrato con un proveedor externo que se compromete a realizar el proyecto. Los modelos contractuales más comunes son: a cuerpo (precio fijo por resultado definido), por tiempo y materiales (jornadas-hombre facturadas), o híbridos. El proveedor pone a disposición un equipo de consultores que trabajan en el proyecto, frecuentemente con rotación periódica del personal.\u003c/p\u003e","title":"Outsourcing"},{"content":"El Parking Lot es una lista visible — en una pizarra, un documento compartido o el chat — donde el facilitador anota los temas que surgen durante una reunión pero que no pueden discutirse en el tiempo disponible. Los temas se \u0026ldquo;aparcan\u0026rdquo; y se abordan después de la reunión solo con las personas involucradas.\nCómo funciona #Cuando durante un standup alguien plantea un problema complejo, el facilitador dice: \u0026ldquo;Lo anoto en el parking lot, lo hablamos después.\u0026rdquo; El tema no se ignora — simplemente se traslada al contexto adecuado, donde puede abordarse sin hacer perder tiempo a quienes no están involucrados.\nPara qué sirve #Es la herramienta más infravalorada en la gestión de standups y reuniones en general. Permite decir \u0026ldquo;lo hablamos después\u0026rdquo; sin que el tema se olvide. Resuelve el problema de los \u0026ldquo;thread killers\u0026rdquo; — esas discusiones entre dos personas que bloquean toda la reunión.\nPor qué es crítico #Sin parking lot, el facilitador tiene dos opciones malas: dejar que la discusión se expanda (y el standup se pasa de tiempo), o cortar el tema (y alguien se siente ignorado). El parking lot ofrece una tercera vía: reconocer la importancia del tema y garantizar que será abordado, pero en el momento adecuado.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/parking-lot/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eParking Lot\u003c/strong\u003e es una lista visible — en una pizarra, un documento compartido o el chat — donde el facilitador anota los temas que surgen durante una reunión pero que no pueden discutirse en el tiempo disponible. Los temas se \u0026ldquo;aparcan\u0026rdquo; y se abordan después de la reunión solo con las personas involucradas.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando durante un standup alguien plantea un problema complejo, el facilitador dice: \u0026ldquo;Lo anoto en el parking lot, lo hablamos después.\u0026rdquo; El tema no se ignora — simplemente se traslada al contexto adecuado, donde puede abordarse sin hacer perder tiempo a quienes no están involucrados.\u003c/p\u003e","title":"Parking Lot"},{"content":"La Partita IVA es el código de identificación fiscal asignado a los trabajadores autónomos y empresas en Italia para las operaciones sujetas a IVA. En la consultoría IT, \u0026ldquo;trabajar con partita IVA\u0026rdquo; significa operar como profesional independiente, facturando los servicios directamente al cliente.\nCómo funciona #El consultor autónomo emite factura al cliente al final del periodo de trabajo. El pago se realiza según los términos contractuales — que en Italia son típicamente 60-90-120 días fin de mes. Mientras tanto, el consultor asume todos los gastos (cotizaciones sociales, impuestos, alquiler, suministros) con fondos propios.\nPara qué sirve #Es el régimen estándar para la consultoría IT en Italia. Ofrece flexibilidad y autonomía, pero expone al profesional al riesgo de crédito: si el cliente no paga o paga con retraso, el consultor no tiene protecciones comparables a las de un empleado. No hay prestación por desempleo, no hay indemnización, no hay pagas extra.\nQué puede salir mal #Con plazos de pago de 90 días y un solo cliente, el consultor autónomo es el eslabón más débil de la cadena. No tiene poder de negociación, no tiene departamento legal, y rechazar las condiciones significa quedarse sin proyectos. La diversificación de clientes es la estrategia defensiva principal.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/partita-iva/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003ePartita IVA\u003c/strong\u003e es el código de identificación fiscal asignado a los trabajadores autónomos y empresas en Italia para las operaciones sujetas a IVA. En la consultoría IT, \u0026ldquo;trabajar con partita IVA\u0026rdquo; significa operar como profesional independiente, facturando los servicios directamente al cliente.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl consultor autónomo emite factura al cliente al final del periodo de trabajo. El pago se realiza según los términos contractuales — que en Italia son típicamente 60-90-120 días fin de mes. Mientras tanto, el consultor asume todos los gastos (cotizaciones sociales, impuestos, alquiler, suministros) con fondos propios.\u003c/p\u003e","title":"Partita IVA"},{"content":"El Partition Pruning es el mecanismo por el cual Oracle, durante la ejecución de una query sobre una tabla particionada, identifica y excluye automáticamente las particiones que no pueden contener datos relevantes para el predicado de la query.\nCómo funciona #Cuando una query incluye un predicado sobre la columna de partición (ej. WHERE data_movimento BETWEEN ...), Oracle consulta los metadatos de las particiones y determina cuáles contienen datos en el rango solicitado. Solo esas particiones se leen. En el plan de ejecución aparece como PARTITION RANGE SINGLE o PARTITION RANGE ITERATOR.\nPara qué sirve #En una tabla de 380 GB con particiones mensuales, una query sobre un solo mes lee solo ~4 GB en lugar de la tabla entera. El pruning transforma un full table scan de pesadilla en un full partition scan manejable, reduciendo el I/O en un 99%.\nCuándo se usa #El pruning es automático, pero solo funciona con predicados directos sobre la columna de partición. Aplicar funciones a la columna (TRUNC(fecha), TO_CHAR(fecha)) desactiva el pruning y fuerza a Oracle a leer todas las particiones. Verificar siempre con EXPLAIN PLAN que el pruning esté activo.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/partition-pruning/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003ePartition Pruning\u003c/strong\u003e es el mecanismo por el cual Oracle, durante la ejecución de una query sobre una tabla particionada, identifica y excluye automáticamente las particiones que no pueden contener datos relevantes para el predicado de la query.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando una query incluye un predicado sobre la columna de partición (ej. \u003ccode\u003eWHERE data_movimento BETWEEN ...\u003c/code\u003e), Oracle consulta los metadatos de las particiones y determina cuáles contienen datos en el rango solicitado. Solo esas particiones se leen. En el plan de ejecución aparece como \u003ccode\u003ePARTITION RANGE SINGLE\u003c/code\u003e o \u003ccode\u003ePARTITION RANGE ITERATOR\u003c/code\u003e.\u003c/p\u003e","title":"Partition Pruning"},{"content":"El Pedaleo Asistido es un sistema de propulsión eléctrica montado en una bicicleta que amplifica la fuerza del pedaleo del ciclista mediante un motor eléctrico. El motor se activa solo cuando se pedalea y se desactiva por encima de los 25 km/h (límite europeo).\nCómo funciona #Un sensor detecta la fuerza y la cadencia del pedaleo y activa el motor eléctrico proporcionalmente. Cuanto más fuerte pedaleas, más ayuda el motor. El resultado es que cuestas como el Celio en Roma se convierten en una ligera pendiente, y se llega al destino sin sudar — un detalle crucial para quien tiene que presentarse en la oficina.\nPara qué sirve #Elimina las dos objeciones principales a la bicicleta como transporte urbano: las cuestas y el sudor. Con el pedaleo asistido, un recorrido urbano de 8 km se cubre en 18 minutos independientemente del desnivel, llegando fresco y listo para trabajar. La autonomía típica es de 40-80 km, más que suficiente para una semana de pendularismo.\nPor qué es crítico #Con una e-bike, el argumento \u0026ldquo;Roma tiene siete colinas\u0026rdquo; se desmorona. Las siete colinas ya no existen con un motor que asiste en las subidas. Esto hace que la bicicleta sea competitiva con el coche incluso en ciudades con cuestas, eliminando la última excusa para quedarse en el tráfico.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/pedalata-assistita/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003ePedaleo Asistido\u003c/strong\u003e es un sistema de propulsión eléctrica montado en una bicicleta que amplifica la fuerza del pedaleo del ciclista mediante un motor eléctrico. El motor se activa solo cuando se pedalea y se desactiva por encima de los 25 km/h (límite europeo).\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn sensor detecta la fuerza y la cadencia del pedaleo y activa el motor eléctrico proporcionalmente. Cuanto más fuerte pedaleas, más ayuda el motor. El resultado es que cuestas como el Celio en Roma se convierten en una ligera pendiente, y se llega al destino sin sudar — un detalle crucial para quien tiene que presentarse en la oficina.\u003c/p\u003e","title":"Pedaleo Asistido"},{"content":"El Pendularismo (commuting) es el desplazamiento diario entre casa y lugar de trabajo. En las grandes ciudades italianas como Roma, el desplazamiento medio absorbe 2-4 horas al día, con costes directos (combustible, aparcamiento, transporte público) e indirectos (estrés, cansancio, productividad perdida).\nCómo funciona #Un consultor IT que vive a 30 km de la oficina en Roma puede tardar 1h15-2h30 solo para la ida. En 220 días laborables, son 47-89 horas perdidas al mes — hasta dos semanas laborables pasadas en el coche sin producir nada.\nPor qué es crítico #El pendularismo no es solo tiempo perdido. Es energía mental quemada antes de empezar a trabajar. Un consultor IT trabaja con la cabeza: analiza sistemas, escribe código, diseña arquitecturas. Si esa cabeza llega ya agotada después de una hora de tráfico, el valor de la jornada laboral está comprometido de entrada.\nQué puede salir mal #Las empresas que ignoran el coste del pendularismo pagan un precio oculto: para 50 consultores en Roma, el coste estimado es de ~1.700.000 euros/año entre horas perdidas, alquiler de oficina y gastos asociados. El smart working al 80% reduce este coste a ~174.000 euros/año a partir del segundo año.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/pendolarismo/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003ePendularismo\u003c/strong\u003e (commuting) es el desplazamiento diario entre casa y lugar de trabajo. En las grandes ciudades italianas como Roma, el desplazamiento medio absorbe 2-4 horas al día, con costes directos (combustible, aparcamiento, transporte público) e indirectos (estrés, cansancio, productividad perdida).\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn consultor IT que vive a 30 km de la oficina en Roma puede tardar 1h15-2h30 solo para la ida. En 220 días laborables, son 47-89 horas perdidas al mes — hasta dos semanas laborables pasadas en el coche sin producir nada.\u003c/p\u003e","title":"Pendularismo"},{"content":"pg_stat_statements es una extensión de PostgreSQL — incluida en la distribución oficial pero no activa por defecto — que lleva el registro de las estadísticas de ejecución de todas las queries SQL que pasan por el servidor. Las queries se normalizan (los valores literales se reemplazan con parámetros) para agrupar las ejecuciones del mismo patrón.\nCómo funciona #La extensión requiere ser cargada como shared library al arranque del servidor mediante el parámetro shared_preload_libraries. Una vez activa, registra para cada query: número de ejecuciones, tiempo total y medio, filas devueltas, bloques leídos de disco y de caché. El parámetro pg_stat_statements.max controla cuántas queries distintas se rastrean (por defecto 5000).\nPara qué sirve #Es la herramienta principal para identificar las queries más costosas en un servidor PostgreSQL. Ordenando por total_exec_time se obtiene inmediatamente el ranking de queries que consumen más recursos. Combinado con EXPLAIN ANALYZE, permite un workflow diagnóstico completo: pg_stat_statements identifica el problema, EXPLAIN explica la causa.\nCuándo se usa #Debería estar activo en cualquier instalación PostgreSQL de producción. El overhead es despreciable (1-2% de CPU). Sin pg_stat_statements, cualquier actividad de performance tuning se basa en suposiciones en lugar de datos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/pg-stat-statements/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003epg_stat_statements\u003c/strong\u003e es una extensión de PostgreSQL — incluida en la distribución oficial pero no activa por defecto — que lleva el registro de las estadísticas de ejecución de todas las queries SQL que pasan por el servidor. Las queries se normalizan (los valores literales se reemplazan con parámetros) para agrupar las ejecuciones del mismo patrón.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa extensión requiere ser cargada como shared library al arranque del servidor mediante el parámetro \u003ccode\u003eshared_preload_libraries\u003c/code\u003e. Una vez activa, registra para cada query: número de ejecuciones, tiempo total y medio, filas devueltas, bloques leídos de disco y de caché. El parámetro \u003ccode\u003epg_stat_statements.max\u003c/code\u003e controla cuántas queries distintas se rastrean (por defecto 5000).\u003c/p\u003e","title":"pg_stat_statements"},{"content":"pg_trgm es una extensión de PostgreSQL que implementa la búsqueda basada en trigramas — secuencias de tres caracteres consecutivos extraídos del texto. Habilita el uso de índices GIN y GiST para acelerar búsquedas LIKE '%valor%' e ILIKE, que de otro modo requerirían escaneos secuenciales.\nCómo funciona #La extensión descompone cada cadena en trigramas: por ejemplo, \u0026ldquo;hello\u0026rdquo; se convierte en {\u0026quot; h\u0026quot;, \u0026quot; he\u0026quot;, \u0026ldquo;hel\u0026rdquo;, \u0026ldquo;ell\u0026rdquo;, \u0026ldquo;llo\u0026rdquo;, \u0026ldquo;lo \u0026ldquo;}. Un índice GIN con operator class gin_trgm_ops indexa estos trigramas. Al ejecutar un LIKE '%ell%', PostgreSQL busca los trigramas correspondientes en el índice en lugar de escanear toda la tabla.\nPara qué sirve #pg_trgm resuelve uno de los problemas más comunes en PostgreSQL: la búsqueda \u0026ldquo;contiene\u0026rdquo; en columnas de texto grandes. Sin pg_trgm, un LIKE '%valor%' en una tabla de millones de filas requiere un escaneo completo. Con pg_trgm y un índice GIN, la misma búsqueda usa el índice y responde en milisegundos.\nCuándo se usa #Se activa con CREATE EXTENSION IF NOT EXISTS pg_trgm y se crea el índice con USING gin (columna gin_trgm_ops). Es ideal en tablas con bajo churn (pocos UPDATE/DELETE). La creación del índice debe hacerse con CONCURRENTLY en producción para evitar locks.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/pg-trgm/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003epg_trgm\u003c/strong\u003e es una extensión de PostgreSQL que implementa la búsqueda basada en trigramas — secuencias de tres caracteres consecutivos extraídos del texto. Habilita el uso de índices GIN y GiST para acelerar búsquedas \u003ccode\u003eLIKE '%valor%'\u003c/code\u003e e \u003ccode\u003eILIKE\u003c/code\u003e, que de otro modo requerirían escaneos secuenciales.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa extensión descompone cada cadena en trigramas: por ejemplo, \u0026ldquo;hello\u0026rdquo; se convierte en {\u0026quot;  h\u0026quot;, \u0026quot; he\u0026quot;, \u0026ldquo;hel\u0026rdquo;, \u0026ldquo;ell\u0026rdquo;, \u0026ldquo;llo\u0026rdquo;, \u0026ldquo;lo \u0026ldquo;}. Un índice GIN con operator class \u003ccode\u003egin_trgm_ops\u003c/code\u003e indexa estos trigramas. Al ejecutar un \u003ccode\u003eLIKE '%ell%'\u003c/code\u003e, PostgreSQL busca los trigramas correspondientes en el índice en lugar de escanear toda la tabla.\u003c/p\u003e","title":"pg_trgm"},{"content":"PITR (Point-in-Time Recovery) es una técnica de restauración que permite llevar una base de datos a cualquier momento en el tiempo, no solo al momento del backup. Se basa en la combinación de un backup completo y los logs de transacciones (binary log en MySQL, WAL en PostgreSQL, redo log en Oracle).\nCómo funciona #El proceso se articula en dos fases:\nRestore del backup: se restaura la base de datos al último backup disponible Replay de los logs: se reaplican los logs de transacciones desde el momento del backup hasta el momento deseado, excluyendo el evento que causó el problema En MySQL, la herramienta mysqlbinlog extrae los eventos de los binary log y los reproduce sobre la base de datos restaurada.\nPara qué sirve #PITR es esencial cuando se produce un error humano (DROP TABLE, DELETE sin WHERE, UPDATE masivo equivocado) y se necesita restaurar la base de datos al estado inmediatamente anterior al error, sin perder las horas de trabajo entre el último backup y el incidente.\nCuándo se usa #PITR requiere que el binary log esté activo y que los archivos binlog no hayan sido eliminados. La retención de los binlog debe cubrir al menos el doble del intervalo entre dos backups consecutivos para garantizar una cobertura PITR completa.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/pitr/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003ePITR\u003c/strong\u003e (Point-in-Time Recovery) es una técnica de restauración que permite llevar una base de datos a cualquier momento en el tiempo, no solo al momento del backup. Se basa en la combinación de un backup completo y los logs de transacciones (binary log en MySQL, WAL en PostgreSQL, redo log en Oracle).\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl proceso se articula en dos fases:\u003c/p\u003e","title":"PITR"},{"content":"El Presentismo es la cultura organizativa que mide el valor del trabajo en base a la presencia física del empleado en la oficina, independientemente de la calidad y cantidad de los resultados producidos. Es la suposición de que \u0026ldquo;si te veo en tu escritorio, estás trabajando.\u0026rdquo;\nCómo funciona #En una organización presentista, estar en la oficina de 9 a 18 es más importante que cerrar tareas. Llegar tarde es un problema incluso si has producido más que todos. Trabajar desde casa es sospechoso incluso si los resultados son excelentes. El control se basa en la vista, no en las métricas.\nPor qué es crítico #El presentismo es el principal obstáculo para la adopción del smart working en la consultoría IT. Un consultor informático no trabaja en cadena de montaje — necesita concentración, silencio y herramientas digitales, no un escritorio en un open space ruidoso. Confundir presencia con productividad es un legado cultural, no una necesidad operativa.\nQué puede salir mal #Las empresas que no superan el presentismo pagan un coste invisible: horas de desplazamiento no productivas, empleados que llegan estresados y agotados, talento que se va hacia empresas más flexibles. El presentismo no protege la productividad — la destruye.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/presenteismo/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003ePresentismo\u003c/strong\u003e es la cultura organizativa que mide el valor del trabajo en base a la presencia física del empleado en la oficina, independientemente de la calidad y cantidad de los resultados producidos. Es la suposición de que \u0026ldquo;si te veo en tu escritorio, estás trabajando.\u0026rdquo;\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn una organización presentista, estar en la oficina de 9 a 18 es más importante que cerrar tareas. Llegar tarde es un problema incluso si has producido más que todos. Trabajar desde casa es sospechoso incluso si los resultados son excelentes. El control se basa en la vista, no en las métricas.\u003c/p\u003e","title":"Presentismo"},{"content":"Una Pull Request (PR) es una solicitud formal de incorporar los cambios de un branch de desarrollo al branch principal del repositorio. Es el mecanismo central de colaboración en GitHub y plataformas similares.\nCómo funciona #El desarrollador trabaja en un branch dedicado (ej. fix/issue-234-error-calculo), completa los cambios, y abre una PR. La PR muestra el diff del código, permite a los colegas comentar línea por línea, solicitar cambios o aprobar. Solo después de la aprobación el código se une (merge) al branch principal. Esto garantiza que el código \u0026ldquo;bueno\u0026rdquo; siga siendo bueno.\nPara qué sirve #La PR transforma el desarrollo de una actividad individual a un proceso de equipo. Previene sobreescrituras accidentales, captura bugs antes de que lleguen a producción, y crea un historial completo de quién hizo qué, cuándo y por qué. En proyectos caóticos, es la diferencia entre control y desorden.\nCuándo se usa #En cada cambio de código, sin excepciones. Incluso las correcciones pequeñas pasan por una PR, porque el valor no está solo en la revisión sino en la trazabilidad. En plataformas GitLab la misma funcionalidad se llama Merge Request.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/pull-request/","section":"Glosario","summary":"\u003cp\u003eUna \u003cstrong\u003ePull Request\u003c/strong\u003e (PR) es una solicitud formal de incorporar los cambios de un branch de desarrollo al branch principal del repositorio. Es el mecanismo central de colaboración en GitHub y plataformas similares.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl desarrollador trabaja en un branch dedicado (ej. \u003ccode\u003efix/issue-234-error-calculo\u003c/code\u003e), completa los cambios, y abre una PR. La PR muestra el diff del código, permite a los colegas comentar línea por línea, solicitar cambios o aprobar. Solo después de la aprobación el código se une (merge) al branch principal. Esto garantiza que el código \u0026ldquo;bueno\u0026rdquo; siga siendo bueno.\u003c/p\u003e","title":"Pull Request"},{"content":"El quorum es el número mínimo de nodos que deben estar de acuerdo para considerar el cluster operativo. En un cluster de 3 nodos, el quorum es 2 (la mayoría). Si un nodo se desconecta, los otros dos reconocen que son la mayoría y continúan operando normalmente.\nCómo funciona #Galera Cluster utiliza un protocolo de comunicación de grupo que verifica continuamente cuántos nodos son alcanzables. El cálculo es simple: quorum = (número total de nodos / 2) + 1. Con 3 nodos el quorum es 2, con 5 nodos es 3. Los nodos que pierden el quorum pasan al estado Non-Primary y rechazan las escrituras para evitar inconsistencias.\nPara qué sirve #El quorum previene el split-brain: la situación en la que dos partes del cluster operan independientemente, aceptando escrituras diferentes sobre los mismos datos. Sin quorum, una interrupción de red podría llevar a datos divergentes imposibles de reconciliar automáticamente.\nCuándo se usa #El quorum está activo automáticamente en cualquier cluster Galera. Por esta razón, tres nodos es el mínimo en producción: con dos nodos, la pérdida de uno deja al superviviente sin quorum y por tanto bloqueado.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/quorum/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003equorum\u003c/strong\u003e es el número mínimo de nodos que deben estar de acuerdo para considerar el cluster operativo. En un cluster de 3 nodos, el quorum es 2 (la mayoría). Si un nodo se desconecta, los otros dos reconocen que son la mayoría y continúan operando normalmente.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eGalera Cluster utiliza un protocolo de comunicación de grupo que verifica continuamente cuántos nodos son alcanzables. El cálculo es simple: quorum = (número total de nodos / 2) + 1. Con 3 nodos el quorum es 2, con 5 nodos es 3. Los nodos que pierden el quorum pasan al estado Non-Primary y rechazan las escrituras para evitar inconsistencias.\u003c/p\u003e","title":"Quorum"},{"content":"RAC (Real Application Clusters) es la tecnologia Oracle que permite a multiples instancias de base de datos acceder simultaneamente al mismo almacenamiento compartido. Si un nodo falla, los demas continuan atendiendo solicitudes sin interrupcion — el failover es transparente para las aplicaciones.\nComo funciona #Un cluster RAC esta compuesto por dos o mas servidores (nodos) conectados entre si mediante una red privada de alta velocidad (interconnect) y almacenamiento compartido (tipicamente ASM — Automatic Storage Management). Cada nodo ejecuta su propia instancia Oracle, pero todos acceden a los mismos datafiles.\nEl protocolo Cache Fusion gestiona la coherencia de datos entre nodos: cuando un bloque modificado por un nodo es necesario en otro, se transfiere directamente por el interconnect sin pasar por disco.\nAlta disponibilidad #Si un nodo cae, las sesiones activas se transfieren automaticamente a los nodos restantes mediante TAF (Transparent Application Failover) o Application Continuity. El tiempo de failover depende de la configuracion pero tipicamente es del orden de segundos.\nImplicaciones de licensing #RAC es una opcion de la Enterprise Edition con un coste de licensing significativo. En una migracion cloud, el conteo de licencias RAC es uno de los aspectos mas delicados: en OCI con BYOL las licencias on-premises se reutilizan, en otros proveedores cloud el coste puede multiplicarse.\nCuando es realmente necesario #RAC esta justificado cuando se necesita alta disponibilidad con failover automatico y escalabilidad horizontal. Para entornos con pocos usuarios o requisitos de uptime estandar, un nodo unico con Data Guard es a menudo una solucion mas simple y economica.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/rac/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eRAC\u003c/strong\u003e (Real Application Clusters) es la tecnologia Oracle que permite a multiples instancias de base de datos acceder simultaneamente al mismo almacenamiento compartido. Si un nodo falla, los demas continuan atendiendo solicitudes sin interrupcion — el failover es transparente para las aplicaciones.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn cluster RAC esta compuesto por dos o mas servidores (nodos) conectados entre si mediante una red privada de alta velocidad (interconnect) y almacenamiento compartido (tipicamente ASM — Automatic Storage Management). Cada nodo ejecuta su propia instancia Oracle, pero todos acceden a los mismos datafiles.\u003c/p\u003e","title":"RAC"},{"content":"Una ragged hierarchy (jerarquía desequilibrada) es una estructura jerárquica en la que no todas las ramas alcanzan la misma profundidad. Algunos niveles intermedios están ausentes para determinadas entidades.\nEjemplo concreto #En una jerarquía de tres niveles Top Group → Group → Client:\nAlgunos clientes tienen los tres niveles (jerarquía completa) Algunos clientes tienen un Group pero ningún Top Group Algunos clientes no tienen ni Group ni Top Group (clientes directos) El resultado es una estructura con \u0026ldquo;huecos\u0026rdquo; que causa problemas en los reportes de agregación: filas con NULL, totales divididos, drill-downs incompletos.\nPor qué es un problema en el DWH #Las herramientas de BI y las consultas SQL esperan jerarquías completas para funcionar correctamente. Un GROUP BY sobre una columna con NULLs produce resultados inesperados: las filas con NULL se agrupan por separado, los totales no cuadran, y el mismo grupo puede aparecer en múltiples filas.\nCómo se resuelve #La técnica estándar es el self-parenting: quien no tiene padre se convierte en padre de sí mismo. Esto balancea la jerarquía aguas arriba, en el ETL, eliminando los NULLs de la tabla dimensional. Flags adicionales (is_direct_client, is_standalone_group) permiten distinguir las entidades balanceadas artificialmente de las que tienen una jerarquía natural.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/ragged-hierarchy/","section":"Glosario","summary":"\u003cp\u003eUna \u003cstrong\u003eragged hierarchy\u003c/strong\u003e (jerarquía desequilibrada) es una estructura jerárquica en la que no todas las ramas alcanzan la misma profundidad. Algunos niveles intermedios están ausentes para determinadas entidades.\u003c/p\u003e\n\u003ch2 id=\"ejemplo-concreto\" class=\"relative group\"\u003eEjemplo concreto \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#ejemplo-concreto\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn una jerarquía de tres niveles Top Group → Group → Client:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAlgunos clientes tienen los tres niveles (jerarquía completa)\u003c/li\u003e\n\u003cli\u003eAlgunos clientes tienen un Group pero ningún Top Group\u003c/li\u003e\n\u003cli\u003eAlgunos clientes no tienen ni Group ni Top Group (clientes directos)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eEl resultado es una estructura con \u0026ldquo;huecos\u0026rdquo; que causa problemas en los reportes de agregación: filas con NULL, totales divididos, drill-downs incompletos.\u003c/p\u003e","title":"Ragged hierarchy"},{"content":"El Range Partitioning (particionamiento por rango) es una estrategia de particionamiento de tablas en la que las filas se distribuyen en particiones diferentes según el valor de una columna respecto a intervalos predefinidos. La columna de particionamiento es casi siempre una fecha en los data warehouses.\nCómo funciona #Cada partición se define con una cláusula VALUES LESS THAN que establece el límite superior del intervalo. Oracle asigna automáticamente cada fila a la partición correcta según el valor de la columna de particionamiento. Si una fila tiene data_vendita = '2025-03-15', se inserta en la partición cuyo rango incluye esa fecha.\nCuándo se usa #El range partitioning es la elección natural cuando los datos tienen una dimensión temporal dominante — fact tables en data warehouses, tablas de log, tablas de transacciones. La granularidad de la partición (diaria, mensual, trimestral) depende del volumen de inserción y del tipo de queries: particiones demasiado pequeñas generan overhead de gestión, demasiado grandes reducen la eficacia del partition pruning.\nVentajas operativas #Más allá del rendimiento de las queries, el range partitioning habilita operaciones de gestión del ciclo de vida imposibles en tablas monolíticas: drop instantáneo de una partición (sin DELETE), compresión selectiva de particiones históricas, movimiento a almacenamiento diferente (ILM — Information Lifecycle Management), y exchange partition para cargas masivas sin impacto.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/range-partitioning/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eRange Partitioning\u003c/strong\u003e (particionamiento por rango) es una estrategia de particionamiento de tablas en la que las filas se distribuyen en particiones diferentes según el valor de una columna respecto a intervalos predefinidos. La columna de particionamiento es casi siempre una fecha en los data warehouses.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada partición se define con una cláusula \u003ccode\u003eVALUES LESS THAN\u003c/code\u003e que establece el límite superior del intervalo. Oracle asigna automáticamente cada fila a la partición correcta según el valor de la columna de particionamiento. Si una fila tiene \u003ccode\u003edata_vendita = '2025-03-15'\u003c/code\u003e, se inserta en la partición cuyo rango incluye esa fecha.\u003c/p\u003e","title":"Range Partitioning"},{"content":"Redo Log es el mecanismo con el que Oracle registra cada modificacion de datos (INSERT, UPDATE, DELETE, DDL) antes de que se escriba definitivamente en los datafiles. Es la garantia fundamental de durabilidad de las transacciones.\nComo funciona #Oracle escribe las modificaciones en los redo log online de forma secuencial y continua. Los redo log estan organizados en grupos circulares: cuando un grupo se llena, Oracle pasa al siguiente. Cuando todos los grupos han sido utilizados, Oracle vuelve al primero (log switch).\nOnline vs Archived # Online redo log: los archivos activos donde Oracle escribe en tiempo real. Son circulares y se sobreescriben Archived redo log: copias de los redo log online guardadas antes de la sobreescritura. Necesarios para la recuperacion point-in-time y para Data Guard El modo ARCHIVELOG de la base de datos activa la creacion automatica de los archived log. Sin el, los redo se sobreescriben y la recuperacion se limita al ultimo backup completo.\nPor que son importantes #Los redo log son el corazon de la recuperacion y la replica en Oracle. Sin redo:\nNo es posible la recuperacion tras un crash (instance recovery) No es posible la recuperacion point-in-time (media recovery) Data Guard no puede funcionar (la replica se basa enteramente en los redo) No es posible el flashback database ","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/redo-log/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eRedo Log\u003c/strong\u003e es el mecanismo con el que Oracle registra cada modificacion de datos (INSERT, UPDATE, DELETE, DDL) antes de que se escriba definitivamente en los datafiles. Es la garantia fundamental de durabilidad de las transacciones.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOracle escribe las modificaciones en los redo log online de forma secuencial y continua. Los redo log estan organizados en grupos circulares: cuando un grupo se llena, Oracle pasa al siguiente. Cuando todos los grupos han sido utilizados, Oracle vuelve al primero (log switch).\u003c/p\u003e","title":"Redo Log"},{"content":"El relay log es un archivo de log intermedio presente en el slave en una arquitectura de replicación MySQL. Contiene los eventos recibidos del binary log del master, a la espera de ser ejecutados localmente por el hilo SQL del slave.\nCómo funciona #El flujo de la replicación MySQL pasa por el relay log en tres fases:\nEl I/O thread del slave se conecta al master y lee los binary log Los eventos recibidos se escriben en el relay log local El SQL thread del slave lee los eventos del relay log y los ejecuta en la base de datos local Esta arquitectura de dos hilos permite desacoplar la recepción de datos de su aplicación: el slave puede seguir recibiendo eventos del master incluso si la ejecución local está temporalmente ralentizada.\nPara qué sirve #El relay log es el mecanismo que garantiza la consistencia de la replicación. Actúa como buffer entre el master y la aplicación local de los eventos, permitiendo al slave gestionar diferencias de velocidad sin perder datos.\nCuándo se usa #El relay log se crea automáticamente cuando se configura una réplica MySQL. No requiere gestión manual directa, pero su estado (posición actual, posible retardo) es visible a través de SHOW REPLICA STATUS y es fundamental para diagnosticar problemas de replica lag.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/relay-log/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003erelay log\u003c/strong\u003e es un archivo de log intermedio presente en el slave en una arquitectura de replicación MySQL. Contiene los eventos recibidos del binary log del master, a la espera de ser ejecutados localmente por el hilo SQL del slave.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl flujo de la replicación MySQL pasa por el relay log en tres fases:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eEl \u003cstrong\u003eI/O thread\u003c/strong\u003e del slave se conecta al master y lee los binary log\u003c/li\u003e\n\u003cli\u003eLos eventos recibidos se escriben en el relay log local\u003c/li\u003e\n\u003cli\u003eEl \u003cstrong\u003eSQL thread\u003c/strong\u003e del slave lee los eventos del relay log y los ejecuta en la base de datos local\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eEsta arquitectura de dos hilos permite desacoplar la recepción de datos de su aplicación: el slave puede seguir recibiendo eventos del master incluso si la ejecución local está temporalmente ralentizada.\u003c/p\u003e","title":"Relay log"},{"content":"REVOKE es el comando SQL que elimina privilegios o roles previamente asignados con GRANT. Es el complemento indispensable del GRANT y la herramienta principal para restringir permisos cuando se reestructura un modelo de seguridad.\nCómo funciona #La sintaxis sigue el mismo esquema que GRANT: REVOKE SELECT ON schema.tabla FROM usuario o REVOKE rol FROM usuario. En Oracle, revocar un rol como DBA elimina de un solo golpe todos los system privileges incluidos en ese rol. Antes de ejecutar un REVOKE crítico, es fundamental verificar que el usuario mantenga los privilegios necesarios para sus funciones.\nCuándo se usa #El caso más común es la reestructuración del modelo de seguridad: eliminar roles excesivos (como DBA de usuarios aplicativos) y sustituirlos por roles personalizados calibrados. También se usa cuando un usuario cambia de función, cuando un servicio se da de baja, o cuando una auditoría revela privilegios asignados en exceso.\nQué puede salir mal #Un REVOKE mal planificado puede bloquear aplicaciones en producción. Si una aplicación se conecta con un usuario que pierde el privilegio CREATE SESSION, deja de funcionar instantáneamente. Por esto la revocación de privilegios críticos debe ir siempre precedida de un análisis de dependencias y un plan de despliegue gradual.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/revoke/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eREVOKE\u003c/strong\u003e es el comando SQL que elimina privilegios o roles previamente asignados con \u003ccode\u003eGRANT\u003c/code\u003e. Es el complemento indispensable del GRANT y la herramienta principal para restringir permisos cuando se reestructura un modelo de seguridad.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa sintaxis sigue el mismo esquema que GRANT: \u003ccode\u003eREVOKE SELECT ON schema.tabla FROM usuario\u003c/code\u003e o \u003ccode\u003eREVOKE rol FROM usuario\u003c/code\u003e. En Oracle, revocar un rol como \u003ccode\u003eDBA\u003c/code\u003e elimina de un solo golpe todos los system privileges incluidos en ese rol. Antes de ejecutar un REVOKE crítico, es fundamental verificar que el usuario mantenga los privilegios necesarios para sus funciones.\u003c/p\u003e","title":"REVOKE"},{"content":"RMAN (Recovery Manager) es la herramienta nativa de Oracle para el backup, restore y recovery de la base de datos. Es una utilidad de linea de comandos que gestiona todas las operaciones de proteccion de datos de forma integrada con la base de datos.\nQue hace # Backup: completos, incrementales, solo de archived logs Restore: recuperacion de datafiles, tablespaces o de toda la base de datos Recovery: aplicacion de redo logs para llevar la base de datos a un punto en el tiempo especifico Duplicate: creacion de copias de la base de datos, incluyendo bases de datos standby para Data Guard RMAN y Data Guard #Para la creacion de una base de datos standby, RMAN permite el DUPLICATE ... FOR STANDBY FROM ACTIVE DATABASE — una copia directa por red del primario al standby, sin necesidad de backups intermedios en cinta o disco. El comando transfiere todos los datafiles y controlfiles y los configura automaticamente para la replica.\nPor que RMAN y no copias manuales #RMAN conoce la estructura interna de la base de datos Oracle: sabe que bloques han cambiado (para los incrementales), que archivos se necesitan, como aplicar los redo. Una copia manual de archivos (con cp o rsync) no garantiza la consistencia y requiere que la base de datos este cerrada. RMAN puede trabajar con la base de datos abierta, con impacto minimo en el rendimiento.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/rman/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eRMAN\u003c/strong\u003e (Recovery Manager) es la herramienta nativa de Oracle para el backup, restore y recovery de la base de datos. Es una utilidad de linea de comandos que gestiona todas las operaciones de proteccion de datos de forma integrada con la base de datos.\u003c/p\u003e\n\u003ch2 id=\"que-hace\" class=\"relative group\"\u003eQue hace \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#que-hace\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eBackup\u003c/strong\u003e: completos, incrementales, solo de archived logs\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRestore\u003c/strong\u003e: recuperacion de datafiles, tablespaces o de toda la base de datos\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRecovery\u003c/strong\u003e: aplicacion de redo logs para llevar la base de datos a un punto en el tiempo especifico\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDuplicate\u003c/strong\u003e: creacion de copias de la base de datos, incluyendo bases de datos standby para Data Guard\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"rman-y-data-guard\" class=\"relative group\"\u003eRMAN y Data Guard \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#rman-y-data-guard\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePara la creacion de una base de datos standby, RMAN permite el \u003ccode\u003eDUPLICATE ... FOR STANDBY FROM ACTIVE DATABASE\u003c/code\u003e — una copia directa por red del primario al standby, sin necesidad de backups intermedios en cinta o disco. El comando transfiere todos los datafiles y controlfiles y los configura automaticamente para la replica.\u003c/p\u003e","title":"RMAN"},{"content":"El ROI (Return on Investment) es la métrica que mide el rendimiento de una inversión relacionando el beneficio neto con el coste incurrido, expresado como porcentaje. Un ROI del 200% significa que cada euro invertido generó dos de retorno.\nCómo funciona #Se calcula como: (Beneficio - Coste) / Coste × 100. En el contexto de proyectos IT con componentes IA, el cálculo del ROI debe incluir no solo los costes de implementación sino también los de mantenimiento, formación del equipo, governance y gestión de errores del modelo.\nPara qué sirve #El ROI es la herramienta principal para evaluar si una inversión en IA tiene sentido económico. Pero en el mercado actual es también la herramienta más abusada: proveedores que prometen ROI de tres cifras basándose en demos controladas, sin considerar los costes operativos reales. El AI Manager es quien verifica que los números sean reales, no de diapositivas.\nQué puede salir mal #Un ROI calculado solo sobre los beneficios inmediatos sin contar los costes ocultos (mantenimiento del modelo, retraining periódico, gestión de falsos positivos, compliance GDPR) es un ROI falso. La diferencia entre un proyecto IA exitoso y un fracaso costoso está casi siempre en la calidad del cálculo del ROI inicial.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/roi/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eROI\u003c/strong\u003e (Return on Investment) es la métrica que mide el rendimiento de una inversión relacionando el beneficio neto con el coste incurrido, expresado como porcentaje. Un ROI del 200% significa que cada euro invertido generó dos de retorno.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSe calcula como: \u003ccode\u003e(Beneficio - Coste) / Coste × 100\u003c/code\u003e. En el contexto de proyectos IT con componentes IA, el cálculo del ROI debe incluir no solo los costes de implementación sino también los de mantenimiento, formación del equipo, governance y gestión de errores del modelo.\u003c/p\u003e","title":"ROI"},{"content":"En PostgreSQL, ROLE es la única entidad de seguridad. No existe distinción entre \u0026ldquo;usuario\u0026rdquo; y \u0026ldquo;rol\u0026rdquo;: todo es un ROLE. Un ROLE con el atributo LOGIN se comporta como un usuario; sin LOGIN, es un contenedor de privilegios asignable a otros ROLEs.\nCómo funciona #CREATE USER mario es simplemente un atajo para CREATE ROLE mario WITH LOGIN. Los ROLEs pueden poseer objetos, heredar privilegios de otros ROLEs a través del atributo INHERIT, y ser utilizados para construir jerarquías de permisos. Un ROLE \u0026ldquo;funcional\u0026rdquo; (sin LOGIN) agrupa privilegios; los ROLEs \u0026ldquo;usuario\u0026rdquo; (con LOGIN) los heredan.\nPara qué sirve #El modelo unificado permite diseñar arquitecturas de seguridad limpias: se crean ROLEs funcionales como role_readonly o role_write, se asignan privilegios a los ROLEs funcionales, y luego se asignan esos ROLEs a los usuarios reales. Cuando llega un nuevo colega, basta un GRANT role_readonly TO nuevo_usuario.\nPor qué es crítico #La simplicidad del modelo es su punto fuerte — pero también una trampa si no se comprende. Muchos administradores asignan privilegios directamente a los usuarios en lugar de usar ROLEs funcionales, creando una maraña de GRANTs imposible de mantener. El modelo mental correcto es: los privilegios van a los ROLEs, los ROLEs van a los usuarios.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/postgresql-role/","section":"Glosario","summary":"\u003cp\u003eEn PostgreSQL, \u003cstrong\u003eROLE\u003c/strong\u003e es la única entidad de seguridad. No existe distinción entre \u0026ldquo;usuario\u0026rdquo; y \u0026ldquo;rol\u0026rdquo;: todo es un ROLE. Un ROLE con el atributo \u003ccode\u003eLOGIN\u003c/code\u003e se comporta como un usuario; sin \u003ccode\u003eLOGIN\u003c/code\u003e, es un contenedor de privilegios asignable a otros ROLEs.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003e\u003ccode\u003eCREATE USER mario\u003c/code\u003e es simplemente un atajo para \u003ccode\u003eCREATE ROLE mario WITH LOGIN\u003c/code\u003e. Los ROLEs pueden poseer objetos, heredar privilegios de otros ROLEs a través del atributo \u003ccode\u003eINHERIT\u003c/code\u003e, y ser utilizados para construir jerarquías de permisos. Un ROLE \u0026ldquo;funcional\u0026rdquo; (sin LOGIN) agrupa privilegios; los ROLEs \u0026ldquo;usuario\u0026rdquo; (con LOGIN) los heredan.\u003c/p\u003e","title":"ROLE"},{"content":"RPO (Recovery Point Objective) es la cantidad maxima de datos que una organizacion puede permitirse perder en caso de fallo o desastre. Se mide en tiempo: un RPO de 1 hora significa aceptar la perdida de como maximo la ultima hora de transacciones.\nComo se determina #El RPO depende de la estrategia de backup y replica:\nEstrategia RPO tipico Backup nocturno en cinta 12-24 horas Backup + archived logs en almacenamiento remoto 1-4 horas Data Guard asincrono (MaxPerformance) Pocos segundos Data Guard sincrono (MaxAvailability) Cero RPO vs RTO #RPO y RTO son complementarios pero distintos:\nRPO: cuantos datos puedes perder (mira hacia atras en el tiempo) RTO: cuanto tiempo se necesita para restaurar el servicio (mira hacia adelante en el tiempo) Una organizacion puede tener RPO=0 (cero perdida de datos) pero RTO=4 horas (se necesitan 4 horas para reiniciar), o viceversa.\nPor que importa #El RPO determina la inversion necesaria en infraestructura de replica. Pasar de RPO=24 horas a RPO=0 puede costar ordenes de magnitud mas, pero el coste debe compararse con el valor de los datos perdidos — como en el caso de seis horas de polizas de seguros no emitidas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/rpo/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eRPO\u003c/strong\u003e (Recovery Point Objective) es la cantidad maxima de datos que una organizacion puede permitirse perder en caso de fallo o desastre. Se mide en tiempo: un RPO de 1 hora significa aceptar la perdida de como maximo la ultima hora de transacciones.\u003c/p\u003e\n\u003ch2 id=\"como-se-determina\" class=\"relative group\"\u003eComo se determina \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-se-determina\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl RPO depende de la estrategia de backup y replica:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eEstrategia\u003c/th\u003e\n          \u003cth\u003eRPO tipico\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBackup nocturno en cinta\u003c/td\u003e\n          \u003ctd\u003e12-24 horas\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBackup + archived logs en almacenamiento remoto\u003c/td\u003e\n          \u003ctd\u003e1-4 horas\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard asincrono (MaxPerformance)\u003c/td\u003e\n          \u003ctd\u003ePocos segundos\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard sincrono (MaxAvailability)\u003c/td\u003e\n          \u003ctd\u003eCero\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"rpo-vs-rto\" class=\"relative group\"\u003eRPO vs RTO \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#rpo-vs-rto\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eRPO y RTO son complementarios pero distintos:\u003c/p\u003e","title":"RPO"},{"content":"RTO (Recovery Time Objective) es el tiempo maximo aceptable para restaurar el servicio despues de un fallo o desastre. Se mide desde el momento del fallo hasta el momento en que el sistema vuelve a estar operativo.\nComo se determina #El RTO depende de la estrategia de recuperacion y la infraestructura disponible:\nEstrategia RTO tipico Restore desde backup en cinta 4-12 horas Restore desde backup en disco 1-4 horas Data Guard con switchover manual 1-5 minutos Data Guard con Fast-Start Failover 10-30 segundos RTO vs RPO # RTO: cuanto tiempo se necesita para reiniciar (mira hacia adelante) RPO: cuantos datos puedes perder (mira hacia atras) Son metricas independientes. Un restore desde backup puede tener RTO=2 horas y RPO=24 horas. Un Data Guard sincrono puede tener RTO=30 segundos y RPO=0.\nEl impacto en el negocio #El RTO tiene un impacto directo y medible: cada minuto de parada se traduce en operaciones bloqueadas, clientes no atendidos, ingresos perdidos. La diferencia entre RTO=6 horas y RTO=42 segundos — como en el caso del paso de single instance a Data Guard — puede valer mas que el coste de toda la infraestructura.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/rto/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eRTO\u003c/strong\u003e (Recovery Time Objective) es el tiempo maximo aceptable para restaurar el servicio despues de un fallo o desastre. Se mide desde el momento del fallo hasta el momento en que el sistema vuelve a estar operativo.\u003c/p\u003e\n\u003ch2 id=\"como-se-determina\" class=\"relative group\"\u003eComo se determina \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-se-determina\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl RTO depende de la estrategia de recuperacion y la infraestructura disponible:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eEstrategia\u003c/th\u003e\n          \u003cth\u003eRTO tipico\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRestore desde backup en cinta\u003c/td\u003e\n          \u003ctd\u003e4-12 horas\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRestore desde backup en disco\u003c/td\u003e\n          \u003ctd\u003e1-4 horas\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard con switchover manual\u003c/td\u003e\n          \u003ctd\u003e1-5 minutos\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard con Fast-Start Failover\u003c/td\u003e\n          \u003ctd\u003e10-30 segundos\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"rto-vs-rpo\" class=\"relative group\"\u003eRTO vs RPO \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#rto-vs-rpo\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eRTO\u003c/strong\u003e: cuanto tiempo se necesita para reiniciar (mira hacia adelante)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRPO\u003c/strong\u003e: cuantos datos puedes perder (mira hacia atras)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSon metricas independientes. Un restore desde backup puede tener RTO=2 horas y RPO=24 horas. Un Data Guard sincrono puede tener RTO=30 segundos y RPO=0.\u003c/p\u003e","title":"RTO"},{"content":"El SCAN Listener (Single Client Access Name) es el componente de Oracle RAC que proporciona un unico nombre DNS para acceder al cluster. Las aplicaciones se conectan al SCAN name sin necesidad de conocer los nodos individuales: el listener distribuye automaticamente las conexiones entre los nodos activos.\nComo funciona #SCAN es un nombre DNS que resuelve a tres direcciones IP virtuales (VIP), distribuidas entre los nodos del cluster. Cuando un cliente se conecta al SCAN name, el DNS devuelve una de las tres IPs, y el listener en esa IP redirige la conexion al nodo mas apropiado segun el servicio solicitado y la carga.\nLa ventaja es que los connection strings de la aplicacion nunca cambian: si un nodo se anade o elimina del cluster, SCAN gestiona todo de forma transparente.\nConfiguracion tipica #Un connection string que usa SCAN:\njdbc:oracle:thin:@//scan-name.example.com:1521/service_name Las tres SCAN VIP se ejecutan en cualquier nodo del cluster. En un cluster de dos nodos, un nodo aloja dos VIPs y el otro uno (o viceversa).\nEn las migraciones #En las migraciones a OCI, el SCAN listener se reconfigura con el DNS de la nueva infraestructura. Es uno de los pasos del cutover: actualizar los connection strings para apuntar al nuevo SCAN name en OCI. Si el naming esta bien gestionado, es un cambio en un solo punto (el connection pool de la aplicacion), no en decenas de archivos de configuracion dispersos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/scan-listener/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eSCAN Listener\u003c/strong\u003e (Single Client Access Name) es el componente de Oracle RAC que proporciona un unico nombre DNS para acceder al cluster. Las aplicaciones se conectan al SCAN name sin necesidad de conocer los nodos individuales: el listener distribuye automaticamente las conexiones entre los nodos activos.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSCAN es un nombre DNS que resuelve a tres direcciones IP virtuales (VIP), distribuidas entre los nodos del cluster. Cuando un cliente se conecta al SCAN name, el DNS devuelve una de las tres IPs, y el listener en esa IP redirige la conexion al nodo mas apropiado segun el servicio solicitado y la carga.\u003c/p\u003e","title":"SCAN Listener"},{"content":"SCD (Slowly Changing Dimension) indica un conjunto de tecnicas usadas en data warehouse para gestionar los cambios en los datos de las tablas dimensionales a lo largo del tiempo.\nTipos principales # Tipo 1: sobreescritura del valor anterior. No se conserva historia Tipo 2: insercion de una nueva fila con fechas de validez (fecha inicio, fecha fin). Conserva toda la historia Tipo 3: adicion de una columna para el valor anterior. Conserva solo el ultimo cambio Por que es importante #En una base de datos transaccional, cuando un cliente cambia de direccion se actualiza el registro. En un data warehouse esto significaria perder la historia: todas las ventas anteriores aparecerian asociadas a la nueva direccion.\nLa SCD Tipo 2 resuelve este problema manteniendo una fila por cada version del dato, con fechas de validez que permiten reconstruir la situacion en cualquier punto en el tiempo.\nCuando se usa #La eleccion del tipo depende del requisito de negocio. Si solo importa el dato actual, el Tipo 1 es suficiente. Si el negocio necesita analisis historicos precisos — y en la mayoria de los data warehouses reales asi es — el Tipo 2 es la eleccion estandar.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/scd/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eSCD\u003c/strong\u003e (Slowly Changing Dimension) indica un conjunto de tecnicas usadas en data warehouse para gestionar los cambios en los datos de las tablas dimensionales a lo largo del tiempo.\u003c/p\u003e\n\u003ch2 id=\"tipos-principales\" class=\"relative group\"\u003eTipos principales \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#tipos-principales\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eTipo 1\u003c/strong\u003e: sobreescritura del valor anterior. No se conserva historia\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTipo 2\u003c/strong\u003e: insercion de una nueva fila con fechas de validez (fecha inicio, fecha fin). Conserva toda la historia\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTipo 3\u003c/strong\u003e: adicion de una columna para el valor anterior. Conserva solo el ultimo cambio\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"por-que-es-importante\" class=\"relative group\"\u003ePor que es importante \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#por-que-es-importante\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn una base de datos transaccional, cuando un cliente cambia de direccion se actualiza el registro. En un data warehouse esto significaria perder la historia: todas las ventas anteriores aparecerian asociadas a la nueva direccion.\u003c/p\u003e","title":"SCD"},{"content":"Un Schema en una base de datos relacional es un namespace lógico que agrupa objetos como tablas, vistas, funciones y secuencias. Funciona como un contenedor organizativo dentro de una base de datos.\nCómo funciona #En PostgreSQL, el schema predeterminado es public. Para acceder a un objeto en otro schema se necesita el prefijo: schema1.tabla. El privilegio USAGE sobre un schema es prerequisito para acceder a cualquier objeto dentro de él — sin USAGE, ni siquiera un GRANT SELECT sobre las tablas funciona.\nPara qué sirve #Los schemas permiten separar lógicamente los datos: un schema para la aplicación, uno para reporting, uno para las tablas de staging. En Oracle, el concepto es diferente: cada usuario es automáticamente un schema, y los objetos creados por ese usuario viven en su schema. En PostgreSQL, schemas y usuarios son entidades independientes.\nPor qué es crítico #La gestión de permisos sobre los schemas es la fuente más común de errores al crear usuarios con acceso limitado. Olvidar el GRANT USAGE ON SCHEMA es el error clásico que genera \u0026ldquo;permission denied for schema\u0026rdquo; incluso cuando los permisos sobre las tablas son correctos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/schema/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eSchema\u003c/strong\u003e en una base de datos relacional es un namespace lógico que agrupa objetos como tablas, vistas, funciones y secuencias. Funciona como un contenedor organizativo dentro de una base de datos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn PostgreSQL, el schema predeterminado es \u003ccode\u003epublic\u003c/code\u003e. Para acceder a un objeto en otro schema se necesita el prefijo: \u003ccode\u003eschema1.tabla\u003c/code\u003e. El privilegio \u003ccode\u003eUSAGE\u003c/code\u003e sobre un schema es prerequisito para acceder a cualquier objeto dentro de él — sin \u003ccode\u003eUSAGE\u003c/code\u003e, ni siquiera un \u003ccode\u003eGRANT SELECT\u003c/code\u003e sobre las tablas funciona.\u003c/p\u003e","title":"Schema"},{"content":"El Scope (alcance) de un proyecto define el perímetro de lo que el proyecto debe realizar: funcionalidades incluidas, entregables esperados, restricciones y límites acordados con los stakeholders. Todo lo que está dentro del scope se hace; todo lo que está fuera, no.\nCómo funciona #El scope se define en las fases iniciales del proyecto a través de documentos como el Statement of Work o el Project Charter. Cualquier solicitud de cambio posterior debe pasar por un proceso formal de gestión de cambios para evaluar su impacto en plazos, costes y recursos.\nPor qué es crítico #El scope creep — la expansión incontrolada de los requisitos — está entre las causas principales de fracaso de los proyectos IT. Cada feature añadida sin reevaluar plazos y presupuesto erosiona los recursos disponibles. Un PM efectivo sabe decir \u0026ldquo;sí, y para incluirlo debemos quitar esto otro\u0026rdquo; — no simplemente \u0026ldquo;no\u0026rdquo;.\nCuándo se usa #En cada fase del proyecto: en la planificación para definir los límites, durante la ejecución para evaluar las solicitudes de cambio, en las negociaciones con stakeholders para redirigir las expectativas. La claridad sobre el scope es la base de toda decisión de proyecto.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/scope/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eScope\u003c/strong\u003e (alcance) de un proyecto define el perímetro de lo que el proyecto debe realizar: funcionalidades incluidas, entregables esperados, restricciones y límites acordados con los stakeholders. Todo lo que está dentro del scope se hace; todo lo que está fuera, no.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl scope se define en las fases iniciales del proyecto a través de documentos como el Statement of Work o el Project Charter. Cualquier solicitud de cambio posterior debe pasar por un proceso formal de gestión de cambios para evaluar su impacto en plazos, costes y recursos.\u003c/p\u003e","title":"Scope"},{"content":"El Scope Creep es la expansión progresiva y frecuentemente no controlada del alcance de un proyecto respecto a lo definido inicialmente. Nuevos requisitos, modificaciones a las especificaciones y funcionalidades adicionales se acumulan sin un correspondiente ajuste de presupuesto y plazos.\nCómo funciona #En un proyecto software, el scope creep empieza típicamente con peticiones aparentemente pequeñas: \u0026ldquo;añadamos también este campo\u0026rdquo;, \u0026ldquo;sería útil también esta función\u0026rdquo;. Cada modificación individual parece razonable, pero el efecto acumulativo es devastador. Las especificaciones se convierten en un objetivo móvil, el equipo nunca logra alcanzar una baseline estable, y el proyecto entra en un ciclo infinito de revisiones.\nPara qué sirve #Reconocer el scope creep es el primer paso para prevenirlo. Los mecanismos de defensa incluyen: change requests formales con análisis de impacto, congelación de especificaciones por fase, priorización rigurosa y la capacidad de decir \u0026ldquo;no\u0026rdquo; — o al menos \u0026ldquo;ahora no\u0026rdquo;.\nCuándo se usa #El término describe un anti-patrón de project management a evitar. En los grandes proyectos de consultoría, el scope creep se convierte frecuentemente en un arma en manos del proveedor: las especificaciones incompletas justifican retrasos y costes adicionales, transformando un proyecto a cuerpo en una consultoría a tiempo indefinido.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/scope-creep/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eScope Creep\u003c/strong\u003e es la expansión progresiva y frecuentemente no controlada del alcance de un proyecto respecto a lo definido inicialmente. Nuevos requisitos, modificaciones a las especificaciones y funcionalidades adicionales se acumulan sin un correspondiente ajuste de presupuesto y plazos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn un proyecto software, el scope creep empieza típicamente con peticiones aparentemente pequeñas: \u0026ldquo;añadamos también este campo\u0026rdquo;, \u0026ldquo;sería útil también esta función\u0026rdquo;. Cada modificación individual parece razonable, pero el efecto acumulativo es devastador. Las especificaciones se convierten en un objetivo móvil, el equipo nunca logra alcanzar una baseline estable, y el proyecto entra en un ciclo infinito de revisiones.\u003c/p\u003e","title":"Scope Creep"},{"content":"Scrum es un framework ágil para la gestión de proyectos que organiza el trabajo en iteraciones de duración fija llamadas sprints (típicamente 2 semanas). Define tres roles (Product Owner, Scrum Master, Development Team) y cuatro ceremonias (Sprint Planning, Daily Standup, Sprint Review, Sprint Retrospective).\nCómo funciona #Cada sprint comienza con una planificación, continúa con standups diarios para la sincronización, y termina con una review (qué se hizo) y una retrospectiva (cómo mejorar el proceso). El timeboxing es el principio fundamental: cada ceremonia tiene una duración máxima no negociable.\nPara qué sirve #Scrum proporciona estructura a equipos que trabajan en proyectos complejos con requisitos en evolución. El ciclo corto de los sprints permite feedback rápido, correcciones de rumbo frecuentes y visibilidad continua sobre el estado del proyecto. El standup diario es una de las ceremonias más reconocibles del framework.\nQué puede salir mal #El riesgo más común es adoptar Scrum como ritual sin entender sus principios. Equipos que hacen el standup pero no respetan el timebox, sprints sin un objetivo claro, retrospectivas que no producen acciones concretas. Scrum funciona cuando se aplica con disciplina, no cuando es solo una etiqueta.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/scrum/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eScrum\u003c/strong\u003e es un framework ágil para la gestión de proyectos que organiza el trabajo en iteraciones de duración fija llamadas sprints (típicamente 2 semanas). Define tres roles (Product Owner, Scrum Master, Development Team) y cuatro ceremonias (Sprint Planning, Daily Standup, Sprint Review, Sprint Retrospective).\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada sprint comienza con una planificación, continúa con standups diarios para la sincronización, y termina con una review (qué se hizo) y una retrospectiva (cómo mejorar el proceso). El timeboxing es el principio fundamental: cada ceremonia tiene una duración máxima no negociable.\u003c/p\u003e","title":"Scrum"},{"content":"secure-file-priv es una variable de sistema MySQL que controla dónde las instrucciones LOAD DATA INFILE, SELECT INTO OUTFILE y la función LOAD_FILE() pueden operar en el filesystem del servidor.\nCómo funciona #La variable acepta tres valores: una ruta específica (ej. /var/lib/mysql-files/), que limita las operaciones sobre archivos a ese directorio; una cadena vacía (\u0026quot;\u0026quot;), que no impone restricciones; o NULL, que deshabilita completamente las operaciones sobre archivos. El valor solo se puede configurar en el archivo de configuración (my.cnf) y requiere reinicio del servicio para modificarse — no se puede cambiar en tiempo de ejecución.\nPara qué sirve #La directiva previene el acceso arbitrario al filesystem por parte de usuarios MySQL con el privilegio FILE. Sin esta protección, un atacante que explota una SQL injection podría leer archivos del sistema (ej. /etc/passwd, llaves SSH) o escribir web shells en el webroot de un servidor web en el mismo host.\nCuándo se usa #secure-file-priv debe configurarse al momento del setup de cada instancia MySQL, especificando un directorio dedicado. En entornos multi-instancia, cada instancia debería tener su propio directorio secure-file-priv. Si el export a archivo está bloqueado, la alternativa recomendada es usar el cliente mysql desde shell con las opciones -B y -e para redirigir la salida.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/secure-file-priv/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003esecure-file-priv\u003c/strong\u003e es una variable de sistema MySQL que controla dónde las instrucciones \u003ccode\u003eLOAD DATA INFILE\u003c/code\u003e, \u003ccode\u003eSELECT INTO OUTFILE\u003c/code\u003e y la función \u003ccode\u003eLOAD_FILE()\u003c/code\u003e pueden operar en el filesystem del servidor.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa variable acepta tres valores: una ruta específica (ej. \u003ccode\u003e/var/lib/mysql-files/\u003c/code\u003e), que limita las operaciones sobre archivos a ese directorio; una cadena vacía (\u003ccode\u003e\u0026quot;\u0026quot;\u003c/code\u003e), que no impone restricciones; o \u003ccode\u003eNULL\u003c/code\u003e, que deshabilita completamente las operaciones sobre archivos. El valor solo se puede configurar en el archivo de configuración (\u003ccode\u003emy.cnf\u003c/code\u003e) y requiere reinicio del servicio para modificarse — no se puede cambiar en tiempo de ejecución.\u003c/p\u003e","title":"secure-file-priv"},{"content":"El self-parenting es una técnica de dimensional modeling usada para balancear las jerarquías desequilibradas (ragged hierarchies). El principio es simple: una entidad que no tiene un nivel jerárquico superior se convierte en su propio padre a ese nivel.\nCómo funciona #En una jerarquía de tres niveles Top Group → Group → Client:\nUn Client sin Group usa su propio nombre/ID como Group Un Group sin Top Group usa su propio nombre/ID como Top Group El resultado es una tabla dimensional sin NULLs en las columnas jerárquicas, con todos los niveles siempre poblados.\nLos flags de distinción #Para no perder la información sobre qué entidades fueron balanceadas artificialmente, se agregan flags a la dimensión:\nis_direct_client = 'Y': el cliente no tenía un Group en la fuente is_standalone_group = 'Y': el Group no tenía un Top Group en la fuente Estos flags permiten al negocio filtrar los \u0026ldquo;verdaderos\u0026rdquo; top groups de los clientes promovidos.\nPor qué en el ETL y no en el reporte #El self-parenting se aplica una vez en el ETL, no en cada reporte individual. Un reporte debería hacer GROUP BY y JOIN, no decidir cómo gestionar los niveles faltantes. Si la lógica de balanceo está en el modelo, todos los reportes se benefician automáticamente.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/self-parenting/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eself-parenting\u003c/strong\u003e es una técnica de dimensional modeling usada para balancear las jerarquías desequilibradas (ragged hierarchies). El principio es simple: una entidad que no tiene un nivel jerárquico superior se convierte en su propio padre a ese nivel.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn una jerarquía de tres niveles Top Group → Group → Client:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUn Client sin Group usa su propio nombre/ID como Group\u003c/li\u003e\n\u003cli\u003eUn Group sin Top Group usa su propio nombre/ID como Top Group\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eEl resultado es una tabla dimensional sin NULLs en las columnas jerárquicas, con todos los niveles siempre poblados.\u003c/p\u003e","title":"Self-parenting"},{"content":"El Sequential Scan (Seq Scan) es la operación con la que PostgreSQL lee una tabla de principio a fin, bloque por bloque, sin utilizar ningún índice. Es el equivalente en PostgreSQL del Full Table Scan de Oracle.\nCuándo es normal #En tablas pequeñas (unos pocos miles de filas), el sequential scan suele ser la opción más eficiente. Leer una tabla entera en secuencia es más rápido que hacer lookups en un índice cuando la tabla cabe en pocas páginas. El optimizer elige el sequential scan cuando estima que es más económico que un index scan.\nCuándo es un problema #En tablas grandes (millones de filas), un sequential scan para devolver pocas filas es una señal de alarma. Significa que falta un índice apropiado o que las estadísticas de la tabla están obsoletas y el optimizer hace estimaciones erróneas. pg_stat_statements ayuda a identificar estas situaciones mostrando las queries con peor ratio bloques leídos / filas devueltas.\nCómo diagnosticarlo #EXPLAIN muestra \u0026ldquo;Seq Scan on tabla\u0026rdquo; en el plan de ejecución. Si el filtro posterior descarta la mayoría de las filas (rows removed by filter \u0026raquo; rows), casi con certeza se necesita un índice en la columna del filtro.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/sequential-scan/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eSequential Scan\u003c/strong\u003e (Seq Scan) es la operación con la que PostgreSQL lee una tabla de principio a fin, bloque por bloque, sin utilizar ningún índice. Es el equivalente en PostgreSQL del Full Table Scan de Oracle.\u003c/p\u003e\n\u003ch2 id=\"cuándo-es-normal\" class=\"relative group\"\u003eCuándo es normal \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#cu%c3%a1ndo-es-normal\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn tablas pequeñas (unos pocos miles de filas), el sequential scan suele ser la opción más eficiente. Leer una tabla entera en secuencia es más rápido que hacer lookups en un índice cuando la tabla cabe en pocas páginas. El optimizer elige el sequential scan cuando estima que es más económico que un index scan.\u003c/p\u003e","title":"Sequential Scan"},{"content":"La SGA (System Global Area) es el área de memoria compartida principal de Oracle Database. Contiene las estructuras de datos fundamentales: buffer cache (páginas de datos leídas de disco), shared pool (planes de ejecución y diccionario de datos), redo log buffer y large pool.\nCómo funciona #El tamaño de la SGA se controla con el parámetro SGA_TARGET o SGA_MAX_SIZE. Oracle asigna la SGA al inicio de la instancia en la memoria compartida del sistema operativo. Los parámetros del kernel Linux shmmax y shmall deben dimensionarse para permitir la asignación completa de la SGA.\nPara qué sirve #Toda la actividad de lectura y escritura de la base de datos pasa a través de la SGA. Un buffer cache eficiente evita lecturas físicas de disco. Un shared pool bien dimensionado evita el re-parsing de las queries. La SGA es el corazón del rendimiento Oracle — y debe residir en Huge Pages para maximizar la eficiencia.\nPor qué es crítico #Una SGA no asignada en Huge Pages significa millones de entradas en la Page Table y overflow constante del TLB. El resultado son latch free waits, library cache contention y CPU elevada. Configurar las Huge Pages y el parámetro memlock unlimited para el usuario oracle es el prerequisito para cualquier tuning serio.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/sga/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eSGA\u003c/strong\u003e (System Global Area) es el área de memoria compartida principal de Oracle Database. Contiene las estructuras de datos fundamentales: buffer cache (páginas de datos leídas de disco), shared pool (planes de ejecución y diccionario de datos), redo log buffer y large pool.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl tamaño de la SGA se controla con el parámetro \u003ccode\u003eSGA_TARGET\u003c/code\u003e o \u003ccode\u003eSGA_MAX_SIZE\u003c/code\u003e. Oracle asigna la SGA al inicio de la instancia en la memoria compartida del sistema operativo. Los parámetros del kernel Linux \u003ccode\u003eshmmax\u003c/code\u003e y \u003ccode\u003eshmall\u003c/code\u003e deben dimensionarse para permitir la asignación completa de la SGA.\u003c/p\u003e","title":"SGA"},{"content":"shared_buffers es el parámetro que controla el tamaño del área de memoria compartida que PostgreSQL usa como caché para los bloques de datos leídos del disco. Cada vez que PostgreSQL lee una página de datos (8 KB), la conserva en shared_buffers para las lecturas posteriores.\nCómo funciona #PostgreSQL asigna la memoria para shared_buffers al arranque del servicio. Todos los procesos backend comparten esta área de memoria. Cuando un proceso necesita un bloque de datos, busca primero en shared_buffers. Si lo encuentra (cache hit), la lectura es inmediata. Si no lo encuentra (cache miss), debe leer del disco — una operación órdenes de magnitud más lenta.\nCuánto asignar #El valor por defecto es 128 MB — inadecuado para cualquier base de datos de producción. La regla empírica es configurar shared_buffers al 25% de la RAM disponible. En un servidor con 64 GB de RAM, 16 GB es un buen punto de partida. Valores por encima del 40% de la RAM raramente aportan beneficios porque PostgreSQL también se apoya en la caché del sistema operativo.\nCómo monitorizarlo #La vista pg_stat_bgwriter muestra la relación entre buffers_alloc (nuevos bloques asignados) y el total de bloques servidos. Un cache hit ratio por debajo del 95% sugiere que shared_buffers podría estar subdimensionado.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/shared-buffers/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eshared_buffers\u003c/strong\u003e es el parámetro que controla el tamaño del área de memoria compartida que PostgreSQL usa como caché para los bloques de datos leídos del disco. Cada vez que PostgreSQL lee una página de datos (8 KB), la conserva en shared_buffers para las lecturas posteriores.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePostgreSQL asigna la memoria para shared_buffers al arranque del servicio. Todos los procesos backend comparten esta área de memoria. Cuando un proceso necesita un bloque de datos, busca primero en shared_buffers. Si lo encuentra (cache hit), la lectura es inmediata. Si no lo encuentra (cache miss), debe leer del disco — una operación órdenes de magnitud más lenta.\u003c/p\u003e","title":"shared_buffers"},{"content":"Single-primary es el modo operativo más común de MySQL Group Replication, donde solo un nodo del cluster — el primary — acepta operaciones de escritura. Los demás nodos (secondary) son de solo lectura (read_only=ON, super_read_only=ON) y reciben las modificaciones a través de la replicación síncrona del grupo.\nCómo funciona #El parámetro group_replication_single_primary_mode=ON activa este modo. El primary es el único nodo con read_only=OFF. Si el primary se detiene o se vuelve inaccesible, el cluster ejecuta una elección automática y uno de los secondary se convierte en el nuevo primary en pocos segundos.\nPor qué se usa #El modo single-primary evita los conflictos de escritura concurrente típicos del multi-primary. En producción la mayoría de los clusters MySQL usan este modo porque es más predecible: las aplicaciones escriben en un solo endpoint, la replicación es lineal y el debugging es más sencillo.\nQué puede salir mal #Cuando se detiene el primary por mantenimiento, el cluster realiza un failover automático. Durante esos segundos las conexiones activas pueden caerse y las transacciones en curso pueden fallar. Es una interrupción breve pero debe comunicarse. La regla práctica: en una intervención de mantenimiento sobre un cluster single-primary, los secondary se tocan primero, el primary de último.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/single-primary/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eSingle-primary\u003c/strong\u003e es el modo operativo más común de MySQL Group Replication, donde solo un nodo del cluster — el primary — acepta operaciones de escritura. Los demás nodos (secondary) son de solo lectura (\u003ccode\u003eread_only=ON\u003c/code\u003e, \u003ccode\u003esuper_read_only=ON\u003c/code\u003e) y reciben las modificaciones a través de la replicación síncrona del grupo.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl parámetro \u003ccode\u003egroup_replication_single_primary_mode=ON\u003c/code\u003e activa este modo. El primary es el único nodo con \u003ccode\u003eread_only=OFF\u003c/code\u003e. Si el primary se detiene o se vuelve inaccesible, el cluster ejecuta una elección automática y uno de los secondary se convierte en el nuevo primary en pocos segundos.\u003c/p\u003e","title":"Single-primary"},{"content":"El Smart Working (trabajo ágil) es un modelo organizativo que permite al empleado trabajar desde cualquier lugar, combinando días en oficina y días en remoto, con horarios flexibles y evaluación basada en resultados en lugar de presencia.\nCómo funciona #El modelo típico es 80/20: 80% remoto, 20% presencial. Los días en oficina sirven para workshops, revisiones de proyecto y team building — no para calentar la silla. La empresa proporciona equipamiento para el puesto doméstico (monitor, silla ergonómica, auriculares) y una contribución para la conectividad.\nPara qué sirve #En la consultoría IT, el smart working elimina el coste del pendularismo (hasta 90 horas/mes para un consultor romano), reduce los costes inmobiliarios (de 50 puestos fijos a 15 hot desks) y restituye horas de productividad real. Un consultor que empieza a trabajar a las 7:45 fresco y concentrado produce más que uno que llega a las 9:30 estresado por el tráfico.\nPor qué es crítico #El smart working no es un beneficio — es un modelo organizativo que requiere KPIs claros, confianza recíproca y herramientas de comunicación adecuadas. Las empresas que lo adoptan como \u0026ldquo;concesión\u0026rdquo; en lugar de \u0026ldquo;estrategia\u0026rdquo; pierden sus beneficios. Las que lo rechazan por presentismo pagan un coste invisible en productividad perdida y talento en fuga.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/smart-working/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eSmart Working\u003c/strong\u003e (trabajo ágil) es un modelo organizativo que permite al empleado trabajar desde cualquier lugar, combinando días en oficina y días en remoto, con horarios flexibles y evaluación basada en resultados en lugar de presencia.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl modelo típico es 80/20: 80% remoto, 20% presencial. Los días en oficina sirven para workshops, revisiones de proyecto y team building — no para calentar la silla. La empresa proporciona equipamiento para el puesto doméstico (monitor, silla ergonómica, auriculares) y una contribución para la conectividad.\u003c/p\u003e","title":"Smart Working"},{"content":"Snapshot en Oracle es una captura puntual de las estadisticas de rendimiento de la base de datos almacenada en el repositorio AWR. Por defecto Oracle genera un snapshot cada 60 minutos y los conserva durante 8 dias.\nComo funciona #Cada snapshot registra cientos de metricas: wait events, estadisticas SQL, metricas de memoria (SGA, PGA), I/O por datafile, estadisticas de sistema. La comparacion entre dos snapshots genera el informe AWR, que muestra que cambio entre los dos instantes.\nSnapshots manuales #En situaciones de emergencia se puede generar un snapshot manual para capturar el estado actual:\nEXEC DBMS_WORKLOAD_REPOSITORY.create_snapshot; Esto es util cuando se quiere un punto de referencia inmediato — por ejemplo, antes y despues de un deploy — sin esperar al ciclo automatico.\nGestion #Los snapshots son consultables a traves de la vista DBA_HIST_SNAPSHOT. La retencion (cuantos dias conservarlos) y el intervalo (cada cuantos minutos generarlos) se configuran con:\nEXEC DBMS_WORKLOAD_REPOSITORY.modify_snapshot_settings( retention =\u0026gt; 43200, -- 30 dias en minutos interval =\u0026gt; 30 -- cada 30 minutos ); Por que son importantes #Sin snapshots, no hay AWR. Sin AWR, el diagnostico de un problema de rendimiento se convierte en un ejercicio de intuicion en lugar de un analisis basado en datos. Los snapshots son los cimientos de la observabilidad en Oracle.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/snapshot-oracle/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eSnapshot\u003c/strong\u003e en Oracle es una captura puntual de las estadisticas de rendimiento de la base de datos almacenada en el repositorio AWR. Por defecto Oracle genera un snapshot cada 60 minutos y los conserva durante 8 dias.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada snapshot registra cientos de metricas: wait events, estadisticas SQL, metricas de memoria (SGA, PGA), I/O por datafile, estadisticas de sistema. La comparacion entre dos snapshots genera el informe AWR, que muestra que cambio entre los dos instantes.\u003c/p\u003e","title":"Snapshot (Oracle)"},{"content":"El split-brain es una condición crítica que se produce cuando un cluster de bases de datos se divide en dos o más particiones que no pueden comunicarse entre sí, y cada partición continúa aceptando escrituras independientemente. El resultado son datos divergentes imposibles de reconciliar automáticamente.\nCómo funciona #En un cluster de 3 nodos, si la red entre el Nodo 1 y los Nodos 2-3 se interrumpe, sin protección del quorum ambas partes podrían seguir aceptando escrituras. Cuando la red se restablece, el cluster se encontraría con dos versiones diferentes de los mismos datos. El mecanismo de quorum previene este escenario: solo la partición con la mayoría de nodos (quorum) puede seguir operando.\nPara qué sirve #Comprender el split-brain es fundamental para diseñar clusters de bases de datos fiables. Es la razón principal por la que Galera Cluster requiere un número impar de nodos (3, 5, 7) e implementa el mecanismo de quorum. Con un número par de nodos, una partición de red puede dividir el cluster en dos mitades iguales, ninguna de las cuales tiene quorum.\nCuándo se usa #El término split-brain describe un riesgo a evitar, no una funcionalidad a activar. En Galera, la protección es automática: los nodos que pierden el quorum pasan al estado Non-Primary y rechazan las escrituras. El parámetro pc.ignore_quorum desactiva esta protección, pero usarlo en producción está fuertemente desaconsejado.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/split-brain/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003esplit-brain\u003c/strong\u003e es una condición crítica que se produce cuando un cluster de bases de datos se divide en dos o más particiones que no pueden comunicarse entre sí, y cada partición continúa aceptando escrituras independientemente. El resultado son datos divergentes imposibles de reconciliar automáticamente.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn un cluster de 3 nodos, si la red entre el Nodo 1 y los Nodos 2-3 se interrumpe, sin protección del quorum ambas partes podrían seguir aceptando escrituras. Cuando la red se restablece, el cluster se encontraría con dos versiones diferentes de los mismos datos. El mecanismo de quorum previene este escenario: solo la partición con la mayoría de nodos (quorum) puede seguir operando.\u003c/p\u003e","title":"Split-brain"},{"content":"La SQL Injection es una de las vulnerabilidades más extendidas y peligrosas en aplicaciones web. Se produce cuando los inputs proporcionados por el usuario se insertan directamente en las queries SQL sin validación ni parametrización, permitiendo a un atacante modificar la lógica de la query.\nCómo funciona #El atacante inserta fragmentos de código SQL en los campos de input de la aplicación (formularios de login, campos de búsqueda, parámetros URL). Si la aplicación concatena estos inputs directamente en las queries SQL, el código malicioso es ejecutado por la base de datos con los privilegios del usuario aplicativo. En combinación con el privilegio FILE de MySQL y un secure-file-priv no configurado, el atacante puede leer archivos del sistema o escribir archivos arbitrarios en el servidor.\nPara qué sirve #Comprender la SQL injection es fundamental para quien gestiona bases de datos en producción, porque muchas configuraciones de seguridad (como secure-file-priv, la gestión de privilegios y la separación de usuarios) existen específicamente para mitigar el impacto de este tipo de ataque.\nCuándo se usa #El término describe un ataque a prevenir, no una técnica a utilizar. Las contramedidas principales son: queries parametrizadas (prepared statements), validación de inputs, principio de mínimo privilegio para los usuarios de base de datos, y configuración correcta de directivas como secure-file-priv.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/sql-injection/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eSQL Injection\u003c/strong\u003e es una de las vulnerabilidades más extendidas y peligrosas en aplicaciones web. Se produce cuando los inputs proporcionados por el usuario se insertan directamente en las queries SQL sin validación ni parametrización, permitiendo a un atacante modificar la lógica de la query.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl atacante inserta fragmentos de código SQL en los campos de input de la aplicación (formularios de login, campos de búsqueda, parámetros URL). Si la aplicación concatena estos inputs directamente en las queries SQL, el código malicioso es ejecutado por la base de datos con los privilegios del usuario aplicativo. En combinación con el privilegio \u003ccode\u003eFILE\u003c/code\u003e de MySQL y un \u003ccode\u003esecure-file-priv\u003c/code\u003e no configurado, el atacante puede leer archivos del sistema o escribir archivos arbitrarios en el servidor.\u003c/p\u003e","title":"SQL Injection"},{"content":"SST (State Snapshot Transfer) es el mecanismo por el cual un nodo Galera que se une al cluster (o que ha estado offline demasiado tiempo) recibe una copia completa del dataset entero desde un nodo donante.\nCómo funciona #Cuando un nodo se une al cluster y el gap de transacciones faltantes supera el tamaño del gcache, el cluster inicia un SST. El nodo donante crea una instantánea completa de la base de datos y la transfiere al nodo receptor. Los métodos disponibles son: mariabackup (no bloquea al donante), rsync (rápido pero bloquea al donante en lectura), y mysqldump (lento y bloqueante).\nPara qué sirve #SST es esencial para dos escenarios: la adición de un nuevo nodo al cluster (primer join) y la recuperación de un nodo que ha estado offline tanto tiempo que las transacciones faltantes ya no están disponibles en el gcache del donante.\nCuándo se usa #SST se activa automáticamente por Galera cuando es necesario. La elección del método SST (wsrep_sst_method) se hace durante la configuración. En producción, mariabackup es la opción recomendada porque no bloquea al nodo donante, evitando degradar el cluster durante la transferencia.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/sst/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eSST\u003c/strong\u003e (State Snapshot Transfer) es el mecanismo por el cual un nodo Galera que se une al cluster (o que ha estado offline demasiado tiempo) recibe una copia completa del dataset entero desde un nodo donante.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando un nodo se une al cluster y el gap de transacciones faltantes supera el tamaño del gcache, el cluster inicia un SST. El nodo donante crea una instantánea completa de la base de datos y la transfiere al nodo receptor. Los métodos disponibles son: \u003ccode\u003emariabackup\u003c/code\u003e (no bloquea al donante), \u003ccode\u003ersync\u003c/code\u003e (rápido pero bloquea al donante en lectura), y \u003ccode\u003emysqldump\u003c/code\u003e (lento y bloqueante).\u003c/p\u003e","title":"SST"},{"content":"Un Stakeholder es cualquier persona, grupo u organización con un interés directo o indirecto en el resultado de un proyecto. Incluye clientes, sponsors, usuarios finales, equipos de desarrollo, management y proveedores externos.\nCómo funciona #En el project management, los stakeholders se identifican, clasifican por nivel de influencia e interés, y se gestionan con estrategias de comunicación diferenciadas. Un stakeholder de alta influencia y alto interés (como el CTO) requiere involucramiento activo; uno de baja influencia requiere solo actualizaciones periódicas.\nPor qué es crítico #La mayoría de los fracasos de proyectos no son técnicos — son relacionales. Stakeholders no alineados, expectativas no gestionadas y comunicación deficiente son las causas más frecuentes de retrasos, scope creep y conflictos. El PM efectivo dedica más tiempo a gestionar stakeholders que a gestionar cronogramas.\nCuándo se usa #En cada fase del proyecto: en la definición de requisitos (quién decide qué se construye), en la planificación (quién aprueba los recursos), en la ejecución (quién valida los entregables) y en el cierre (quién acepta el resultado). Ignorar a un stakeholder clave es la forma más rápida de descarrilar un proyecto.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/stakeholder/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eStakeholder\u003c/strong\u003e es cualquier persona, grupo u organización con un interés directo o indirecto en el resultado de un proyecto. Incluye clientes, sponsors, usuarios finales, equipos de desarrollo, management y proveedores externos.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEn el project management, los stakeholders se identifican, clasifican por nivel de influencia e interés, y se gestionan con estrategias de comunicación diferenciadas. Un stakeholder de alta influencia y alto interés (como el CTO) requiere involucramiento activo; uno de baja influencia requiere solo actualizaciones periódicas.\u003c/p\u003e","title":"Stakeholder"},{"content":"El star schema (esquema en estrella) es el modelo de datos más utilizado en el data warehouse. Toma su nombre de su forma: una tabla central de hechos (fact table) conectada a múltiples tablas dimensionales que la rodean, como los rayos de una estrella.\nEstructura # Fact table en el centro: contiene las medidas numéricas y las claves foráneas hacia las dimensiones Dimension tables alrededor: contienen los atributos descriptivos (quién, qué, dónde, cuándo) con estructura desnormalizada Las dimensiones en un star schema están típicamente desnormalizadas — todos los atributos en una sola tabla plana, sin jerarquías normalizadas. Esto simplifica las consultas y mejora el rendimiento de las agregaciones.\nPor qué funciona #El star schema está optimizado para consultas analíticas:\nLos joins son simples: la fact se conecta directamente a cada dimensión con un solo join Las agregaciones son rápidas: los optimizadores de las bases de datos reconocen el patrón y lo optimizan Es intuitivo para los usuarios de negocio: la estructura refleja cómo piensan sobre los datos (ventas por producto, por región, por período) Star schema vs Snowflake #El snowflake schema normaliza las dimensiones, dividiéndolas en sub-tablas. Ahorra espacio pero complica las consultas con joins adicionales. En la práctica, el star schema es preferido en la mayoría de los casos porque la simplicidad de las consultas compensa ampliamente el coste del espacio extra en las dimensiones.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/star-schema/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003estar schema\u003c/strong\u003e (esquema en estrella) es el modelo de datos más utilizado en el data warehouse. Toma su nombre de su forma: una tabla central de hechos (fact table) conectada a múltiples tablas dimensionales que la rodean, como los rayos de una estrella.\u003c/p\u003e\n\u003ch2 id=\"estructura\" class=\"relative group\"\u003eEstructura \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#estructura\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eFact table\u003c/strong\u003e en el centro: contiene las medidas numéricas y las claves foráneas hacia las dimensiones\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDimension tables\u003c/strong\u003e alrededor: contienen los atributos descriptivos (quién, qué, dónde, cuándo) con estructura desnormalizada\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eLas dimensiones en un star schema están típicamente desnormalizadas — todos los atributos en una sola tabla plana, sin jerarquías normalizadas. Esto simplifica las consultas y mejora el rendimiento de las agregaciones.\u003c/p\u003e","title":"Star schema"},{"content":"La Swappiness (vm.swappiness) es un parámetro del kernel Linux que controla cuán agresivamente el sistema mueve páginas de memoria de la RAM al swap en disco. El valor va de 0 (swap solo en caso extremo) a 100 (swap agresivo). El valor por defecto es 60.\nCómo funciona #Con el valor por defecto 60, Linux comienza a hacer swap cuando la presión sobre la memoria es aún relativamente baja. Para un servidor de base de datos dedicado, esto es inaceptable: la SGA debe permanecer en RAM, siempre. El valor recomendado para Oracle es 1 — no 0, que deshabilitaría completamente el swap y podría provocar el OOM killer.\nPara qué sirve #El valor 1 le dice al kernel: \u0026ldquo;Haz swap solo si realmente no hay alternativa.\u0026rdquo; Esto garantiza que la SGA y las estructuras críticas de Oracle permanezcan en memoria física, evitando lecturas de swap (órdenes de magnitud más lentas que la RAM) durante la ejecución de queries.\nPor qué es crítico #Con swappiness en 60, un servidor con 128 GB de RAM y una SGA de 64 GB puede empezar a hacer swap de partes de la SGA incluso con 20-30 GB de RAM libre. El resultado son rendimientos degradados de forma impredecible, con picos de latencia que parecen problemas aplicativos pero son en realidad el sistema operativo moviendo memoria a disco.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/swappiness/","section":"Glosario","summary":"\u003cp\u003eLa \u003cstrong\u003eSwappiness\u003c/strong\u003e (\u003ccode\u003evm.swappiness\u003c/code\u003e) es un parámetro del kernel Linux que controla cuán agresivamente el sistema mueve páginas de memoria de la RAM al swap en disco. El valor va de 0 (swap solo en caso extremo) a 100 (swap agresivo). El valor por defecto es 60.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCon el valor por defecto 60, Linux comienza a hacer swap cuando la presión sobre la memoria es aún relativamente baja. Para un servidor de base de datos dedicado, esto es inaceptable: la SGA debe permanecer en RAM, siempre. El valor recomendado para Oracle es 1 — no 0, que deshabilitaría completamente el swap y podría provocar el OOM killer.\u003c/p\u003e","title":"Swappiness"},{"content":"El switchover es una operacion planificada de Oracle Data Guard que invierte los roles entre la base de datos primary y la standby. El primary se convierte en standby, el standby se convierte en primary. Ningun dato se pierde, ninguna transaccion falla — es un cambio limpio y controlado.\nSwitchover vs Failover #La distincion es fundamental:\nSwitchover Failover Cuando Planificado (mantenimiento, migracion) Emergencia (fallo del primary) Perdida de datos Cero Posible (depende del modo) Reversibilidad Si, con otro switchover No, el standby se convierte en primary permanentemente Tiempo Minutos (tipicamente 1-3) Segundos a minutos Como se ejecuta #Con Data Guard Broker, el switchover es un unico comando:\nDGMGRL\u0026gt; SWITCHOVER TO standby_db; El broker gestiona automaticamente la secuencia: detencion del redo transport, aplicacion de los ultimos redo en el standby, inversion de roles, reinicio del redo transport en la direccion opuesta.\nUso en migraciones #El switchover es la estrategia preferida para las migraciones Oracle cross-site. Se configura el Data Guard entre el entorno origen y destino, se deja sincronizar, y en el momento del cutover se ejecuta el switchover. Si algo sale mal en la nueva infraestructura, un segundo switchover devuelve todo al punto de partida — una red de seguridad que Data Pump no puede ofrecer.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/switchover/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eswitchover\u003c/strong\u003e es una operacion planificada de Oracle Data Guard que invierte los roles entre la base de datos primary y la standby. El primary se convierte en standby, el standby se convierte en primary. Ningun dato se pierde, ninguna transaccion falla — es un cambio limpio y controlado.\u003c/p\u003e\n\u003ch2 id=\"switchover-vs-failover\" class=\"relative group\"\u003eSwitchover vs Failover \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#switchover-vs-failover\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa distincion es fundamental:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003eSwitchover\u003c/th\u003e\n          \u003cth\u003eFailover\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eCuando\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePlanificado (mantenimiento, migracion)\u003c/td\u003e\n          \u003ctd\u003eEmergencia (fallo del primary)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePerdida de datos\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eCero\u003c/td\u003e\n          \u003ctd\u003ePosible (depende del modo)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eReversibilidad\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eSi, con otro switchover\u003c/td\u003e\n          \u003ctd\u003eNo, el standby se convierte en primary permanentemente\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eTiempo\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eMinutos (tipicamente 1-3)\u003c/td\u003e\n          \u003ctd\u003eSegundos a minutos\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"como-se-ejecuta\" class=\"relative group\"\u003eComo se ejecuta \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-se-ejecuta\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCon Data Guard Broker, el switchover es un unico comando:\u003c/p\u003e","title":"Switchover"},{"content":"Un System Privilege en Oracle es una autorización que permite ejecutar operaciones globales en la base de datos, independientemente de un objeto específico. Ejemplos típicos incluyen CREATE TABLE, CREATE SESSION, ALTER SYSTEM, CREATE USER y DROP ANY TABLE.\nCómo funciona #Los system privileges se asignan con GRANT y se revocan con REVOKE. Pueden asignarse directamente a un usuario o a un rol. El rol predefinido DBA incluye más de 200 system privileges, razón por la cual asignarlo a usuarios aplicativos es una práctica peligrosa.\nPara qué sirve #Los system privileges definen lo que un usuario puede hacer a nivel de base de datos: crear objetos, gestionar usuarios, modificar parámetros de sistema. Son el nivel más alto de autorización en Oracle y deben gestionarse con extrema cautela, siguiendo el principio del mínimo privilegio.\nQué puede salir mal #Un system privilege como DROP ANY TABLE permite eliminar cualquier tabla de cualquier schema. Si se asigna por error a un usuario aplicativo, un solo comando puede destruir datos de producción. La distinción entre system privileges y object privileges es fundamental para construir un modelo de seguridad robusto.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/system-privilege/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eSystem Privilege\u003c/strong\u003e en Oracle es una autorización que permite ejecutar operaciones globales en la base de datos, independientemente de un objeto específico. Ejemplos típicos incluyen \u003ccode\u003eCREATE TABLE\u003c/code\u003e, \u003ccode\u003eCREATE SESSION\u003c/code\u003e, \u003ccode\u003eALTER SYSTEM\u003c/code\u003e, \u003ccode\u003eCREATE USER\u003c/code\u003e y \u003ccode\u003eDROP ANY TABLE\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLos system privileges se asignan con \u003ccode\u003eGRANT\u003c/code\u003e y se revocan con \u003ccode\u003eREVOKE\u003c/code\u003e. Pueden asignarse directamente a un usuario o a un rol. El rol predefinido \u003ccode\u003eDBA\u003c/code\u003e incluye más de 200 system privileges, razón por la cual asignarlo a usuarios aplicativos es una práctica peligrosa.\u003c/p\u003e","title":"System Privilege"},{"content":"systemd es el sistema de inicio y gestor de servicios predeterminado en las distribuciones Linux modernas (CentOS/RHEL 7+, Ubuntu 16.04+, Debian 8+). En el ámbito de bases de datos, es el mecanismo que arranca, detiene y monitoriza las instancias MySQL o MariaDB.\nCómo funciona #Cada servicio está definido por un archivo unit (ej. mysqld.service) que especifica el comando de arranque, el archivo de configuración, las dependencias y el comportamiento en caso de crash. En un setup multi-instancia, se crean unit files separados para cada instancia (ej. mysqld-app2.service, mysqld-reporting.service), cada uno con su propio --defaults-file apuntando a un my.cnf diferente.\nPara qué sirve #systemd permite gestionar las instancias MySQL como servicios independientes: arrancarlas, detenerlas, reiniciarlas y monitorizarlas por separado. El comando systemctl cat \u0026lt;servicio\u0026gt; es fundamental para rastrear desde el nombre del servicio hasta el archivo de configuración de la instancia, y de ahí al puerto, socket y datadir.\nCuándo se usa #systemd está activo automáticamente en cualquier servidor Linux moderno. En el trabajo de DBA, se interactúa con él mediante systemctl start/stop/status/restart \u0026lt;servicio\u0026gt;. En entornos multi-instancia, systemctl list-units --type=service | grep mysql es el primer comando para identificar cuántas instancias están activas en un servidor.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/systemd/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003esystemd\u003c/strong\u003e es el sistema de inicio y gestor de servicios predeterminado en las distribuciones Linux modernas (CentOS/RHEL 7+, Ubuntu 16.04+, Debian 8+). En el ámbito de bases de datos, es el mecanismo que arranca, detiene y monitoriza las instancias MySQL o MariaDB.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada servicio está definido por un archivo unit (ej. \u003ccode\u003emysqld.service\u003c/code\u003e) que especifica el comando de arranque, el archivo de configuración, las dependencias y el comportamiento en caso de crash. En un setup multi-instancia, se crean unit files separados para cada instancia (ej. \u003ccode\u003emysqld-app2.service\u003c/code\u003e, \u003ccode\u003emysqld-reporting.service\u003c/code\u003e), cada uno con su propio \u003ccode\u003e--defaults-file\u003c/code\u003e apuntando a un \u003ccode\u003emy.cnf\u003c/code\u003e diferente.\u003c/p\u003e","title":"systemd"},{"content":"Un Tablespace es la unidad lógica de organización del almacenamiento en Oracle Database. Cada tablespace está compuesto por uno o más datafiles físicos en disco, y cada objeto de la base de datos (tabla, índice, partición) reside en un tablespace.\nCómo funciona #Oracle separa la gestión lógica (tablespace) de la física (datafile). Un DBA puede crear tablespaces dedicados para propósitos diferentes: uno para datos activos, uno para índices, uno para archivo. Esto permite distribuir la carga de I/O en discos diferentes y aplicar políticas de gestión diferenciadas (ej. read-only para datos históricos).\nPara qué sirve #En el contexto del partitioning, los tablespaces permiten estrategias avanzadas de gestión del ciclo de vida: mover particiones antiguas a tablespaces de archivo económicos, ponerlas en read-only para reducir la carga de backup, y recuperar espacio activo sin eliminar datos. Un ALTER TABLE MOVE PARTITION ... TABLESPACE ts_archive es una operación DDL que tarda menos de un segundo.\nCuándo se usa #Cada instalación Oracle usa tablespaces. El diseño de tablespaces se vuelve crítico cuando se gestionan tablas de cientos de GB con partitioning, porque una buena distribución en tablespaces separados habilita backups incrementales eficientes y gestión del ciclo de vida de los datos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/tablespace/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eTablespace\u003c/strong\u003e es la unidad lógica de organización del almacenamiento en Oracle Database. Cada tablespace está compuesto por uno o más datafiles físicos en disco, y cada objeto de la base de datos (tabla, índice, partición) reside en un tablespace.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOracle separa la gestión lógica (tablespace) de la física (datafile). Un DBA puede crear tablespaces dedicados para propósitos diferentes: uno para datos activos, uno para índices, uno para archivo. Esto permite distribuir la carga de I/O en discos diferentes y aplicar políticas de gestión diferenciadas (ej. read-only para datos históricos).\u003c/p\u003e","title":"Tablespace"},{"content":"Las THP (Transparent Huge Pages) son una función del kernel Linux que promueve automáticamente las páginas de memoria de 4 KB a 2 MB en segundo plano, sin configuración explícita. A diferencia de las Huge Pages estáticas, son gestionadas por el proceso del kernel khugepaged.\nCómo funciona #Cuando están activas (por defecto always), el kernel intenta compactar las páginas normales en páginas grandes en segundo plano. El proceso khugepaged trabaja continuamente para encontrar y unir grupos de páginas contiguas, causando micro-congelamientos impredecibles durante las operaciones de compactación.\nPor qué es crítico #Para Oracle son un desastre. Oracle lo dice explícitamente en su documentación: deshabilitar THP. Los \u0026ldquo;bloqueos de unos segundos\u0026rdquo; que los usuarios reportan son frecuentemente causados por khugepaged. Se deshabilitan con echo never \u0026gt; /sys/kernel/mm/transparent_hugepage/enabled y vía GRUB para persistencia tras reboot.\nQué puede salir mal #La confusión entre Huge Pages (buenas para Oracle, configuradas estáticamente) y THP (dañinas para Oracle, activas por defecto) es uno de los errores más comunes. Un DBA que ve \u0026ldquo;Huge Pages\u0026rdquo; en la documentación y no deshabilita THP está empeorando las cosas en lugar de mejorarlas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/thp/","section":"Glosario","summary":"\u003cp\u003eLas \u003cstrong\u003eTHP\u003c/strong\u003e (Transparent Huge Pages) son una función del kernel Linux que promueve automáticamente las páginas de memoria de 4 KB a 2 MB en segundo plano, sin configuración explícita. A diferencia de las Huge Pages estáticas, son gestionadas por el proceso del kernel \u003ccode\u003ekhugepaged\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando están activas (por defecto \u003ccode\u003ealways\u003c/code\u003e), el kernel intenta compactar las páginas normales en páginas grandes en segundo plano. El proceso \u003ccode\u003ekhugepaged\u003c/code\u003e trabaja continuamente para encontrar y unir grupos de páginas contiguas, causando micro-congelamientos impredecibles durante las operaciones de compactación.\u003c/p\u003e","title":"THP"},{"content":"El Timeboxing es una técnica de gestión del tiempo que consiste en asignar un intervalo temporal fijo y no negociable a una actividad. Cuando el tiempo se acaba, la actividad se cierra — independientemente de si se ha completado o no.\nCómo funciona #Se define la duración máxima (15 minutos para un standup, 1 hora para una reunión de diseño, 2 semanas para un sprint) y se respeta la restricción. El timebox fuerza a las personas a concentrarse en lo esencial, evitando discusiones infinitas y perfeccionismo paralizante.\nPara qué sirve #En el project management, el timeboxing está en la base del standup meeting (15 minutos máximo), del sprint Scrum (duración fija) y de cualquier reunión bien gestionada. Sin restricción temporal, las reuniones se expanden hasta ocupar todo el tiempo disponible — la ley de Parkinson aplicada a las salas de reuniones.\nPor qué es crítico #Un standup de 15 minutos cuesta al equipo 440 horas al año. Uno de 45 minutos cuesta 1.320. La diferencia — 880 horas — equivale a casi 5 meses-persona. El timeboxing no es rigidez: es respeto por el tiempo de las personas.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/timeboxing/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eTimeboxing\u003c/strong\u003e es una técnica de gestión del tiempo que consiste en asignar un intervalo temporal fijo y no negociable a una actividad. Cuando el tiempo se acaba, la actividad se cierra — independientemente de si se ha completado o no.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSe define la duración máxima (15 minutos para un standup, 1 hora para una reunión de diseño, 2 semanas para un sprint) y se respeta la restricción. El timebox fuerza a las personas a concentrarse en lo esencial, evitando discusiones infinitas y perfeccionismo paralizante.\u003c/p\u003e","title":"Timeboxing"},{"content":"El transport lag es el retardo entre el momento en que la base de datos primary genera un redo log y el momento en que ese redo log es recibido por la base de datos standby en una configuracion Oracle Data Guard. Es uno de los indicadores mas importantes para evaluar la salud de la replicacion.\nComo se mide #El transport lag se monitorea con una consulta sobre la vista V$DATAGUARD_STATS o mediante Data Guard Broker:\nDGMGRL\u0026gt; SHOW DATABASE 'standby_db' 'TransportLagTarget'; El valor se expresa en formato tiempo (ej. +00 00:00:03 = 3 segundos de retardo). Un transport lag de pocos segundos es normal en modo Maximum Performance; un lag que crece constantemente indica un problema de ancho de banda o de redo generate rate.\nDiferencia con Apply Lag # Metrica Que mide Transport Lag Retardo en la transmision de los redo del primary al standby Apply Lag Retardo en la aplicacion de los redo en el standby tras la recepcion El transport lag depende de la red (ancho de banda, latencia); el apply lag depende de los recursos del standby (CPU, I/O). En las migraciones cross-site, el transport lag es el cuello de botella mas comun.\nImpacto en las migraciones #Durante una migracion con Data Guard cross-site, el transport lag debe monitorearse cuidadosamente durante las fases de carga maxima (batch nocturnos, picos de actividad). Un redo generate rate que supera la capacidad de la VPN produce un transport lag creciente. Antes del cutover, el transport lag debe estar cerca de cero para garantizar que el switchover ocurra sin perdida de datos.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/transport-lag/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003etransport lag\u003c/strong\u003e es el retardo entre el momento en que la base de datos primary genera un redo log y el momento en que ese redo log es recibido por la base de datos standby en una configuracion Oracle Data Guard. Es uno de los indicadores mas importantes para evaluar la salud de la replicacion.\u003c/p\u003e\n\u003ch2 id=\"como-se-mide\" class=\"relative group\"\u003eComo se mide \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-se-mide\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl transport lag se monitorea con una consulta sobre la vista \u003ccode\u003eV$DATAGUARD_STATS\u003c/code\u003e o mediante Data Guard Broker:\u003c/p\u003e","title":"Transport Lag"},{"content":"Unified Audit (Oracle Unified Auditing) es el sistema de auditoría centralizado introducido en Oracle Database 12c que sustituye los mecanismos de auditoría tradicionales con una única infraestructura unificada. Todos los eventos de auditoría convergen en la vista UNIFIED_AUDIT_TRAIL.\nCómo funciona #Unified Audit se basa en audit policies: reglas declarativas que especifican qué acciones monitorizar (DDL, DML, logins, operaciones administrativas). Las policies se crean con CREATE AUDIT POLICY, se activan con ALTER AUDIT POLICY ... ENABLE y pueden aplicarse a usuarios específicos o globalmente. Los registros de auditoría se escriben en una cola interna y luego se persisten en la tabla de sistema.\nPara qué sirve #Responde a la pregunta fundamental de la seguridad: \u0026ldquo;¿quién hizo qué, cuándo y desde dónde?\u0026rdquo; Permite rastrear operaciones críticas como DROP TABLE, GRANT, REVOKE, accesos a datos sensibles e intentos de login fallidos. Es esencial para la compliance (GDPR, SOX, PCI-DSS) y para las investigaciones post-incidente.\nPor qué es crítico #El antiguo audit tradicional de Oracle fragmentaba los logs entre archivos del sistema, la tabla SYS.AUD$ y FGA_LOG$, haciendo el análisis complejo. Unified Audit centraliza todo en un único punto, con mejor rendimiento y gestión simplificada. En un entorno sin audit configurado, un incidente de seguridad se vuelve imposible de reconstruir.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/unified-audit/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eUnified Audit\u003c/strong\u003e (Oracle Unified Auditing) es el sistema de auditoría centralizado introducido en Oracle Database 12c que sustituye los mecanismos de auditoría tradicionales con una única infraestructura unificada. Todos los eventos de auditoría convergen en la vista \u003ccode\u003eUNIFIED_AUDIT_TRAIL\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUnified Audit se basa en \u003cstrong\u003eaudit policies\u003c/strong\u003e: reglas declarativas que especifican qué acciones monitorizar (DDL, DML, logins, operaciones administrativas). Las policies se crean con \u003ccode\u003eCREATE AUDIT POLICY\u003c/code\u003e, se activan con \u003ccode\u003eALTER AUDIT POLICY ... ENABLE\u003c/code\u003e y pueden aplicarse a usuarios específicos o globalmente. Los registros de auditoría se escriben en una cola interna y luego se persisten en la tabla de sistema.\u003c/p\u003e","title":"Unified Audit"},{"content":"Un Unix Socket (o socket de dominio Unix) es un endpoint de comunicación que permite a dos procesos en el mismo sistema operativo intercambiar datos sin pasar por la pila de red TCP/IP. En MySQL, es el método de conexión predeterminado cuando te conectas a localhost.\nCómo funciona #Cuando un cliente MySQL se conecta especificando -h localhost, el cliente no usa TCP. Usa el archivo socket Unix (típicamente /var/run/mysqld/mysqld.sock) para comunicarse directamente con el proceso del servidor MySQL. Esta comunicación ocurre enteramente en el kernel, sin overhead de red, y es más rápida que una conexión TCP incluso en el mismo host.\nPara qué sirve #En entornos multi-instancia, cada instancia MySQL tiene su propio archivo socket (ej. mysqld.sock, mysqld-app2.sock). Especificar el socket correcto con --socket=/path/to/socket es la única forma fiable de conectarse a la instancia deseada. Sin especificar el socket, el cliente usa el predeterminado — que casi siempre apunta a la instancia primaria.\nCuándo se usa #Los sockets Unix se usan para todas las conexiones locales a MySQL. En entornos con instancias múltiples, es esencial especificar explícitamente el socket para cada conexión. Para conexiones remotas (desde otro host), se usa TCP con -h \u0026lt;ip\u0026gt; -P \u0026lt;puerto\u0026gt;.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/unix-socket/","section":"Glosario","summary":"\u003cp\u003eUn \u003cstrong\u003eUnix Socket\u003c/strong\u003e (o socket de dominio Unix) es un endpoint de comunicación que permite a dos procesos en el mismo sistema operativo intercambiar datos sin pasar por la pila de red TCP/IP. En MySQL, es el método de conexión predeterminado cuando te conectas a \u003ccode\u003elocalhost\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando un cliente MySQL se conecta especificando \u003ccode\u003e-h localhost\u003c/code\u003e, el cliente no usa TCP. Usa el archivo socket Unix (típicamente \u003ccode\u003e/var/run/mysqld/mysqld.sock\u003c/code\u003e) para comunicarse directamente con el proceso del servidor MySQL. Esta comunicación ocurre enteramente en el kernel, sin overhead de red, y es más rápida que una conexión TCP incluso en el mismo host.\u003c/p\u003e","title":"Unix Socket"},{"content":"VACUUM es el comando PostgreSQL que recupera el espacio ocupado por los dead tuples (filas muertas) y lo pone disponible para nuevas inserciones. No devuelve espacio al sistema operativo, no reorganiza la tabla y no compacta nada — marca las páginas como reescribibles.\nCómo funciona #VACUUM tabla escanea la tabla, identifica los dead tuples que ya no son visibles para ninguna transacción y marca su espacio como reutilizable. Es una operación ligera que no bloquea las escrituras y puede ejecutarse en paralelo con las queries normales. VACUUM FULL en cambio reescribe físicamente toda la tabla con un lock exclusivo — para usar muy raramente y solo en emergencias.\nPara qué sirve #Sin VACUUM, las tablas con alto tráfico de UPDATE y DELETE acumulan dead tuples que ocupan espacio en disco y ralentizan los escaneos secuenciales. VACUUM es el mecanismo de limpieza esencial que equilibra el coste del modelo MVCC de PostgreSQL.\nPor qué es crítico #El autovacuum ejecuta VACUUM automáticamente, pero con los valores por defecto de PostgreSQL puede activarse con poca frecuencia en tablas de alto tráfico. En una tabla con 10 millones de filas, el default espera 2 millones de dead tuples antes de actuar — suficiente para degradar visiblemente el rendimiento.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/vacuum/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eVACUUM\u003c/strong\u003e es el comando PostgreSQL que recupera el espacio ocupado por los dead tuples (filas muertas) y lo pone disponible para nuevas inserciones. No devuelve espacio al sistema operativo, no reorganiza la tabla y no compacta nada — marca las páginas como reescribibles.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003e\u003ccode\u003eVACUUM tabla\u003c/code\u003e escanea la tabla, identifica los dead tuples que ya no son visibles para ninguna transacción y marca su espacio como reutilizable. Es una operación ligera que no bloquea las escrituras y puede ejecutarse en paralelo con las queries normales. \u003ccode\u003eVACUUM FULL\u003c/code\u003e en cambio reescribe físicamente toda la tabla con un lock exclusivo — para usar muy raramente y solo en emergencias.\u003c/p\u003e","title":"VACUUM"},{"content":"El Vendor Lock-in es la situación en la que una empresa se vuelve dependiente de un proveedor externo hasta el punto de que cambiarlo resulta extremadamente costoso o técnicamente complejo. En el contexto IT, se produce cuando el código, la arquitectura o el conocimiento del sistema están en manos del proveedor y no del cliente.\nCómo funciona #El lock-in se instaura gradualmente: el proveedor escribe el código con sus propias convenciones, usa tecnologías propietarias o no documentadas, y el equipo interno no participa en el desarrollo. Cuando el proveedor se va — por decisión propia o por despido — se lleva el know-how consigo. El cliente se queda con un software que no entiende, no sabe mantener y no puede evolucionar sin volver a contratar al mismo proveedor o empezar de cero.\nPara qué sirve #Comprender el vendor lock-in es esencial para tomar decisiones estratégicas sobre outsourcing y desarrollo de software. Cada proyecto debería prever medidas de mitigación: documentación interna, code review, participación del equipo interno, propiedad del código fuente.\nCuándo se usa #El término describe un riesgo a evitar. Las contramedidas principales son: mantener el know-how crítico internamente, preferir tecnologías abiertas y estándar, garantizar la propiedad intelectual del código, y evaluar siempre la opción \u0026ldquo;buy vs build\u0026rdquo; antes de iniciar proyectos custom de gran envergadura.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/vendor-lock-in/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eVendor Lock-in\u003c/strong\u003e es la situación en la que una empresa se vuelve dependiente de un proveedor externo hasta el punto de que cambiarlo resulta extremadamente costoso o técnicamente complejo. En el contexto IT, se produce cuando el código, la arquitectura o el conocimiento del sistema están en manos del proveedor y no del cliente.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eEl lock-in se instaura gradualmente: el proveedor escribe el código con sus propias convenciones, usa tecnologías propietarias o no documentadas, y el equipo interno no participa en el desarrollo. Cuando el proveedor se va — por decisión propia o por despido — se lleva el know-how consigo. El cliente se queda con un software que no entiende, no sabe mantener y no puede evolucionar sin volver a contratar al mismo proveedor o empezar de cero.\u003c/p\u003e","title":"Vendor Lock-in"},{"content":"El Version Control (control de versiones) es un sistema que registra cada cambio en los archivos de un proyecto, manteniendo un historial completo de quién cambió qué, cuándo y por qué. Git es el sistema de control de versiones más usado en el mundo.\nCómo funciona #Cada cambio se registra como \u0026ldquo;commit\u0026rdquo; con un mensaje descriptivo, un autor y un timestamp. El sistema mantiene toda la historia del proyecto: es posible volver a cualquier versión anterior, comparar versiones diferentes y entender la evolución del código en el tiempo. Con Git, cada desarrollador tiene una copia completa de la historia en su propio ordenador.\nPara qué sirve #Sin control de versiones, el código vive en carpetas compartidas donde las sobreescrituras accidentales son la norma y nadie sabe cuál es la versión \u0026ldquo;buena\u0026rdquo;. Con control de versiones, cada cambio es rastreado y reversible, los conflictos entre desarrolladores se gestionan de forma estructurada, y la historia del proyecto es un recurso, no un misterio.\nCuándo se usa #Siempre, en cualquier proyecto software con más de un archivo o más de un desarrollador. La ausencia de control de versiones es la primera señal de un proyecto fuera de control. GitHub, GitLab y Bitbucket son plataformas que añaden colaboración (Pull Requests, Issue tracker) sobre Git.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/version-control/","section":"Glosario","summary":"\u003cp\u003eEl \u003cstrong\u003eVersion Control\u003c/strong\u003e (control de versiones) es un sistema que registra cada cambio en los archivos de un proyecto, manteniendo un historial completo de quién cambió qué, cuándo y por qué. Git es el sistema de control de versiones más usado en el mundo.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCada cambio se registra como \u0026ldquo;commit\u0026rdquo; con un mensaje descriptivo, un autor y un timestamp. El sistema mantiene toda la historia del proyecto: es posible volver a cualquier versión anterior, comparar versiones diferentes y entender la evolución del código en el tiempo. Con Git, cada desarrollador tiene una copia completa de la historia en su propio ordenador.\u003c/p\u003e","title":"Version Control"},{"content":"Wait Event es un indicador diagnostico de Oracle Database que identifica por que una sesion esta esperando en lugar de trabajar activamente. Cada vez que un proceso no puede continuar — porque espera un bloque del disco, un lock, una respuesta de red o un turno de CPU — Oracle registra un wait event especifico.\nLos mas comunes # Wait Event Significado db file sequential read Lectura de un solo bloque — tipica de acceso por indice db file scattered read Lectura multi-bloque — tipica de full table scan log file sync Espera del commit en redo log enq: TX - row lock contention Conflicto de lock de fila direct path read Lectura directa (sin pasar por buffer cache) Para que sirven #Los wait events son la base de la metodologia diagnostica de Oracle. Analizando que eventos dominan el DB time (mediante AWR o ASH) se identifica inmediatamente la naturaleza del problema: I/O, contention, CPU o red.\nDonde se encuentran # En tiempo real: V$SESSION_WAIT, V$ACTIVE_SESSION_HISTORY Historicos: informes AWR (seccion Top Timed Foreground Events), DBA_HIST_ACTIVE_SESS_HISTORY La regla del DBA: no adivines que ralentiza la base de datos — mira los wait events.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/wait-event/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eWait Event\u003c/strong\u003e es un indicador diagnostico de Oracle Database que identifica por que una sesion esta esperando en lugar de trabajar activamente. Cada vez que un proceso no puede continuar — porque espera un bloque del disco, un lock, una respuesta de red o un turno de CPU — Oracle registra un wait event especifico.\u003c/p\u003e\n\u003ch2 id=\"los-mas-comunes\" class=\"relative group\"\u003eLos mas comunes \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#los-mas-comunes\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eWait Event\u003c/th\u003e\n          \u003cth\u003eSignificado\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edb file sequential read\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eLectura de un solo bloque — tipica de acceso por indice\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edb file scattered read\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eLectura multi-bloque — tipica de full table scan\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003elog file sync\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eEspera del commit en redo log\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eenq: TX - row lock contention\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eConflicto de lock de fila\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edirect path read\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eLectura directa (sin pasar por buffer cache)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"para-que-sirven\" class=\"relative group\"\u003ePara que sirven \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#para-que-sirven\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLos wait events son la base de la metodologia diagnostica de Oracle. Analizando que eventos dominan el DB time (mediante AWR o ASH) se identifica inmediatamente la naturaleza del problema: I/O, contention, CPU o red.\u003c/p\u003e","title":"Wait Event"},{"content":"WSREP (Write Set Replication) es la API y el protocolo que Galera Cluster utiliza para la replicación síncrona multi-master. Cada transacción se captura como \u0026ldquo;write set\u0026rdquo; (conjunto de cambios a nivel de fila) y se replica en todos los nodos del cluster antes del commit.\nCómo funciona #Cuando un nodo ejecuta una transacción, WSREP la intercepta en el momento del commit, la empaqueta como write set y la envía a todos los nodos del cluster a través del protocolo de comunicación de grupo. Cada nodo ejecuta un proceso de certification: verifica que la transacción no entre en conflicto con otras transacciones concurrentes. Si la certification tiene éxito, todos los nodos aplican la transacción. Si falla, la transacción se revierte en el nodo que la originó.\nPara qué sirve #WSREP garantiza que todos los nodos del cluster tengan los mismos datos en todo momento (replicación síncrona). A diferencia de la replicación asíncrona tradicional de MySQL, no hay retardo entre master y slave: cuando una transacción se confirma en un nodo, ya está presente en todos los demás.\nCuándo se usa #WSREP se activa con el parámetro wsrep_on=ON en la configuración de MariaDB/Percona XtraDB Cluster. Las variables de estado que comienzan con wsrep_ (como wsrep_cluster_size, wsrep_cluster_status, wsrep_flow_control_paused) son los indicadores principales para monitorizar la salud del cluster.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/wsrep/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eWSREP\u003c/strong\u003e (Write Set Replication) es la API y el protocolo que Galera Cluster utiliza para la replicación síncrona multi-master. Cada transacción se captura como \u0026ldquo;write set\u0026rdquo; (conjunto de cambios a nivel de fila) y se replica en todos los nodos del cluster antes del commit.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando un nodo ejecuta una transacción, WSREP la intercepta en el momento del commit, la empaqueta como write set y la envía a todos los nodos del cluster a través del protocolo de comunicación de grupo. Cada nodo ejecuta un proceso de \u003cstrong\u003ecertification\u003c/strong\u003e: verifica que la transacción no entre en conflicto con otras transacciones concurrentes. Si la certification tiene éxito, todos los nodos aplican la transacción. Si falla, la transacción se revierte en el nodo que la originó.\u003c/p\u003e","title":"WSREP"},{"content":"Yes-And (Sí-Y) es una técnica de comunicación originaria del teatro de improvisación, aplicada al project management para transformar las discusiones conflictivas en conversaciones constructivas. El principio es simple: en lugar de negar la propuesta del interlocutor con \u0026ldquo;No, pero\u0026hellip;\u0026rdquo;, se acoge con \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo; añadiendo la propia contribución.\nCómo funciona #Cuando alguien propone una idea, la respuesta \u0026ldquo;No\u0026rdquo; activa una reacción defensiva y bloquea la conversación. La respuesta \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo; reconoce la validez de la propuesta y la extiende, manteniendo el diálogo abierto. No significa estar de acuerdo con todo — significa construir sobre la propuesta del otro antes de redirigirla.\nCuándo se usa #En reuniones de proyecto donde dos posiciones chocan, en code reviews donde el feedback corre el riesgo de sonar como crítica, en negociaciones con stakeholders donde un \u0026ldquo;no\u0026rdquo; seco quema las relaciones. Es particularmente efectiva cuando hay que hacer converger opiniones diversas hacia una decisión compartida.\nCuándo no funciona #No se aplica a cuestiones de seguridad, violaciones de proceso o deadlines no negociables. Si alguien propone eliminar la autenticación de la base de datos de producción, la respuesta es \u0026ldquo;No\u0026rdquo;, punto. El Yes-And funciona con personas de buena fe; no funciona con quien solo quiere tener razón.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/yes-and/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eYes-And\u003c/strong\u003e (Sí-Y) es una técnica de comunicación originaria del teatro de improvisación, aplicada al project management para transformar las discusiones conflictivas en conversaciones constructivas. El principio es simple: en lugar de negar la propuesta del interlocutor con \u0026ldquo;No, pero\u0026hellip;\u0026rdquo;, se acoge con \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo; añadiendo la propia contribución.\u003c/p\u003e\n\u003ch2 id=\"cómo-funciona\" class=\"relative group\"\u003eCómo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#c%c3%b3mo-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCuando alguien propone una idea, la respuesta \u0026ldquo;No\u0026rdquo; activa una reacción defensiva y bloquea la conversación. La respuesta \u0026ldquo;Sí, y\u0026hellip;\u0026rdquo; reconoce la validez de la propuesta y la extiende, manteniendo el diálogo abierto. No significa estar de acuerdo con todo — significa construir sobre la propuesta del otro antes de redirigirla.\u003c/p\u003e","title":"Yes-And"},{"content":"ZDM (Zero Downtime Migration) es la herramienta que Oracle proporciona para automatizar las migraciones de bases de datos Oracle hacia OCI (Oracle Cloud Infrastructure) o hacia bases de datos on-premises de version superior. El nombre es algo optimista — el downtime no es cero, pero se reduce al minimo.\nComo funciona #ZDM es esencialmente un orquestador que combina tecnologias Oracle existentes bajo un unico flujo automatizado. Soporta dos modalidades:\nMigracion fisica (basada en Data Guard): crea un standby de la base de datos origen en el destino, lo sincroniza mediante redo transport, y luego ejecuta un switchover. Downtime del orden de minutos. Migracion logica (basada en Data Pump): ejecuta export e import logico con sincronizacion incremental mediante GoldenGate o Data Pump. Mas flexible pero mas lenta. Cuando usarlo #ZDM esta indicado para migraciones estandar donde la infraestructura origen y destino estan configuradas de forma convencional. La ventaja es la automatizacion: reduce la posibilidad de error humano en los pasos repetitivos.\nCuando no usarlo #Para configuraciones complejas — RAC con DB links cross-engine, dependencias externas no estandar, procedimientos PL/SQL con llamadas HTTP — la capa de automatizacion de ZDM puede convertirse en un obstaculo. En estos casos, configurar Data Guard manualmente da mas control sobre los detalles y la secuencia de operaciones.\nRequisitos #ZDM requiere un host dedicado (el \u0026ldquo;ZDM service host\u0026rdquo;) con acceso SSH tanto a la base de datos origen como al destino. El origen debe ser Oracle 11.2.0.4 o superior, el destino puede estar en OCI o on-premises.\n","date":"1 enero 0001","permalink":"https://ivanluminaria.com/es/glossary/zdm/","section":"Glosario","summary":"\u003cp\u003e\u003cstrong\u003eZDM\u003c/strong\u003e (Zero Downtime Migration) es la herramienta que Oracle proporciona para automatizar las migraciones de bases de datos Oracle hacia OCI (Oracle Cloud Infrastructure) o hacia bases de datos on-premises de version superior. El nombre es algo optimista — el downtime no es cero, pero se reduce al minimo.\u003c/p\u003e\n\u003ch2 id=\"como-funciona\" class=\"relative group\"\u003eComo funciona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#como-funciona\" aria-label=\"Ancla\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eZDM es esencialmente un orquestador que combina tecnologias Oracle existentes bajo un unico flujo automatizado. Soporta dos modalidades:\u003c/p\u003e","title":"ZDM"}]