{"id":79893,"date":"2020-05-01T13:43:12","date_gmt":"2020-05-01T11:43:12","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov"},"modified":"2020-05-01T13:43:12","modified_gmt":"2020-05-01T11:43:12","slug":"postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","status":"publish","type":"post","link":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","title":{"rendered":"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Le invito a revisar la transcripci\u00f3n de la presentaci\u00f3n a principios de 2016 de Vladimir Sitnikov titulada \"PostgreSQL y JDBC: exprimiendo hasta la \u00faltima gota\"<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9d94c8a024bd2821e431c525aae0127d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/030666abda53aa388b1cb1d0c46a7524.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00a1Buenos d\u00edas! Me llamo Vladimir Sitnikov. He trabajado 10 a\u00f1os en la empresa NetCracker y me ocupo principalmente de rendimiento. Todo lo que est\u00e1 relacionado con Java y SQL es lo que me apasiona. <\/p>\n<p><\/p>\n<p>Y hoy les contar\u00e9 sobre lo que encontramos en la empresa cuando comenzamos a usar PostgreSQL como servidor de bases de datos. Y principalmente trabajamos con Java. Pero lo que compartir\u00e9 hoy no solo est\u00e1 relacionado con Java. Como ha demostrado la pr\u00e1ctica, esto tambi\u00e9n surge en otros lenguajes. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b01a214d782c7e32797a6c6466457979.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vamos a hablar de:<\/p>\n<p><\/p>\n<ul>\n<li>la recuperaci\u00f3n de datos. <\/li>\n<li>Sobre la conservaci\u00f3n de datos. <\/li>\n<li>Y tambi\u00e9n sobre el rendimiento. <\/li>\n<li>Y sobre los escollos ocultos que hay all\u00ed. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/57da0c6aa4bb62e1beb77160f5aee7e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Comencemos con una pregunta sencilla. Elegimos una fila de la tabla por la clave primaria. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/d5fcb1172aef402a87064498bf8a5218.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La base de datos se encuentra en el mismo host. Y todo esto toma 20 milisegundos.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/103b7f9736b82a3313491b2f0d2a5824.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Esos 20 milisegundos son mucho. Si tienes 100 consultas as\u00ed, pierdes tiempo en un segundo para ejecutar esas consultas, es decir, est\u00e1s perdiendo tiempo en vano.<\/p>\n<p><\/p>\n<p>No nos gusta hacer eso y miramos qu\u00e9 nos ofrece la base de datos para esto. La base de datos nos ofrece dos opciones de ejecuci\u00f3n de consultas. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b467e86a0f8c4c32cea182fe27a28e6e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La primera opci\u00f3n es una consulta simple. \u00bfQu\u00e9 tiene de bueno? Que la tomamos y la enviamos, y no hacemos nada m\u00e1s. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7e333a62ba68feb0781ff96e39486591.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/478\">https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/478<\/a><\/noindex><\/p>\n<p><\/p>\n<p>La base de datos tambi\u00e9n tiene una consulta extendida, que es m\u00e1s inteligente, pero m\u00e1s funcional. Se puede enviar una consulta por separado para an\u00e1lisis, ejecuci\u00f3n, vinculaci\u00f3n de variables, etc. <\/p>\n<p><\/p>\n<p>La superconsulta extendida es algo que no cubriremos en esta presentaci\u00f3n. Quiz\u00e1s deseamos algo de la base de datos y hay una lista de deseos que se ha formado de alguna manera, es decir, esto es lo que queremos, pero no es posible ahora ni en el pr\u00f3ximo a\u00f1o. Por eso lo anotamos y vamos a molestar a las personas clave.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/19094729074fd28c5b9f236833a9a266.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y lo que podemos hacer es simplemente la consulta simple y la consulta extendida.<\/p>\n<p><\/p>\n<p>\u00bfCu\u00e1l es la peculiaridad de cada enfoque? <\/p>\n<p><\/p>\n<p>La consulta simple es buena para la ejecuci\u00f3n \u00fanica. La ejecutas una vez y olvidas. Y el problema es que no soporta el formato binario de datos, es decir, no es adecuado para sistemas de alto rendimiento.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/062c0e45cefd91ece331a306a7651bde.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La consulta extendida permite ahorrar tiempo en el an\u00e1lisis. Esto es lo que hemos hecho y comenzamos a usar. Nos ha ayudado enormemente. No solo hay econom\u00edas en el an\u00e1lisis. Tambi\u00e9n hay ahorros en la transmisi\u00f3n de datos. Transmitir datos en formato binario es mucho m\u00e1s eficiente. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6df83a2f3736568668cf9d74de5d9758.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pasemos a la pr\u00e1ctica. As\u00ed es como se ve una aplicaci\u00f3n t\u00edpica. Puede ser Java, etc. <\/p>\n<p><\/p>\n<p>Creamos el statement. Ejecutamos el comando. Creamos el close. \u00bfD\u00f3nde est\u00e1 el error aqu\u00ed? \u00bfCu\u00e1l es el problema? No hay problemas. As\u00ed est\u00e1 escrito en todos los libros. As\u00ed se debe escribir. Si quieres el m\u00e1ximo rendimiento, escr\u00edbelo as\u00ed. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6923293946dec45b3fd508235728ab95.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pero la pr\u00e1ctica ha demostrado que esto no funciona. \u00bfPor qu\u00e9? Porque tenemos el m\u00e9todo 'close'. Y cuando hacemos esto, desde el punto de vista de la base de datos, es como si un fumador estuviera trabajando con la base de datos. Dijimos 'PARSE EXECUTE DEALLOCATE'.<\/p>\n<p><\/p>\n<p>\u00bfPor qu\u00e9 estas creaciones innecesarias y la descarga de statements? No son necesarios para nadie. Pero generalmente en PreparedStatement resulta as\u00ed, cuando los cerramos, cierran todo en la base de datos. Esto no es lo que queremos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5a357a209e414024c437d042f600f251.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Queremos, como personas sanas, trabajar con la base. Una vez preparamos nuestro statement, luego lo ejecutamos muchas veces. En realidad, muchas veces significa una vez en toda la vida de la aplicaci\u00f3n. Y utilizamos el mismo id de statement en diferentes REST. Ese es nuestro objetivo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ac4aed702a624ad9f9addc4362daf760.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00bfC\u00f3mo logramos esto? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0f101d890d1a2af8e99f8a3a8a06fd5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Muy simple: no hay que cerrar los statements. Escribimos as\u00ed: 'prepare' 'execute'. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0b3fd8fd4f5861d4a76cad5a8421ddad.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/724646bfc55b5e2b611b1584ca8ba6aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Si ejecutamos esto, est\u00e1 claro que en alg\u00fan lugar habr\u00e1 un desbordamiento. Si no es claro, se puede medir. Tomaremos y escribiremos un benchmark con este m\u00e9todo simple. Creamos el statement. Lo ejecutamos en alguna versi\u00f3n del driver y nos damos cuenta de que se cae bastante r\u00e1pido con una p\u00e9rdida de toda la memoria que ten\u00edamos. <\/p>\n<p><\/p>\n<p>Est\u00e1 claro que esos errores son f\u00e1ciles de corregir. No voy a hablar de ellos. Pero dir\u00e9 que en la nueva versi\u00f3n funciona mucho m\u00e1s r\u00e1pido. El m\u00e9todo es absurdo, pero aun as\u00ed. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b232a6205e708c70f52be0024bbe9980.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00bfC\u00f3mo trabajar correctamente? \u00bfQu\u00e9 necesitamos hacer para esto?<\/p>\n<p><\/p>\n<p>En realidad, las aplicaciones siempre cierran los statements. Todos los libros dicen que deben cerrarse, de lo contrario, la memoria se filtrar\u00e1. <\/p>\n<p><\/p>\n<p>Y PostgreSQL no puede almacenar en cach\u00e9 las consultas. Cada sesi\u00f3n necesita crear esta cach\u00e9 para s\u00ed misma. <\/p>\n<p><\/p>\n<p>Y tampoco queremos gastar tiempo en el an\u00e1lisis. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/85b9574938aa6e6bf59c956e3728bdc3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y como siempre, tenemos dos opciones. <\/p>\n<p><\/p>\n<p>La primera opci\u00f3n es que tomemos y digamos que envolvamos todo en PgSQL. Ah\u00ed hay un cach\u00e9. Lo cachea todo. Resultar\u00e1 genial. Hemos mirado esto. Tenemos 100500 consultas. No funciona. No estamos de acuerdo en convertir las consultas a procedimientos manualmente. No, no. <\/p>\n<p><\/p>\n<p>Tenemos una segunda opci\u00f3n: hacer nuestro propio desarrollo. Abrimos el c\u00f3digo fuente, comenzamos a desarrollar. Desarrollamos y desarrollamos. Result\u00f3 que no era tan complicado hacerlo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/501620b014800406167d20668baef709.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/319\">https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/319<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Esto apareci\u00f3 en agosto de 2015. Ahora hay una versi\u00f3n m\u00e1s moderna. Y todo va genial. Funciona tan bien que no hemos cambiado nada en la aplicaci\u00f3n. Incluso hemos dejado de pensar en PgSQL, es decir, esto nos ha bastado para reducir pr\u00e1cticamente a cero todos los gastos generales. <\/p>\n<p><\/p>\n<p>El servidor prepara las declaraciones en la quinta ejecuci\u00f3n para no gastar memoria en la base de datos para cada consulta temporal. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8ee95e71f92187941989ad0c18ece0c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se puede preguntar: \u00bfd\u00f3nde est\u00e1n los n\u00fameros? \u00bfQu\u00e9 obtienen? Y aqu\u00ed no dar\u00e9 n\u00fameros, porque cada consulta tiene los suyos.<\/p>\n<p><\/p>\n<p>Nuestras consultas eran tales que gast\u00e1bamos alrededor de 20 milisegundos en el an\u00e1lisis en consultas OLTP. Hab\u00eda 0,5 milisegundos en ejecuci\u00f3n, 20 milisegundos en an\u00e1lisis. La consulta era un texto de 10 KiB, 170 l\u00edneas de plan. Esta es una consulta OLTP. Solicita 1, 5, 10 filas, a veces m\u00e1s. <\/p>\n<p><\/p>\n<p>Pero no quer\u00edamos gastar 20 milisegundos. Lo hemos reducido a 0. Todo genial. <\/p>\n<p><\/p>\n<p>\u00bfQu\u00e9 puedes sacar de aqu\u00ed? Si tienes Java, tomas la versi\u00f3n moderna del controlador y te alegras. <\/p>\n<p><\/p>\n<p>Si tienes alg\u00fan otro lenguaje, piensa: \u00bftal vez t\u00fa tambi\u00e9n lo necesitas? Porque desde la perspectiva del lenguaje final, por ejemplo, si es PL 8 o tienes LibPQ, no es obvio que est\u00e1s gastando tiempo no en la ejecuci\u00f3n, sino en el an\u00e1lisis, y eso vale la pena comprobar. \u00bfC\u00f3mo? Todo es gratis. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fda6b1c1b126cb85c970e42335e1dc24.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Excepto que hay errores, algunas peculiaridades. Y sobre eso vamos a hablar ahora. La mayor parte ser\u00e1 sobre arqueolog\u00eda industrial, sobre lo que hemos encontrado, en qu\u00e9 nos hemos topado. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9a3b383f83c5e227cd02952c5825b64f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Si la consulta se genera din\u00e1micamente. Eso sucede. Alguien concatena cadenas, resultando en una consulta SQL.<\/p>\n<p><\/p>\n<p>\u00bfPor qu\u00e9 es malo? Es malo porque cada vez terminamos con una cadena diferente.<\/p>\n<p><\/p>\n<p>Y esta l\u00ednea diferente necesita calcular el hashCode nuevamente. Realmente es una tarea de CPU: encontrar un texto de consulta largo, incluso teniendo el hash, no es tan f\u00e1cil. As\u00ed que la conclusi\u00f3n es simple: no generen consultas. Almacenen en una sola variable. Y disfruten.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/bcd4f729204cecdb572a98f357bcc33f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>El siguiente problema. Los tipos de datos son importantes. Hay ORMs que dicen que no importa qu\u00e9 NULL, que sea cualquiera. Si es Int, decimos setInt. Y si es NULL, que siempre sea VARCHAR. \u00bfY qu\u00e9 importa al final qu\u00e9 NULL haya? La base de datos lo entender\u00e1 por s\u00ed sola. Y esta imagen no funciona. <\/p>\n<p><\/p>\n<p>En la pr\u00e1ctica, a la base de datos realmente le importa. <strong>Si la primera vez dijiste que era un n\u00famero, y la segunda vez dijiste que era VARCHAR, no puedes reutilizar las declaraciones preparadas del servidor. Y en ese caso, tienes que recrear nuestra declaraci\u00f3n desde cero.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/552d9c2e25cf9abbdfef12c98d027740.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Si est\u00e1s ejecutando la misma consulta, aseg\u00farate de que los tipos de datos en la columna no se confundan. Debes cuidar el NULL. Este es un error com\u00fan que tuvimos despu\u00e9s de comenzar a usar PreparedStatements.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5d73c8f5dfa281c3bda962fc3e5edd84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Bien, lo activamos. Tal vez tomamos un controlador. Y el rendimiento cay\u00f3. Todo se volvi\u00f3 malo. <\/p>\n<p><\/p>\n<p>\u00bfC\u00f3mo puede ser eso? \u00bfEs un bug o una caracter\u00edstica? Desafortunadamente, no pudimos entender si era un bug o una caracter\u00edstica. Pero hay un escenario bastante simple para reproducir este problema. Nos sorprendi\u00f3 completamente. Y se trata de una consulta de literalmente una tabla. Por supuesto, tuvimos m\u00e1s de tales consultas. Generalmente inclu\u00edan de dos a tres tablas, pero hay este escenario de reproducci\u00f3n. Toma cualquier versi\u00f3n en tu base de datos y rep\u00edtelo.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fa0fdd037c2eaa31667d5a527bb71f9c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1\">https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1<\/a><\/noindex><\/p>\n<p><\/p>\n<p>El sentido es que tenemos dos columnas, cada una de las cuales est\u00e1 indexada. En una columna hay un mill\u00f3n de filas con el valor NULL. Y en la otra columna hay solo 20 filas. Cuando ejecutamos sin variables asociadas, todo funciona bien. <\/p>\n<p><\/p>\n<p>Si comenzamos a ejecutar con variables vinculadas, es decir, usamos un signo \u00ab?\u00bb o \u00ab$1\u00bb para nuestra consulta, \u00bfqu\u00e9 obtenemos al final?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e91c397796c7ddcbade3bc090719e9d1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1\">https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1<\/a><\/noindex><\/p>\n<p><\/p>\n<p>La primera ejecuci\u00f3n - como se supone. La segunda - un poco m\u00e1s r\u00e1pida. Algo se ha almacenado en cach\u00e9. Tercera, cuarta, quinta. Luego, \u00a1pum! - y as\u00ed. Y lo peor es que esto sucede en la sexta ejecuci\u00f3n. \u00bfQui\u00e9n sab\u00eda que hab\u00eda que hacer exactamente seis ejecuciones para entender cu\u00e1l es realmente el plan de ejecuci\u00f3n?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/893c955bc1e2e15a6986690e516f72a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00bfQui\u00e9n es el culpable? \u00bfQu\u00e9 ha pasado? La base de datos contiene optimizaci\u00f3n. Y est\u00e1 m\u00e1s o menos optimizada para un caso gen\u00e9rico. Por lo tanto, a partir de cierta cantidad de veces, cambia a un plan gen\u00e9rico que, lamentablemente, puede resultar ser diferente. Puede ser el mismo, o puede ser diferente. Y hay un valor umbral que conduce a tal comportamiento. <\/p>\n<p><\/p>\n<p>\u00bfQu\u00e9 se puede hacer al respecto? Aqu\u00ed, por supuesto, es m\u00e1s complicado hacer suposiciones. Hay una soluci\u00f3n sencilla que utilizamos. Es +0, OFFSET 0. Seguramente, conoces este tipo de soluciones. Simplemente tomamos y a\u00f1adimos \u00ab+0\u00bb a la consulta y todo sale bien. Lo mostrar\u00e9 m\u00e1s adelante. <\/p>\n<p><\/p>\n<p>Y hay otra opci\u00f3n: observar los planes m\u00e1s detenidamente. El desarrollador no solo debe escribir la consulta, sino tambi\u00e9n decir \u00abexplain analyze\u00bb 6 veces. Si son 5, no servir\u00e1. <\/p>\n<p><\/p>\n<p>Y hay una tercera opci\u00f3n: enviar una carta a pgsql-hackers. Yo escrib\u00ed, pero todav\u00eda no est\u00e1 claro si es un error o una caracter\u00edstica.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8dc8d3a78e0b794e1ceba20f6ca914ae.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1\">https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Mientras pensamos si es un error o una caracter\u00edstica, arreglemos esto. Tomemos nuestra consulta y a\u00f1adamos \u00ab+0\u00bb. Todo bien. Dos caracteres y ni siquiera hay que pensar en c\u00f3mo o qu\u00e9. Muy sencillo. Simplemente hemos prohibido a la base de datos usar el \u00edndice en esa columna. No hay \u00edndice en la columna \u00ab+0\u00bb y eso es todo, la base de datos no utiliza el \u00edndice, todo bien. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5261d80d084786a15b9764f6367014cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Esta es la regla de los 6 \u00abexplain\u00bb. Actualmente en las versiones actuales hay que hacerlo 6 veces si tienes variables relacionadas. Si no tienes variables relacionadas, lo hacemos de esta manera. Al final, esta consulta es la que falla. No es complicado.<\/p>\n<p><\/p>\n<p>A primera vista, \u00bfcu\u00e1nto m\u00e1s se puede? Aqu\u00ed hay un error, all\u00e1 hay un error. Realmente hay errores en todas partes. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/674dc7e7b4624baa5c79eee9e1e89db0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Veamos un ejemplo m\u00e1s. Supongamos que tenemos dos esquemas. Esquema A con la tabla \u042b y esquema B con la tabla \u042b. Consulta: seleccionar datos de la tabla. \u00bfQu\u00e9 tendremos entonces? Tendremos un error. Tendremos todo lo mencionado anteriormente. La regla es: hay un error en todas partes, tendremos todo lo mencionado anteriormente.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dd6f544bb9e930c39e36523c9afe6003.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ahora la pregunta es: \u00ab\u00bfPor qu\u00e9?\u00bb. Aparentemente, hay documentaci\u00f3n que dice que si tenemos un esquema, hay una variable \u00absearch_path\u00bb, que indica d\u00f3nde buscar la tabla. Aparentemente, la variable est\u00e1 presente.<\/p>\n<p><\/p>\n<p>\u00bfCu\u00e1l es el problema? El problema es que las declaraciones preparadas en el servidor no sospechan que alguien pueda cambiar el search_path. Este valor permanece como una constante para la base de datos. Y algunas partes pueden no captar los nuevos valores. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f738301606d84d72bfa7cc5b568c0df8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por supuesto, esto depende de la versi\u00f3n en la que est\u00e9s probando. Depende de cu\u00e1n diferentes sean tus tablas. Y la versi\u00f3n 9.1 simplemente ejecutar\u00e1 las consultas antiguas. Las nuevas versiones pueden detectar la trampa y decir que tienes un error.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4761cd92835b94acbf9d6c9d21817316.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/message-id\/CAB=Je-GQOW7kU9Hn3AqP1vhaZg_wE9Lz6F4jSp-7cm9_M6DyVA@mail.gmail.com\">Set search_path + declaraciones preparadas en el servidor =<br \/>\nel plan en cach\u00e9 no debe cambiar el tipo de resultado<\/a><\/noindex><\/p>\n<p><\/p>\n<p>\u00bfC\u00f3mo se soluciona esto? Hay una receta sencilla: no lo hagas. No cambies el search_path mientras la aplicaci\u00f3n est\u00e9 en funcionamiento. Si lo cambias, lo mejor es crear una nueva conexi\u00f3n.<\/p>\n<p><\/p>\n<p>Podemos discutir, es decir, abrir, discutir y a\u00f1adir. Tal vez logremos convencer a los desarrolladores de bases de datos de que, en caso de que alguien cambie un valor, la base de datos deber\u00eda informar al cliente: \u2018Mira, aqu\u00ed has actualizado un valor. Tal vez necesites restablecer o recrear las declaraciones?\u2019. Actualmente, la base de datos act\u00faa de forma sigilosa y no informa de que internamente las declaraciones han cambiado. <\/p>\n<p><\/p>\n<p>Y vuelvo a enfatizar: esto no es t\u00edpico de Java. Veremos lo mismo en PL\/pgSQL uno a uno. Pero se reproducir\u00e1 ah\u00ed.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a4e7b201d0c0aa4a0092d2b6ff152df7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Intentemos seleccionar algunos datos. Seleccionamos, seleccionamos. Tenemos una tabla de un mill\u00f3n de filas. Cada fila tiene un kilobyte. Aproximadamente un gigabyte de datos. Y tenemos una memoria operativa en la m\u00e1quina Java de 128 megabytes. <\/p>\n<p><\/p>\n<p>Nosotros, como se recomienda en todos los libros, usamos procesamiento por flujo. Es decir, abrimos resultSet y leemos los datos poco a poco. \u00bfFuncionar\u00e1 esto? \u00bfNo se agotar\u00e1 la memoria? \u00bfLeer\u00e1 poco a poco? Vamos a confiar en la base de datos, confiemos en Postgres. No confiamos. \u00bfCaeremos en OutOfMemory? \u00bfA qui\u00e9n le ha ocurrido un OutOfMemory? \u00bfY qui\u00e9n pudo solucionarlo despu\u00e9s? Alguien pudo solucionarlo. <\/p>\n<p><\/p>\n<p>Si tienes un mill\u00f3n de filas, no puedes simplemente seleccionarlas. Es absolutamente necesario usar OFFSET\/LIMIT. \u00bfQui\u00e9n est\u00e1 a favor de esta opci\u00f3n? \u00bfY qui\u00e9n a favor de jugar con autoCommit? <\/p>\n<p><\/p>\n<p>Aqu\u00ed, como de costumbre, la opci\u00f3n m\u00e1s inesperada resulta ser la correcta. Y si de repente desactivas autoCommit, eso ayudar\u00e1. \u00bfPor qu\u00e9? La ciencia no lo sabe. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2e5d9d2a8450a9069155de86a8ec387a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pero por defecto, todos los clientes que se conectan a la base de datos Postgres seleccionan los datos completos. PgJDBC no es una excepci\u00f3n en este aspecto, selecciona todas las filas.<\/p>\n<p><\/p>\n<p>Hay una variaci\u00f3n en el tema FetchSize, es decir, se puede especificar a nivel de una declaraci\u00f3n individual que, por favor, seleccione datos de 10, 50. Pero esto no funciona hasta que apagues autoCommit. Apagaste autoCommit: empieza a funcionar. <\/p>\n<p><\/p>\n<p>Sin embargo, recorrer el c\u00f3digo y poner setFetchSize en todas partes es inc\u00f3modo. Por eso hicimos una configuraci\u00f3n que indicar\u00e1 un valor predeterminado para toda la conexi\u00f3n.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c9ac8e483dc6bfdbbc300972ee1ab1e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Esto es lo que hemos dicho. Hemos configurado el par\u00e1metro. \u00bfY qu\u00e9 hemos conseguido? Si seleccionamos un n\u00famero peque\u00f1o, por ejemplo, si seleccionamos 10 filas, tenemos costos adicionales bastante grandes. Por lo tanto, este valor deber\u00eda ser alrededor de cien. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/073e7a4af63688396eefe332ba8261d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Idealmente, por supuesto, tambi\u00e9n deber\u00edamos aprender a limitar en bytes, pero la receta es esta: establecemos defaultRowFetchSize por encima de cien y nos alegramos. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e3078faf2078fcaec10d6d99872a9990.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pasemos a la inserci\u00f3n de datos. Insertar es m\u00e1s sencillo, hay diferentes variantes. Por ejemplo, INSERT, VALUES. Esa es una buena opci\u00f3n. Se puede hablar de \"INSERT SELECT\". En la pr\u00e1ctica, es lo mismo. No hay diferencia en rendimiento. <\/p>\n<p><\/p>\n<p>Los libros dicen que se debe ejecutar un Batch statement, y tambi\u00e9n dicen que se pueden ejecutar comandos m\u00e1s complejos con varios par\u00e9ntesis. Y en Postgres hay una funci\u00f3n maravillosa: se puede hacer COPY, es decir, hacerlo m\u00e1s r\u00e1pido. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4d281c9515bdf8de7fbf1e9922d192d0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Si medimos, podemos hacer algunas descubrimientos interesantes nuevamente. \u00bfC\u00f3mo queremos que esto funcione? Queremos no analizar y no ejecutar comandos innecesarios. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b2e4343c51dab3ddb6919bf0f117c4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En la pr\u00e1ctica, TCP no nos permite hacer eso. Si el cliente est\u00e1 ocupado enviando una solicitud, la base de datos, en sus intentos de enviarnos respuestas, no lee las solicitudes. Como resultado, el cliente espera a que la base de datos lea la solicitud, y la base de datos espera al cliente a que lea la respuesta. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/17a062c30ddd83cb890775ec1722044f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y por eso el cliente se ve obligado a enviar peri\u00f3dicamente un paquete de sincronizaci\u00f3n. Interacciones de red innecesarias, p\u00e9rdida de tiempo adicional.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ae7a4f32e2949c1d0550da051937de02.jpg\" style=\"display:block;margin: 0 auto;\" \/>Y cuanto m\u00e1s a\u00f1adimos, peor se vuelve. El controlador es bastante pesimista y los a\u00f1ade con bastante frecuencia, aproximadamente cada 200 filas, dependiendo del tama\u00f1o de las filas, etc. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/82b1d597986633a8c4b7952517ca6477.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/380\">https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/380<\/a><\/noindex><\/p>\n<p><\/p>\n<p>A veces, corregir solo una l\u00ednea acelera todo diez veces. Eso sucede. \u00bfPor qu\u00e9? Como siempre, una constante ya se hab\u00eda utilizado en alg\u00fan lugar. Y el valor \"128\" significaba no utilizar batching.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b6bcd95591b36441037b4c4631d2ad0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/openjdk.java.net\/projects\/code-tools\/jmh\/\">Java microbenchmark harness<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Es bueno que esto no haya llegado a la versi\u00f3n oficial. Lo descubrimos antes de comenzar a lanzar la versi\u00f3n. Todos los valores que menciono est\u00e1n basados en versiones modernas. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28c82d9e11f6bdaf3cf62b49fc074d68.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vamos a medir. Medimos InsertBatch simple. Medimos InsertBatch m\u00faltiple, es decir, lo mismo, pero con muchos values. Un movimiento astuto. No todos pueden hacer eso, pero es un movimiento simple, mucho m\u00e1s f\u00e1cil que COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/72f7cf6c3b9d9175d3e5a6d5410fe209.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Se puede hacer COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2b0d8bbcc50f1293c9a8a1eb8eb70d2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Y se puede hacer esto en estructuras. Declarar el tipo User por defecto, pasar un arreglo e INSERTar directamente en la tabla. <\/p>\n<p><\/p>\n<p>Si abres el enlace: pgjdbc\/ubenchmsrk\/InsertBatch.java, el c\u00f3digo est\u00e1 en GitHub. Puedes ver espec\u00edficamente qu\u00e9 consultas se generan all\u00ed. No es lo m\u00e1s importante.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28dede211fe401286685ca62081453de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lo hemos lanzado. Y lo primero que entendimos es que no usar batch es simplemente imposible. Todas las opciones de batching son iguales a cero, es decir, el tiempo de ejecuci\u00f3n es pr\u00e1cticamente cero en comparaci\u00f3n con la ejecuci\u00f3n \u00fanica. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4ea68f712bbdeadd35f5baa4ddaeff33.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Estamos insertando datos. Es una tabla bastante simple. Tres columnas. \u00bfY qu\u00e9 vemos aqu\u00ed? Vemos que las tres opciones son aproximadamente comparables. Y COPY, por supuesto, es mejor.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2686f1d7eea347a839ac23aef2a27e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Esto es cuando insertamos en peque\u00f1as porciones. Cuando dijimos que un valor son VALUES, dos valores son VALUES, tres valores son VALUES o que enumeramos 10 separados por comas. Esto es justo ahora horizontal. 1, 2, 4, 128. Se nota que el Batch Insert, que est\u00e1 dibujado en azul, le facilita mucho la vida. Es decir, cuando insertas uno a uno o incluso cuando insertas cuatro, se vuelve dos veces mejor, simplemente porque pusimos un poco m\u00e1s en VALUES. Menos operaciones EXECUTE.<\/p>\n<p><\/p>\n<p>Usar COPY en vol\u00famenes peque\u00f1os es extremadamente poco prometedor. Ni siquiera dibuj\u00e9 en los dos primeros. Van hacia el cielo, es decir, esos n\u00fameros verdes para COPY.<\/p>\n<p><\/p>\n<p>COPY debe utilizarse cuando tienes al menos m\u00e1s de cien filas de datos. Los costos de abrir esta conexi\u00f3n son grandes. Y, sinceramente, no he explorado en esta direcci\u00f3n. Optimic\u00e9 el batch, pero no COPY. <\/p>\n<p><\/p>\n<p>\u00bfQu\u00e9 hacemos despu\u00e9s? Medimos. Entendemos que hay que usar estructuras o un ingenioso batch que combine varios valores. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL y JDBC exprimir hasta la \u00faltima gota. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e02fa2574e2d1b678382db15064610d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u00bfQu\u00e9 se debe resaltar de la exposici\u00f3n de hoy?<\/p>\n<p><\/p>\n<ul>\n<li>PreparedStatement es lo m\u00e1s importante. Esto aporta mucho a la eficiencia. Trae un gran barril de alquitr\u00e1n. <\/li>\n<li>Y hay que hacer EXPLAIN ANALYZE 6 veces.<\/li>\n<li>Y hay que diluir OFFSET 0, y usar trucos como +0 para corregir el porcentaje restante de nuestras consultas problem\u00e1ticas.<\/li>\n<\/ul>\n<p>Fuente: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/499794\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot; \u0414\u043e\u0431\u0440\u044b\u0439 \u0434\u0435\u043d\u044c! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432. \u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e 10 \u043b\u0435\u0442 \u0432 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 NetCracker. \u0418 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0441\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e. \u0412\u0441\u0435, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 Java, \u0432\u0441\u0435, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 SQL \u2013 \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u044f \u043b\u044e\u0431\u043b\u044e. \u0418 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79894,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79893","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot;\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438. \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot;\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-01T11:43:12+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-01T11:43:12+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47PostgreSQL y JDBC exprimir todo el jugo. Vladimir Sitnikov | ProHoster","description":"Les propongo que se familiaricen con la transcripci\u00f3n de la presentaci\u00f3n de principios de 2016 de Vladimir Sitnikov \"PostgreSQL y JDBC exprimir hasta la \u00faltima gota\"","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438. \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432 | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot;","og:url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-01T11:43:12+00:00","article:modified_time":"2020-05-01T11:43:12+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79893","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:29:39","updated":"2022-10-10 00:32:43","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/79893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=79893"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/79893\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/79894"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=79893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=79893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=79893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}