{"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\/nl\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","title":{"rendered":"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Ik nodig u uit om de transcriptie van de presentatie van begin 2016 van Vladimir Sitnikov \"PostgreSQL en JDBC: we persen er alles uit\" te bekijken.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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 en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/030666abda53aa388b1cb1d0c46a7524.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Goedemiddag! Mijn naam is Vladimir Sitnikov. Ik werk al 10 jaar bij NetCracker. En ik ben voornamelijk bezig met prestaties. Alles wat met Java en SQL te maken heeft \u2013 dat is waar ik van hou. <\/p>\n<p><\/p>\n<p>En vandaag zal ik vertellen over de uitdagingen die we in het bedrijf tegenkwamen toen we PostgreSQL begonnen te gebruiken als databas server. En we werken voornamelijk met Java. Maar wat ik vandaag zal vertellen, is niet alleen gerelateerd aan Java. Zoals de praktijk heeft aangetoond, komt dit ook voor in andere talen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b01a214d782c7e32797a6c6466457979.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>We zullen bespreken:<\/p>\n<p><\/p>\n<ul>\n<li>het ophalen van gegevens. <\/li>\n<li>het opslaan van gegevens. <\/li>\n<li>en ook de prestaties. <\/li>\n<li>En over de valkuilen die daar verborgen zijn. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/57da0c6aa4bb62e1beb77160f5aee7e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Laten we beginnen met een simpele vraag. We selecteren \u00e9\u00e9n rij uit de tabel op basis van de primaire sleutel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/d5fcb1172aef402a87064498bf8a5218.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>De database bevindt zich op dezelfde host. En dit hele proces kost 20 milliseconden.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/103b7f9736b82a3313491b2f0d2a5824.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Die 20 milliseconden zijn echt veel. Als je 100 van zulke verzoeken hebt, verlies je tijd in seconden om deze verzoeken te verwerken, d.w.z. je verspilt tijd.<\/p>\n<p><\/p>\n<p>We houden er niet van om dat te doen en kijken wat de database ons hiervoor biedt. De database biedt ons twee opties voor query-uitvoering. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b467e86a0f8c4c32cea182fe27a28e6e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>De eerste optie is een eenvoudige query. Wat is het voordeel ervan? Je neemt het en stuurt het gewoon op, en verder niets. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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>De database heeft ook een uitgebreide query, die geavanceerder maar functioneler is. Je kunt afzonderlijk aanvragen voor parsing, uitvoering, associatie van variabelen, enz. <\/p>\n<p><\/p>\n<p>Super uitgebreide query \u2013 dat is iets wat we in deze presentatie niet zullen behandelen. Misschien willen we iets van de database, en er is een lijst met wensen, die op een bepaalde manier is opgesteld, dat wil zeggen, dat is wat we willen, maar het is nu en in het komende jaar niet mogelijk. Daarom hebben we het gewoon opgeschreven en zullen we de belangrijkste mensen hierover onder druk zetten.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/19094729074fd28c5b9f236833a9a266.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Wat we kunnen doen, is de simple query en de extended query.<\/p>\n<p><\/p>\n<p>Wat is het kenmerk van elke benadering? <\/p>\n<p><\/p>\n<p>Een eenvoudige query is goed te gebruiken voor eenmalige uitvoering. Een keer uitgevoerd en vergeten. En het probleem is dat het geen binaire gegevensformaten ondersteunt, d.w.z. voor sommige hoog-performante systemen is het niet geschikt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/062c0e45cefd91ece331a306a7651bde.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Uitgebreide query \u2013 helpt om tijd te besparen bij het parseren. Dit is wat we hebben gedaan en begonnen te gebruiken. Het heeft ons enorm geholpen. Er is niet alleen besparing op het parseren. Er is ook besparing op gegevensoverdracht. Gegevens in binaire vorm verzenden is veel effici\u00ebnter. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6df83a2f3736568668cf9d74de5d9758.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Laten we naar de praktijk gaan. Zo ziet een typisch applicatie eruit. Dit kan Java zijn, enz. <\/p>\n<p><\/p>\n<p>We hebben een statement aangemaakt. Een commando uitgevoerd. Een close gemaakt. Waar is de fout? Wat is het probleem? Er zijn geen problemen. Zo staat het in alle boeken. Zo moet je schrijven. Als je maximale prestaties wilt, schrijf dan zo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6923293946dec45b3fd508235728ab95.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Maar de praktijk heeft aangetoond dat dit niet werkt. Waarom? Omdat we de methode 'close' hebben. En als we het zo doen, is dat vanuit het perspectief van de database als het werk van een roker met de database. We zeiden 'PARSE EXECUTE DEALLOCATE'.<\/p>\n<p><\/p>\n<p>Waarom deze overbodige creaties en uitvoeringen van statements? Ze zijn voor niemand nodig. Maar meestal is het zo met PreparedStatement, dat wanneer we ze sluiten, ze alles in de database sluiten. Dat is niet wat we willen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5a357a209e414024c437d042f600f251.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>We willen, net als gezonde mensen, met de database werken. Een keer nemen we en bereiden we ons statement voor, en daarna voeren we het veelvuldig uit. Veelvuldig betekent eigenlijk \u00e9\u00e9n keer in het hele leven van de applicatie parseren. En bij verschillende REST gebruiken we dezelfde statement id. Dat is ons doel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ac4aed702a624ad9f9addc4362daf760.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hoe bereiken we dit? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0f101d890d1a2af8e99f8a3a8a06fd5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Heel eenvoudig \u2013 we hoeven statements niet te sluiten. We schrijven zo: 'prepare' 'execute'. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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 en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/724646bfc55b5e2b611b1584ca8ba6aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Als we dit draaien, is het duidelijk dat ergens iets volloopt. Als het niet duidelijk is, kunnen we het meten. Laten we een benchmark maken, waarin we zo'n simpele methode hebben. We cre\u00ebren een statement. We draaien het op een bepaalde versie van de driver en krijgen dat het vrij snel instort met verlies van al het geheugen dat we hebben aangeschaft. <\/p>\n<p><\/p>\n<p>Het is duidelijk dat zulke fouten gemakkelijk te verhelpen zijn. Ik ga er niet verder op in. Maar ik zal zeggen dat het in de nieuwe versie veel sneller werkt. Een onsamenhangende methode, maar desondanks. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b232a6205e708c70f52be0024bbe9980.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hoe werken we correct? Wat moeten we hiervoor doen?<\/p>\n<p><\/p>\n<p>In de realiteit sluiten applicaties altijd statements. In alle boeken staat dat je ze moet sluiten, anders lekt geheugen. <\/p>\n<p><\/p>\n<p>En PostgreSQL kan geen queries cachen. Elke sessie moet deze cache zelf aanmaken. <\/p>\n<p><\/p>\n<p>En we willen ook geen tijd verspillen aan parseren. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/85b9574938aa6e6bf59c956e3728bdc3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En zoals gewoonlijk hebben we twee opties. <\/p>\n<p><\/p>\n<p>De eerste optie is dat we zeggen laten we alles in PgSQL wikkelen. Daar is een cache. Het cached alles. Het zou geweldig zijn. We hebben dit bekeken. We hebben 100500 aanvragen. Het werkt niet. We zijn het er niet mee eens om handmatig de aanvragen om te zetten in procedures. Nee, nee. <\/p>\n<p><\/p>\n<p>We hebben een tweede optie \u2013 zelf aan de slag gaan. We openen de broncode en beginnen te programmeren. We programmeren maar door. Het bleek niet zo moeilijk te zijn om dit te doen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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>Dit verscheen in augustus 2015. Nu is er al een modernere versie. En alles is geweldig. Het werkt zo goed dat we niets aan de applicatie veranderen. En we zijn zelfs gestopt met denken aan PgSQL, dat wil zeggen, dit volstond om alle overheadkosten tot vrijwel nul te verlagen. <\/p>\n<p><\/p>\n<p>Bijgevolg wordt Server-prepared statements geactiveerd bij de vijfde uitvoering om geheugen in de database niet te verspillen aan elk eenmalig verzoek. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8ee95e71f92187941989ad0c18ece0c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Je kunt vragen \u2013 waar zijn de cijfers? Wat krijg je? En hier kan ik geen cijfers geven, omdat elke aanvraag zijn eigen cijfers heeft.<\/p>\n<p><\/p>\n<p>Onze aanvragen waren zodanig dat we op OLTP-aanvragen ongeveer 20 milliseconden besteedden aan parsing. Er was 0,5 milliseconde voor uitvoering, 20 milliseconden voor parsing. Aanvraag \u2013 10 KiB tekst, 170 regels plan. Dit is een OLTP-aanvraag. Het vraagt 1, 5, 10 regels op, soms meer. <\/p>\n<p><\/p>\n<p>Maar we wilden helemaal geen 20 milliseconden besteden. We hebben het teruggebracht naar 0. Alles is geweldig. <\/p>\n<p><\/p>\n<p>Wat kun je hieruit halen? Als je Java hebt, neem dan de moderne versie van de driver en wees blij. <\/p>\n<p><\/p>\n<p>Als je een andere taal hebt, denk dan na \u2013 misschien heb je dit ook nodig? Want vanuit het perspectief van de doeltaal, bijvoorbeeld als je PL 8 of LibPQ hebt, is het niet vanzelfsprekend dat je tijd verliest, niet aan de uitvoering, maar aan de parsing en dit moet je verifi\u00ebren. Hoe? Alles is gratis. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fda6b1c1b126cb85c970e42335e1dc24.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Behalve dat er fouten zijn, bepaalde eigenaardigheden. En daar gaan we het nu over hebben. Het grootste deel zal gaan over industri\u00eble archeologie, over wat we vonden, tegen wat we aanliepen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9a3b383f83c5e227cd02952c5825b64f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Als de aanvraag dynamisch wordt gegenereerd. Dat komt voor. Iemand plakt de strings aan elkaar, en dat resulteert in een SQL-aanvraag.<\/p>\n<p><\/p>\n<p>Waarom is dit slecht? Het is slecht omdat we elke keer uiteindelijk een andere string krijgen.<\/p>\n<p><\/p>\n<p>Ook deze verschillende string moet opnieuw de hashCode berekenen. Dit is echt een CPU-taak - het vinden van een lange aanvraagtekst in zelfs een bestaande hash is niet zo eenvoudig. Dus de boodschap is simpel: genereer geen aanvragen. Bewaar ze in \u00e9\u00e9n enkele variabele. En wees tevreden.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/bcd4f729204cecdb572a98f357bcc33f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Het volgende probleem. Datatypes zijn belangrijk. Er zijn ORM's die zeggen dat het niet uitmaakt welke NULL, laat het maar een of andere zijn. Als het Int is, dan zeggen we setInt. En als het NULL is, laat het dan altijd VARCHAR zijn. En wat maakt het uiteindelijk uit welke NULL daar is? De database begrijpt het uiteindelijk zelf. En zo'n situatie werkt niet. <\/p>\n<p><\/p>\n<p>In de praktijk maakt de database het helemaal niet uit. <strong>Als je de eerste keer zegt dat het een getal is, en de tweede keer zegt dat het VARCHAR is, dan is het onmogelijk om Server-prepared statements opnieuw te gebruiken. En in dat geval moet je onze statement opnieuw aanmaken.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/552d9c2e25cf9abbdfef12c98d027740.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Als je dezelfde aanvraag meerdere keren uitvoert, zorg er dan voor dat de datatypes in de kolom niet door elkaar raken. Let op NULL. Dit is een veelvoorkomende fout die we hebben gehad after we begonnen met PreparedStatements.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5d73c8f5dfa281c3bda962fc3e5edd84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ok\u00e9, we hebben het ingeschakeld. Misschien hebben we een driver genomen. En de prestaties zijn gedaald. Alles is slecht geworden. <\/p>\n<p><\/p>\n<p>Hoe kan dit gebeuren? Is het een bug of een feature? Helaas, we konden niet begrijpen of het een bug of een feature is. Maar er is een vrij eenvoudig scenario om dit probleem te reproduceren. Het heeft ons volledig verrast. Het betreft een query uit letterlijk \u00e9\u00e9n tabel. We hadden natuurlijk meer van zulke queries. Over het algemeen omvatten ze twee of drie tabellen, maar er is zo'n scenario om te reproduceren. Neem op jouw database enige versie en reproduceer het.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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>De essentie is dat we twee kolommen hebben, die elk ge\u00efndexeerd zijn. In de ene kolom ligt een miljoen regels met de waarde NULL. En in de andere kolom liggen slechts 20 regels. Wanneer we uitvoeren zonder gekoppelde variabelen, werkt alles goed. <\/p>\n<p><\/p>\n<p>Als we beginnen met uitvoeren met gekoppelde variabelen, d.w.z. we voeren het teken \u00ab?\u00bb of \u00ab$1\u00bb voor onze aanvraag uit, wat krijgen we dan uiteindelijk?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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>De eerste uitvoering - zoals het hoort. De tweede - iets sneller. Iets is gecached. De derde, vierde, vijfde. Dan klap - en zo gaat het. En het slechtste is dat dit gebeurt bij de zesde uitvoering. Wie wist dat je precies zes uitvoeringen moest doen om te begrijpen wat het echte uitvoeringsplan is?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/893c955bc1e2e15a6986690e516f72a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Wie zit er achter? Wat is er gebeurd? De database bevat optimalisatie. En deze is als het ware geoptimaliseerd voor de algemene situatie. En, dienovereenkomstig, vanaf een bepaald moment gaat het over naar een algemeen plan, dat helaas anders kan zijn. Het kan hetzelfde zijn, maar het kan ook anders zijn. En er is een drempelwaarde die dit gedrag veroorzaakt. <\/p>\n<p><\/p>\n<p>Wat kunnen we hieraan doen? Hier is het natuurlijk moeilijk om iets te veronderstellen. Er is een eenvoudige oplossing die we gebruiken. Dit is +0, OFFSET 0. Zeker weten dat je zulke oplossingen kent. We nemen het gewoon en voegen \u2018+0\u2019 toe aan de query en het is allemaal goed. Ik zal het later laten zien. <\/p>\n<p><\/p>\n<p>En er is nog een optie \u2013 de plannen aandachtiger bekijken. De ontwikkelaar moet niet alleen de query schrijven, maar ook zes keer zeggen \u2018explain analyze\u2019. Als het er vijf zijn, is het niet goed. <\/p>\n<p><\/p>\n<p>En er is nog een derde optie \u2013 een brief schrijven naar pgsql-hackers. Ik heb het geschreven, maar het is nog niet duidelijk \u2013 is dit een bug of een functie.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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>Terwijl we denken \u2013 is het een bug of een functie, laten we het oplossen. We nemen onze query en voegen \u2018+0\u2019 toe. Het is allemaal goed. Twee karakters en je hoeft zelfs niet na te denken over hoe en wat. Heel eenvoudig. We hebben de database gewoon verboden om de index op deze kolom te gebruiken. We hebben geen index op de kolom \u2018+0\u2019 en dat is het, de database gebruikt de index niet, alles is goed. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5261d80d084786a15b9764f6367014cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dit is de regel van zes explains. In de huidige versies moet je het zes keer doen, als je gekoppelde variabelen hebt. Als je geen gekoppelde variabelen hebt, dan doen we het zo. En uiteindelijk faalt precies deze query. Het is niet ingewikkeld.<\/p>\n<p><\/p>\n<p>Het zou zo zijn, hoe lang kan dat duren? Hier is een bug, daar is een bug. Echt, er is overal een bug. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/674dc7e7b4624baa5c79eee9e1e89db0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Laten we nog eens kijken. Bijvoorbeeld, we hebben twee schema's. Schema A met tabel Y en schema B met tabel Y. De query \u2013 selecteer gegevens uit de tabel. Wat hebben we in dit geval? We krijgen een fout. We krijgen alles wat hierboven is genoemd. De regel is zo \u2013 bug overal, we zullen alles hierboven hebben.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dd6f544bb9e930c39e36523c9afe6003.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Nu de vraag: \u2018Waarom?\u2019. Het lijkt erop dat er documentatie is, dat als we een schema hebben, er een variabele \u2018search_path\u2019 is die aangeeft waar de tabel moet worden gezocht. Het lijkt erop dat de variabele er is.<\/p>\n<p><\/p>\n<p>Wat is het probleem? Het probleem is dat server-prepared statements niet vermoeden dat iemand het search_path kan wijzigen. Deze waarde blijft als het ware constant voor de database. En sommige delen kunnen de nieuwe waarden mogelijk niet oppikken. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f738301606d84d72bfa7cc5b568c0df8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Natuurlijk hangt het af van de versie waarop je test. Het hangt af van hoe verschillend je tabellen zijn. En versie 9.1 zal simpelweg oudere verzoeken uitvoeren. Nieuwe versies kunnen een trucje ontdekken en zeggen dat je een fout hebt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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 + server-prepared statements =<br \/>\ncached plan moet het resultaattype niet veranderen<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Hoe dit op te lossen? Er is een eenvoudig recept \u2013 doe het niet zo. Verander search_path niet terwijl de applicatie draait. Als je het verandert, cre\u00eber dan beter een nieuwe verbinding.<\/p>\n<p><\/p>\n<p>We kunnen erover discussi\u00ebren, dat wil zeggen, open het, bespreek het, schrijf verder. Misschien overtuigen we de database-ontwikkelaars dat, wanneer iemand een waarde verandert, de database de cli\u00ebnt moet zeggen: 'Kijk, je waarde is hier ge\u00fcpdatet. Misschien moet je de statements resetten, opnieuw cre\u00ebren?'. Momenteel gedraagt de database zich verborgen en geeft helemaal geen melding dat er ergens intern iets in de statements is veranderd. <\/p>\n<p><\/p>\n<p>En ik benadruk opnieuw \u2013 dit is iets wat niet typisch is voor Java. We zullen hetzelfde \u00e9\u00e9n op \u00e9\u00e9n zien in PL\/pgSQL. Maar daar zal het worden gereproduceerd.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a4e7b201d0c0aa4a0092d2b6ff152df7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Laten we proberen weer gegevens te selecteren. We selecteren-en-selecteren. We hebben een tabel met een miljoen rijen. Elke rij is ongeveer een kilobyte. Ongeveer een gigabyte aan gegevens. En we hebben werkgeheugen in de Java-machine van 128 megabyte. <\/p>\n<p><\/p>\n<p>We gebruiken, zoals aanbevolen in alle boeken, stromen voor verwerking. Dat wil zeggen, we openen resultSet en lezen daar de gegevens beetje bij beetje. Werkt dit? Zal het niet uitvallen door geheugen? Zal het beetje bij beetje lezen? Laten we geloven in de database, laten we geloven in Postgres. We geloven niet. Vallen we door OutOfMemory? Wie heeft er last van OutOfMemory gehad? En wie heeft het na dat probleem kunnen repareren? Iemand heeft het weten te repareren. <\/p>\n<p><\/p>\n<p>Als je een miljoen rijen hebt, kun je niet zomaar kiezen. Je moet verplicht OFFSET\/LIMIT gebruiken. Wie is voor deze optie? En wie is voor de optie dat je met autoCommit moet experimenteren? <\/p>\n<p><\/p>\n<p>Hier blijkt, zoals gewoonlijk, de meest onverwachte optie de juiste te zijn. En als je plotseling autoCommit uitschakelt, helpt dat. Waarom zo? De wetenschap weet het niet. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2e5d9d2a8450a9069155de86a8ec387a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Maar standaard selecteren alle clients die verbinding maken met de Postgres-database de gegevens in hun geheel. PgJDBC is hierin geen uitzondering, het selecteert alle rijen.<\/p>\n<p><\/p>\n<p>Er is een variatie op het onderwerp FetchSize, dat wil zeggen, je kunt op het niveau van een individuele statement zeggen, dat je hier, alsjeblieft, gegevens wilt selecteren per 10, 50. Maar dit werkt niet totdat je autoCommit uitschakelt. AutoCommit uitgeschakeld \u2013 het begint te werken. <\/p>\n<p><\/p>\n<p>Maar door de code te doorlopen en overal setFetchSize in te stellen, is ongemakkelijk. Daarom hebben we een instelling gemaakt die de standaardwaarde voor de hele verbinding aangeeft.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c9ac8e483dc6bfdbbc300972ee1ab1e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dat hebben we gezegd. We hebben de parameter ingesteld. En wat hebben we bereikt? Als we selecteren met een klein aantal, bijvoorbeeld met 10 rijen, zijn de overheadkosten behoorlijk hoog. Daarom moeten we deze waarde op ongeveer honderd instellen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/073e7a4af63688396eefe332ba8261d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Idealiter leren we ook om het in bytes te beperken, maar het recept is als volgt: stel defaultRowFetchSize hoger dan honderd in en geniet. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e3078faf2078fcaec10d6d99872a9990.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Laten we verder gaan met het invoegen van gegevens. Invoegen is eenvoudiger, er zijn verschillende opties. Bijvoorbeeld, INSERT, VALUES. Dat is een goede optie. Je kunt ook 'INSERT SELECT' zeggen. In de praktijk is dat hetzelfde. Er is geen verschil in prestaties. <\/p>\n<p><\/p>\n<p>Boeken zeggen dat je Batch statements moet uitvoeren, boeken zeggen dat je complexere opdrachten met meerdere haakjes kunt uitvoeren. En in Postgres is er een geweldige functie \u2013 je kunt COPY doen, dat wil zeggen, het sneller doen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4d281c9515bdf8de7fbf1e9922d192d0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Als we meten, kunnen we weer een paar interessante ontdekkingen doen. Hoe willen we dat dit werkt? We willen niet parseren en geen overbodige opdrachten uitvoeren. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b2e4343c51dab3ddb6919bf0f117c4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>In de praktijk laat TCP ons dit niet doen. Als de client bezig is met het verzenden van een verzoek, leest de database de verzoeken niet in de poging om ons antwoorden te geven. Uiteindelijk wacht de client op de database tot deze het verzoek leest, terwijl de database op de client wacht tot deze het antwoord leest. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/17a062c30ddd83cb890775ec1722044f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Daarom moet de client periodiek een synchronisatiepakket verzenden. Overbodige netwerkinteracties, onnodig verlies van tijd.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ae7a4f32e2949c1d0550da051937de02.jpg\" style=\"display:block;margin: 0 auto;\" \/>En hoe meer we ze toevoegen, hoe slechter het wordt. De driver is vrij pessimistisch en voegt ze redelijk vaak toe, ongeveer om de 200 rijen, afhankelijk van de rijgrootte, enzovoort. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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>Soms kan je slechts \u00e9\u00e9n rij aanpassen en alles met tien keer versnellen. Dat gebeurt. Waarom? Zoals gewoonlijk, werd ergens zo'n constante al gebruikt. En de waarde '128' betekende - batching niet gebruiken.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. 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>Het is goed dat dit niet in de offici\u00eble versie is beland. We hebben het ontdekt voordat we de release begonnen te maken. Alle waarden die ik noem, zijn gebaseerd op moderne versies. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28c82d9e11f6bdaf3cf62b49fc074d68.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Laten we meten. We meten eenvoudige InsertBatch. We meten herhaalde InsertBatch, dat wil zeggen hetzelfde, maar met veel values. Een slimme zet. Niet iedereen kan dat, maar het is een eenvoudige stap, veel eenvoudiger dan COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/72f7cf6c3b9d9175d3e5a6d5410fe209.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Je kunt COPY doen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2b0d8bbcc50f1293c9a8a1eb8eb70d2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En dit kan gedaan worden met structuren. Declareer het standaardtype User, geef een array door en INSERT rechtstreeks in de tabel. <\/p>\n<p><\/p>\n<p>Als je de link opent: pgjdbc\/ubenchmsrk\/InsertBatch.java, dan vind je deze code op GitHub. Je kunt specifiek bekijken welke queries daar worden gegenereerd. Het is niet echt belangrijk.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28dede211fe401286685ca62081453de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>We hebben het uitgevoerd. En het eerste wat we begrepen, is dat je batch-niet kunt negeren \u2013 dat is gewoon niet mogelijk. Alle batch-opties zijn gelijk aan nul, d. w. z. de uitvoeringstijd is praktisch nul vergeleken met een enkele uitvoering. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4ea68f712bbdeadd35f5baa4ddaeff33.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>We voegen gegevens toe. Het is een vrij eenvoudige tabel. Drie kolommen. En wat zien we hier? We zien dat al deze drie opties ongeveer vergelijkbaar zijn. En COPY is natuurlijk beter.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2686f1d7eea347a839ac23aef2a27e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dit is wanneer we in stukjes invoegen. Wanneer we zeiden dat \u00e9\u00e9n waarde VALUES, twee waarden VALUES, drie waarden VALUES zijn of dat we er 10 door elkaar hebben opgegeven. Dit is nu horizontaal. 1, 2, 4, 128. Je ziet dat Batch Insert, dat in het blauw is weergegeven, dit veel gemakkelijker maakt. D. w. z. wanneer je \u00e9\u00e9n voor \u00e9\u00e9n invoegt of zelfs wanneer je vier tegelijk invoegt, wordt het twee keer beter, gewoon omdat we iets meer in VALUES hebben gestopt. Minder EXECUTE-operaties.<\/p>\n<p><\/p>\n<p>COPY gebruiken voor kleine volumes is uiterst onvoordelig. Ik heb zelfs op de eerste twee niet getekend. Zij stijgen de lucht in, d. w. z. deze groene cijfers zijn voor COPY.<\/p>\n<p><\/p>\n<p>COPY moet worden gebruikt wanneer je gegevensvolume tenminste meer dan honderd regels is. De overhead voor het openen van deze verbinding is groot. En, eerlijk gezegd, heb ik hier niet verder in gegraven. Batch heb ik geoptimaliseerd, COPY niet. <\/p>\n<p><\/p>\n<p>Wat doen we nu verder? We hebben gemeten. We begrijpen dat we ofwel structuren moeten gebruiken, of een ingenieuze batch die meerdere waarden combineert. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL en JDBC persen het maximale eruit. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e02fa2574e2d1b678382db15064610d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Wat moeten we meenemen uit de presentatie van vandaag?<\/p>\n<p><\/p>\n<ul>\n<li>PreparedStatement is alles voor ons. Het geeft veel voor de prestaties. Het levert een grote emmer teers. <\/li>\n<li>En we moeten EXPLAIN ANALYZE 6 keer uitvoeren.<\/li>\n<li>En we moeten OFFSET 0 verdunnen, en trucs zoals +0 toepassen om het resterende percentage van onze problematische queries te corrigeren.<\/li>\n<\/ul>\n<p>Bron: <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.3 - 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\/nl\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\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\/nl\/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 en JDBC persen we er alles uit. Vladimir Sitnikov | ProHoster","description":"Ik nodig u uit om het verslag van de presentatie van begin 2016 van Vladimir Sitnikov \"PostgreSQL en JDBC - we persen alles eruit\" te bekijken","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","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\/nl\/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\/nl\/wp-json\/wp\/v2\/posts\/79893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=79893"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/79893\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media\/79894"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=79893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=79893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=79893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}