<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Postgresql on Ivan Luminaria</title><link>https://ivanluminaria.com/es/categories/postgresql/</link><description>Recent content in Postgresql on Ivan Luminaria</description><generator>Hugo</generator><language>es</language><lastBuildDate>Tue, 24 Mar 2026 08:03:00 +0100</lastBuildDate><atom:link href="https://ivanluminaria.com/es/categories/postgresql/index.xml" rel="self" type="application/rss+xml"/><item><title>VACUUM y autovacuum: por qué PostgreSQL necesita que alguien limpie</title><link>https://ivanluminaria.com/es/posts/postgresql/vacuum-autovacuum-postgresql/</link><pubDate>Tue, 24 Mar 2026 08:03:00 +0100</pubDate><guid>https://ivanluminaria.com/es/posts/postgresql/vacuum-autovacuum-postgresql/</guid><description>&lt;p&gt;Hace un par de años me pidieron revisar un PostgreSQL en producción que
&amp;ldquo;se ralentiza cada semana&amp;rdquo;. 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.&lt;/p&gt;
&lt;p&gt;Base 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.&lt;/p&gt;</description></item><item><title>Roles y usuarios en PostgreSQL: por qué todo es (solo) un ROLE</title><link>https://ivanluminaria.com/es/posts/postgresql/postgresql_roles_and_users/</link><pubDate>Tue, 10 Feb 2026 08:03:00 +0100</pubDate><guid>https://ivanluminaria.com/es/posts/postgresql/postgresql_roles_and_users/</guid><description>&lt;p&gt;La primera vez que trabajé seriamente con PostgreSQL venía de
años utilizando otros motores de base de datos. Buscaba el comando &lt;code&gt;CREATE USER&lt;/code&gt;. Lo encontraba.
Luego veía &lt;code&gt;CREATE ROLE&lt;/code&gt;. Luego &lt;code&gt;ALTER USER&lt;/code&gt;. Luego &lt;code&gt;ALTER ROLE&lt;/code&gt;.&lt;br&gt;
Durante unos minutos pensé: &amp;ldquo;Vale, aquí alguien se divierte confundiendo
a la gente&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;En realidad no. PostgreSQL es mucho más coherente de lo que parece.
Solo que lo es a su manera.&lt;/p&gt;
&lt;h2 id="en-postgresql-no-existen-usuarios-existen-roles" class="relative group"&gt;En PostgreSQL no existen usuarios. Existen roles. &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a 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"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;La clave es esta: &lt;strong&gt;en PostgreSQL todo es un ROLE&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>When a LIKE '%value%' Slows Everything Down: A Real PostgreSQL Optimization Case</title><link>https://ivanluminaria.com/es/posts/postgresql/like-optimization-postgresql/</link><pubDate>Tue, 06 Jan 2026 08:03:00 +0100</pubDate><guid>https://ivanluminaria.com/es/posts/postgresql/like-optimization-postgresql/</guid><description>&lt;p&gt;Hace algunas semanas, un cliente me contactó con un problema muy común:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;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.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Entorno: PostgreSQL en cloud managed.&lt;br&gt;
Tabla principal: &lt;code&gt;payment_report&lt;/code&gt; (~6 millones de filas, 3 GB).&lt;br&gt;
Columna buscada: &lt;code&gt;reference_code&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Query problemática:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reporting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment_report&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reporting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment_cart&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cart_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reference_code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%ABC123%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="-primera-observación-las-join-no-eran-el-problema" class="relative group"&gt;🧠 Primera observación: las JOIN no eran el problema &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a 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"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;Comparé:&lt;/p&gt;</description></item><item><title>EXPLAIN ANALYZE no basta: como leer realmente un plan de ejecucion PostgreSQL</title><link>https://ivanluminaria.com/es/posts/postgresql/explain-analyze-postgresql/</link><pubDate>Tue, 28 Oct 2025 08:03:00 +0100</pubDate><guid>https://ivanluminaria.com/es/posts/postgresql/explain-analyze-postgresql/</guid><description>&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Hice EXPLAIN ANALYZE, pero no entiendo que esta mal. El plan parece correcto.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Spoiler: el plan no era correcto en absoluto. El optimizer habia elegido un &lt;span 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="https://ivanluminaria.com/es/glossary/nested-loop/" data-glossary-more="Leer más →"&gt;nested loop&lt;/span&gt;
 join donde hacia falta un &lt;span 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="https://ivanluminaria.com/es/glossary/hash-join/" data-glossary-more="Leer más →"&gt;hash join&lt;/span&gt;
, 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.&lt;/p&gt;</description></item></channel></rss>