{"id":6501,"date":"2025-09-26T07:00:05","date_gmt":"2025-09-26T05:00:05","guid":{"rendered":"http:\/\/rootfan.com\/?p=6501"},"modified":"2025-09-30T21:58:09","modified_gmt":"2025-09-30T19:58:09","slug":"postgresql-sql-tuning","status":"publish","type":"post","link":"https:\/\/rootfan.com\/es\/postgresql-sql-tuning\/","title":{"rendered":"Ajuste SQL de PostgreSQL: C\u00f3mo encontrar y corregir consultas lentas"},"content":{"rendered":"<p>Ni siquiera el mejor hardware puede salvarte de un SQL mal escrito. <\/p>\n\n\n\n<p>PostgreSQL proporciona potentes herramientas para analizar la ejecuci\u00f3n de consultas y optimizar el rendimiento.<\/p>\n\n\n\n<p>En este art\u00edculo, exploraremos los fundamentos del ajuste de SQL para que pueda identificar los cuellos de botella y hacer que sus consultas se ejecuten m\u00e1s r\u00e1pido.<\/p>\n\n\n\n<!--more-->\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Por qu\u00e9 es importante el ajuste de SQL<\/h2>\n\n\n\n<p>Un SQL mal optimizado conduce a:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Consultas de larga duraci\u00f3n que frustran a los usuarios.<\/li>\n\n\n\n<li>Consumo innecesario de CPU y E\/S.<\/li>\n\n\n\n<li>Bloqueos y contenciones que afectan a otras sesiones.<\/li>\n\n\n\n<li>Aumento de los costes al escalar innecesariamente el hardware.<\/li>\n<\/ul>\n\n\n\n<p>\ud83d\udc49 Afinar SQL es una de las formas m\u00e1s rentables de mejorar el rendimiento.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 1: Identificar las consultas lentas<\/h2>\n\n\n\n<p>Puede realizar un seguimiento de las consultas lentas utilizando:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>log_min_duration_statement<\/strong> - Registra las consultas que superan una duraci\u00f3n determinada.<\/li>\n\n\n\n<li><strong>pg_stat_statements<\/strong> - Captura las estad\u00edsticas de ejecuci\u00f3n de todas las consultas.<\/li>\n\n\n\n<li><strong>Perfilador SQL PEM<\/strong> - Proporciona seguimiento y an\u00e1lisis gr\u00e1fico.<\/li>\n<\/ul>\n\n\n\n<p>Por ejemplo:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\n-- Log queries longer than 5 seconds\nALTER SYSTEM SET log_min_duration_statement = 5000;\nSELECT pg_reload_conf();\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 2: Revisar el plan de ejecuci\u00f3n<\/h2>\n\n\n\n<p>Utilice la <strong>EXPLICAR<\/strong> para ver c\u00f3mo PostgreSQL planea ejecutar una consulta:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nEXPLAIN SELECT * FROM customers JOIN orders USING (customerid);\n<\/pre><\/div>\n\n\n<p>O corre <strong>EXPLICAR ANALIZAR<\/strong> para ejecutar la consulta y comparar las estimaciones con el tiempo de ejecuci\u00f3n real:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nEXPLAIN ANALYZE SELECT * FROM customers JOIN orders USING (customerid);\n<\/pre><\/div>\n\n\n<p>Cosas clave que hay que comprobar:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Exploraciones secuenciales<\/strong> en tablas grandes (puede indicar que faltan \u00edndices).<\/li>\n\n\n\n<li><strong>M\u00e9todos de uni\u00f3n<\/strong> (hash join, bucle anidado, merge join).<\/li>\n\n\n\n<li><strong>Costes de clasificaci\u00f3n y agregaci\u00f3n<\/strong>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 3: Comprobar las estad\u00edsticas<\/h2>\n\n\n\n<p>PostgreSQL se basa en las estad\u00edsticas de tablas y columnas para la planificaci\u00f3n de consultas. <\/p>\n\n\n\n<p>Las estad\u00edsticas obsoletas pueden dar lugar a planes de ejecuci\u00f3n deficientes.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ejecutar <code>ANALIZAR<\/code> para actualizar las estad\u00edsticas:<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nANALYZE customers;\n<\/pre><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>Utilice <strong>autovac\u00edo<\/strong> para mantener las estad\u00edsticas actualizadas autom\u00e1ticamente.<\/li>\n\n\n\n<li>Para datos asim\u00e9tricos, ajuste las estad\u00edsticas de columna:<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nALTER TABLE orders ALTER COLUMN order_date SET STATISTICS 500;\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 4: Reestructurar las consultas<\/h2>\n\n\n\n<p>A veces, el problema es la propia consulta. <\/p>\n\n\n\n<p>Buenas pr\u00e1cticas:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Evite las conversiones de tipo impl\u00edcitas.<\/li>\n\n\n\n<li>Utilice <strong>equijoins<\/strong> en lugar de funciones en las cl\u00e1usulas WHERE.<\/li>\n\n\n\n<li>Sustituir las subconsultas correlacionadas por joins.<\/li>\n\n\n\n<li>Considere <strong>vistas materializadas<\/strong> para informes complejos.<\/li>\n\n\n\n<li>Utilice <strong>consultas paralelas<\/strong> siempre que sea posible.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 5: Estrategias de indexaci\u00f3n<\/h2>\n\n\n\n<p>Los \u00edndices son la columna vertebral del ajuste del rendimiento. <\/p>\n\n\n\n<p>Las opciones incluyen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u00c1rbol B (por defecto)<\/strong> - Para consultas de igualdad y rango.<\/li>\n\n\n\n<li><strong>Hash<\/strong> - Para b\u00fasquedas simples de igualdad.<\/li>\n\n\n\n<li><strong>GIN<\/strong> - Para matrices, JSONB y b\u00fasqueda de texto completo.<\/li>\n\n\n\n<li><strong>BRIN<\/strong> - Para grandes datos secuenciales como las series temporales.<\/li>\n\n\n\n<li><strong>\u00cdndices parciales<\/strong> - Indexar s\u00f3lo las filas relevantes.<\/li>\n\n\n\n<li><strong>\u00cdndices funcionales<\/strong> - Expresiones de \u00edndice como <code>LOWER(correo electr\u00f3nico)<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>Por ejemplo:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\n-- Partial index on active users only\nCREATE INDEX users_active_idx ON users (last_login)\nWHERE active = true;\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Paso 6: Revisi\u00f3n del plan definitivo<\/h2>\n\n\n\n<p>Tras la reestructuraci\u00f3n y la indexaci\u00f3n, vuelva a ejecutar <strong>EXPLICAR ANALIZAR<\/strong> para confirmar las mejoras. Busca:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Tiempo de ejecuci\u00f3n reducido.<\/li>\n\n\n\n<li>Costes estimados y reales m\u00e1s bajos.<\/li>\n\n\n\n<li>Uso correcto del \u00edndice.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lista de comprobaci\u00f3n r\u00e1pida<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 Activar el registro de consultas para consultas lentas.<\/li>\n\n\n\n<li>\u2705 Utilice EXPLAIN\/EXPLAIN ANALYZE para comprender los planes de ejecuci\u00f3n.<\/li>\n\n\n\n<li>\u2705 Mantenga las estad\u00edsticas actualizadas con ANALYZE\/autovacuum.<\/li>\n\n\n\n<li>\u2705 Reestructurar las consultas ineficaces.<\/li>\n\n\n\n<li>\u2705 Aplicar el tipo de \u00edndice adecuado.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Reflexiones finales<\/h2>\n\n\n\n<p>El ajuste de SQL es en parte ciencia y en parte arte. <\/p>\n\n\n\n<p>PostgreSQL le proporciona las herramientas que necesita para identificar los problemas de rendimiento y solucionarlos eficazmente.<\/p>\n\n\n\n<p>Comience con el registro y los planes de ejecuci\u00f3n y, a continuaci\u00f3n, itere con estad\u00edsticas, reescrituras de consultas y estrategias de indexaci\u00f3n.<\/p>\n\n\n\n<p>Espero que te haya sido \u00fatil.<\/p>","protected":false},"excerpt":{"rendered":"<p>Ni siquiera el mejor hardware puede salvarle de un SQL mal escrito. PostgreSQL proporciona herramientas poderosas para analizar la ejecuci\u00f3n de consultas y optimizar el rendimiento. En este art\u00edculo, exploraremos los fundamentos del ajuste SQL para que pueda identificar los cuellos de botella y hacer que sus consultas se ejecuten m\u00e1s r\u00e1pido.<\/p>","protected":false},"author":1,"featured_media":6503,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_focus_keyword":"","rank_math_title":"","rank_math_description":"Find and fix slow queries in PostgreSQL 16 with SQL tuning techniques. Learn how to analyze query execution, identify bottlenecks, and optimize SQL queries for faster performance.","rank_math_robots":"","rank_math_og_title":"","rank_math_og_description":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[126],"tags":[135,109,134,133],"class_list":["post-6501","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-postgresql","tag-fundamentals","tag-performance","tag-slow-queries","tag-sql-tuning"],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/rootfan.com\/wp-content\/uploads\/czNmcy1wcml2YXRlL3Jhd3BpeGVsX2ltYWdlcy93ZWJzaXRlX2NvbnRlbnQvbHIvZmw0NzI2MzczMzgyMS1pbWFnZS1reWJlang5eC5qcGc.webp?fit=1024%2C684&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts\/6501","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/comments?post=6501"}],"version-history":[{"count":6,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts\/6501\/revisions"}],"predecessor-version":[{"id":6564,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts\/6501\/revisions\/6564"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/media\/6503"}],"wp:attachment":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/media?parent=6501"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/categories?post=6501"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/tags?post=6501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}