{"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\/sl\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","title":{"rendered":"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Predlagam, da se seznanite z razlago poro\u010dila Vladimirja Sitnikova iz za\u010detka leta 2016 z naslovom \"PostgreSQL in JDBC: iztisnemo vse sokove\"<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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 in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/030666abda53aa388b1cb1d0c46a7524.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dober dan! Moje ime je Vladimir Sitnikov. Delam 10 let v podjetju NetCracker. In predvsem se ukvarjam z zmogljivostjo. Vse, kar je povezano z Javom, vse, kar je povezano s SQL \u2013 to je tisto, kar imam rad. <\/p>\n<p><\/p>\n<p>Danes bom govoril o tem, s \u010dimer smo se sre\u010dali v podjetju, ko smo za\u010deli uporabljati PostgreSQL kot stre\u017enik podatkov. In ve\u010dinoma delamo z Javo. Toda to, kar bom danes predstavil, ni povezano samo z Javo. Kot je praksa pokazala, se to pojavi tudi v drugih jezikih. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b01a214d782c7e32797a6c6466457979.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Govorili bomo o:<\/p>\n<p><\/p>\n<ul>\n<li>izvleku podatkov. <\/li>\n<li>Shranjevanju podatkov. <\/li>\n<li>Pa tudi o zmogljivosti. <\/li>\n<li>In o podvodnih skalah, ki so tam skrite. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/57da0c6aa4bb62e1beb77160f5aee7e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Za\u010dnimo z enostavnim vpra\u0161anjem. Izbiramo eno vrstico iz tabele po primarnem klju\u010du. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/d5fcb1172aef402a87064498bf8a5218.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Baza se nahaja na istem gostiteljskem stre\u017eniku. In vse to traja 20 milisekund.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/103b7f9736b82a3313491b2f0d2a5824.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Teh 20 milisekund \u2013 to je zelo veliko. \u010ce imate 100 takih poizvedb, porabite \u010das v sekundi za obdelavo teh poizvedb, torej vr\u017eemo \u010das stran.<\/p>\n<p><\/p>\n<p>S tega ne maramo delati in gledamo, kaj nam baza ponuja. Baza nam ponuja dve mo\u017enosti za izvajanje poizvedb. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b467e86a0f8c4c32cea182fe27a28e6e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Prva mo\u017enost je preprosta poizvedba. Po \u010dem je dobra? Po tem, da jo vzamemo in po\u0161ljemo, in to je to. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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>Baza ima tudi raz\u0161irjeno poizvedbo, ki je bolj zapletena, vendar bolj funkcionalna. Lahko po\u0161ljete lo\u010deno poizvedbo za parsanje, izvajanje, povezovanje spremenljivk itd. <\/p>\n<p><\/p>\n<p>Super raz\u0161irjena poizvedba \u2013 to ni tema trenutnega poro\u010dila. Morda smo si od baze za\u017eeleli nekaj in obstaja seznam \u017eelja, ki je v nekem smislu oblikovan, torej to je tisto, kar \u017eelimo, vendar ni mogo\u010de zdaj in v bli\u017enji prihodnosti. Zato smo preprosto zapisali in bomo prosili glavne ljudi.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/19094729074fd28c5b9f236833a9a266.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tisto, kar lahko storimo, je preprosta poizvedba in raz\u0161irjena poizvedba.<\/p>\n<p><\/p>\n<p>Kaj je zna\u010dilno za vsak pristop? <\/p>\n<p><\/p>\n<p>Preprosto poizvedbo je dobro uporabiti za enkratno izvedbo. Enkrat izvedete in pozabite. In te\u017eava je v tem, da ne podpira binarnega formata podatkov, torej za nekatere visoko zmogljive sisteme ni primerno.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/062c0e45cefd91ece331a306a7651bde.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Raz\u0161irjena poizvedba omogo\u010da prihranek \u010dasa pri parsiranju. To smo storili in za\u010deli uporabljati. Zelo nam je pomagalo. Poleg prihranka pri parsiranju je tu tudi prihranek pri prenosu podatkov. Prenos podatkov v binarni obliki je bistveno bolj u\u010dinkovit. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6df83a2f3736568668cf9d74de5d9758.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Poglejmo prakso. Tako izgleda tipi\u010dna aplikacija. To je lahko Java, itd. <\/p>\n<p><\/p>\n<p>Ustvarili smo statement. Izvedli smo ukaz. Ustvarili smo close. Kje je tukaj napaka? Kje je problem? Ni te\u017eav. Tako pi\u0161e v vseh knjigah. Tako je treba pisati. \u010ce \u017eelite najve\u010djo zmogljivost, pi\u0161ite tako. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6923293946dec45b3fd508235728ab95.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Toda praksa je pokazala, da to ne deluje. Zakaj? Zaradi tega, ker imamo metodo 'close'. In ko to naredimo, z vidika baze podatkov to deluje kot delo kadilca z bazo podatkov. Rekli smo 'PARSE EXECUTE DEALLOCATE'.<\/p>\n<p><\/p>\n<p>Zakaj te nepotrebne ustvaritve in nalaganje statements? Nih\u010de jih ne potrebuje. Obi\u010dajno pri PreparedStatement tako pride, ko jih zapremo, zaprejo vse v bazi podatkov. To ni to, kar \u017eelimo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5a357a209e414024c437d042f600f251.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u017delimo, da delamo z bazo kot zdravi ljudje. Enkrat vzamemo in pripravimo na\u0161 statement, nato ga izvajamo ve\u010dkrat. V resnici ve\u010dkrat \u2013 to pomeni enkrat za vse \u017eivljenje aplikacije zaparseriti. In na razli\u010dnih REST-ih uporabljamo isti ID statement. To je na\u0161 cilj. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ac4aed702a624ad9f9addc4362daf760.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kako to dose\u010di? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0f101d890d1a2af8e99f8a3a8a06fd5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Zelo preprosto \u2013 ne smemo zapirati statements. Pi\u0161emo tako: 'prepare' 'execute'. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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 in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/724646bfc55b5e2b611b1584ca8ba6aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u010ce to za\u017eenemo, je jasno, da se lahko kje kaj preplavi. \u010ce ni jasno, lahko to tudi izmerimo. Vzamemo in napi\u0161emo benchmark, v katerem bo tak preprost na\u010din. Ustvarimo statement. Za\u017eenemo na neki razli\u010dici gonilnika in ugotovimo, da se dokaj hitro sesuje z izgubo celotne pomnilni\u0161ke kapacitete, ki smo jo imeli. <\/p>\n<p><\/p>\n<p>Jasno je, da so tak\u0161ne napake enostavno popravljive. O tem ne bom govoril. Toda povedal bom, da v novi razli\u010dici deluje veliko hitreje. Metoda je neumna, a kljub temu. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b232a6205e708c70f52be0024bbe9980.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kako pravilno delovati? Kaj moramo storiti?<\/p>\n<p><\/p>\n<p>V resnici aplikacije vedno zaprejo statements. V vseh knjigah pi\u0161ejo, naj jih zaprejo, sicer bo pri\u0161lo do uhajanja pomnilnika. <\/p>\n<p><\/p>\n<p>In PostgreSQL ne more ke\u0161irati poizvedb. Vsaka seja mora sama ustvariti ta ke\u0161. <\/p>\n<p><\/p>\n<p>In tudi ne \u017eelimo izgubljati \u010dasa za parsanje. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/85b9574938aa6e6bf59c956e3728bdc3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>In kot ponavadi imamo dve mo\u017enosti. <\/p>\n<p><\/p>\n<p>Prva opcija \u2013 uzimamo i ka\u017eemo da sve obavijamo u PgSQL. Tamo postoji ke\u0161. On sve ke\u0161ira. Bi\u0107e odli\u010dno. Pogledali smo to. Imamo 100500 zahteva. Ne radi. Ne sla\u017eemo se da se zahtevi prebacuju u procedure ru\u010dno. Ne-ne. <\/p>\n<p><\/p>\n<p>Imamo drugu opciju \u2013 uzeti i sami napraviti. Otvaramo izvorne kodove, po\u010dinjemo da radimo. Radimo, radimo. Ispostavilo se da to nije tako te\u0161ko uraditi. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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>To se pojavilo u avgustu 2015. Sada ve\u0107 postoji modernija verzija. I sve je odli\u010dno. Radi toliko dobro da ne menjamo ni\u0161ta u aplikaciji. \u010cak smo prestali da razmi\u0161ljamo u pravcu PgSQL, tj. to nam je bilo dovoljno da sve tro\u0161kove skoro svedemo na nulu. <\/p>\n<p><\/p>\n<p>Shodno tome, Server-prepared statements se aktivira pri petom izvr\u0161enju kako ne bismo tro\u0161ili memoriju u bazi podataka za svaku jednokratnu upit. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8ee95e71f92187941989ad0c18ece0c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mo\u017eete pitati \u2013 gde su brojevi? \u0160ta dobijate? I ovde ne mogu da dam brojeve, jer su za svaki upit razli\u010diti.<\/p>\n<p><\/p>\n<p>Na\u0161i zahtevi su bili takvi da smo na OLTP upitima tro\u0161ili oko 20 milisekundi na parsiranje. Tamo je bilo 0,5 milisekundi na izvr\u0161enje, 20 milisekundi na parsiranje. Upit \u2013 10 KiB teksta, 170 redova plana. To je OLTP upit. Pita 1, 5, 10 redova, ponekad vi\u0161e. <\/p>\n<p><\/p>\n<p>Ali nismo \u017eeleli da tro\u0161imo 20 milisekundi. Sve smo sveli na nulu. Sve je odli\u010dno. <\/p>\n<p><\/p>\n<p>\u0160ta mo\u017eete izvu\u0107i iz ovoga? Ako imate Java, uzimate modernu verziju drajvera i radujete se. <\/p>\n<p><\/p>\n<p>Ako imate neki drugi jezik, razmislite \u2013 mo\u017eda vam je to tako\u0111e potrebno? Jer sa stanovi\u0161ta krajnjeg jezika, na primer, ako je PL 8 ili imate LibPQ, nije vam o\u010digledno da tro\u0161ite vreme ne na izvr\u0161enje, ve\u0107 na parsiranje i to treba proveriti. Kako? Sve je besplatno. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fda6b1c1b126cb85c970e42335e1dc24.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Osim toga, postoje gre\u0161ke, neke osobine. I o tome \u0107emo upravo govoriti. Ve\u0107ina \u0107e biti o industrijskoj arheologiji, o onome \u0161to smo prona\u0161li, na \u0161ta smo nai\u0161li. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9a3b383f83c5e227cd02952c5825b64f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ako se upit generi\u0161e dinami\u010dki. To se de\u0161ava. Neko spaja stringove, \u0161to rezultira SQL upitom.<\/p>\n<p><\/p>\n<p>\u0160ta je lo\u0161e u tome? Lo\u0161e je \u0161to svaki put dobijamo druga\u010diji string.<\/p>\n<p><\/p>\n<p>Tudi ta razli\u010dna vrstica mora znova izra\u010dunati hashCode. To je resni\u010dno naloga za CPU \u2013 najti dolg besedilni zahtevek v tudi obstoje\u010dem hash-u ni tako preprosto. Zato je preprost zaklju\u010dek \u2013 ne ustvarjajte zahtevkov. Shranite jih v eno spremenljivko. In u\u017eivajte.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/bcd4f729204cecdb572a98f357bcc33f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Naslednja te\u017eava. Tipi podatkov so pomembni. Obstajajo ORM, ki pravijo, da ni pomembno, kak\u0161en NULL, naj bo kakr\u0161en koli. \u010ce je Int, potem re\u010demo setInt. In \u010de je NULL, naj bo vedno VARCHAR. In kak\u0161na razlika je na koncu kak\u0161en tam NULL? Baza podatkov bo vse razumela sama. In ta slika ne deluje. <\/p>\n<p><\/p>\n<p>V praksi bazi podatkov ni vseeno. <strong>\u010ce ste prvi\u010d rekli, da imate \u0161tevilko, drugi\u010d pa rekli, da je to VARCHAR, potem ni mogo\u010de ponovno uporabiti Server-prepared statements. V takem primeru je treba na\u0161 statement znova ustvariti.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/552d9c2e25cf9abbdfef12c98d027740.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u010ce izvajate isti zahtevek, pazite, da se tipi podatkov v stolpcu ne me\u0161ajo. Treba je paziti na NULL. To je pogosta napaka, ki smo jo imeli po tem, ko smo za\u010deli uporabljati PreparedStatements.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5d73c8f5dfa281c3bda962fc3e5edd84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dobro, vklju\u010dili smo. Morda smo vzeli gonilnik. In zmogljivost je padla. Vse je postalo slabo. <\/p>\n<p><\/p>\n<p>Kako se to zgodi? Je to bug ali funkcija? Na \u017ealost ni bilo mogo\u010de razumeti \u2013 ali je to bug ali funkcija. Toda obstaja povsem preprost scenarij za ponavljanje te te\u017eave. Presenetljivo nas je napadla. In gre za poizvedbo iz ene same tabele. Takih zahtevkov smo imeli ve\u010d. Obi\u010dajno so vklju\u010devali dve ali tri tabele, a obstaja tak\u0161en scenarij ponovitve. Vzemite na va\u0161i bazi katere koli razli\u010dice in ga ponovite.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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>Smisel je v tem, da imamo dva stolpca, od katerih je vsak indeksiran. V enem stolpcu je milijon vrstic z vrednostjo NULL. V drugem stolpcu pa je le 20 vrstic. Ko izvajamo brez povezanih spremenljivk, vse dobro deluje. <\/p>\n<p><\/p>\n<p>\u010ce za\u010dnemo izvajati s povezanimi spremenljivkami, tj. izvajamo znak \u201e?\u201c ali \u201e$1\u201c za na\u0161 zahtevek, kaj na koncu dobimo?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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>Prvo izvajanje \u2013 kot je treba. Drugo \u2013 malo hitreje. Nekaj se je shranilo v predpomnilnik. Tretje-\u010detrto-peto. Potem pa bum \u2013 in nekako tako. In najhuje je, da se to zgodi pri \u0161estem izvajanju. Kdo je vedel, da je treba izvesti prav \u0161est izvajanj, da bi ugotovili, kak\u0161en je dejansko na\u010drt izvedbe?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/893c955bc1e2e15a6986690e516f72a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kdo je kriv? Kaj se je zgodilo? Baza podatkov vsebuje optimizacijo. In je nekako optimizirana za splo\u0161ni primer. In tako se, od dolo\u010dene to\u010dke naprej, preklopi na splo\u0161ni na\u010drt, ki je, \u017eal, lahko druga\u010den. Lahko se izka\u017ee, da je enak, lahko pa tudi druga\u010den. Obstaja neka mejna vrednost, ki vodi do tega vedenja. <\/p>\n<p><\/p>\n<p>Kaj lahko storimo glede tega? Tukaj je seveda te\u017eje karkoli predvidevati. Obstaja enostavna re\u0161itev, ki jo uporabljamo. To je +0, OFFSET 0. Verjetno poznate tak\u0161ne re\u0161itve. Enostavno vzamemo in v poizvedbo dodamo \u201e+0\u201c in vse je v redu. To poka\u017eem kasneje. <\/p>\n<p><\/p>\n<p>Obstaja \u0161e ena mo\u017enost - bolj skrbno preverjanje na\u010drtov. Razvijalec mora ne samo napisati poizvedbo, temve\u010d tudi 6-krat re\u010di \u201eexplain analyze\u201c. \u010ce 5-krat, potem ne bo ustrezalo. <\/p>\n<p><\/p>\n<p>In \u0161e tretja mo\u017enost - poslati e-po\u0161to na pgsql-hackers. Napisal sem, vendar \u0161e vedno ni jasno - ali je to napaka ali lastnost.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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>Medtem ko razmi\u0161ljamo - ali je to napaka ali lastnost, popravimo. Vzamemo na\u0161o poizvedbo in dodamo \u201e+0\u201c. Vse je v redu. Dva znaka in sploh ni treba razmi\u0161ljati, kako in kaj. Zelo preprosto. Preprosto smo bazi podatkov prepovedali uporabo indeksa za to kolono. Nimamo indeksa za kolono \u201e+0\u201c in vse, baza podatkov ne uporablja indeksa, vse je v redu. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5261d80d084786a15b9764f6367014cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>To je pravilo 6-ih pojasnil. Zdaj je v trenutnih razli\u010dicah potrebno narediti 6-krat, \u010de imate povezane spremenljivke. \u010ce nimate povezanih spremenljivk, potem lahko to storimo tako. In tako na koncu ta poizvedba pade. Zadeva ni zapletena.<\/p>\n<p><\/p>\n<p>Zdi se, da koliko lahko? Tukaj napaka, tam napaka. Realno napaka povsod. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/674dc7e7b4624baa5c79eee9e1e89db0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Poglejmo \u0161e eno stvar. Na primer, imamo dve shemi. Shema A z tabelo Y in shema B z tabelo Y. Poizvedba - izberite podatke iz tabele. Kaj se nam pri tem zgodi? Imeli bomo napako. Imeli bomo vse zgoraj navedeno. Pravilo je to - napaka povsod, imeli bomo vse zgoraj navedeno.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dd6f544bb9e930c39e36523c9afe6003.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Zdaj vpra\u0161anje: \u201eZakaj?\u201c. Zdi se, da obstaja dokumentacija, da, \u010de imamo shemo, obstaja spremenljivka \u201esearch_path\u201c, ki pove, kje iskati tabelo. Zdi se, da spremenljivka obstaja.<\/p>\n<p><\/p>\n<p>Kak\u0161na je te\u017eava? Te\u017eava je v tem, da server-prepared statements ne domnevajo, da lahko nekdo spremeni search_path. Ta vrednost ostane nekako konstantna za bazo podatkov. In nekateri deli morda ne prevzamejo novih vrednosti. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f738301606d84d72bfa7cc5b568c0df8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Seveda, to je odvisno od razli\u010dice, na kateri preizku\u0161ate. Odvisno je tudi od tega, kako resno se va\u0161i podatkovni nizi razlikujejo. Razli\u010dica 9.1 bo preprosto izvedla stare poizvedbe. Novej\u0161e razli\u010dice lahko opazijo prevaro in povedo, da imate napako.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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 + stre\u017eni\u0161ki pripravljeni stavki =<br \/>\npredpomnjeni na\u010drt ne sme spremeniti vrste rezultata<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Kako to ozdraviti? Obstaja preprost recept \u2013 ne delajte tako. Ne spreminjajte search_path med delom aplikacije. \u010ce ga \u017ee spremenite, je bolje ustvariti novo povezavo.<\/p>\n<p><\/p>\n<p>Lahko se pogovarjamo, t.j. odpreti, razpravljati, dodati. Morda bomo prepri\u010dali razvijalce podatkovne baze, da v primeru, ko nekdo spremeni vrednost, baza podatkov mora obvestiti uporabnika: 'Oglejte si, va\u0161a vrednost se je posodobila. Morda bi bilo potrebno ponastaviti stavke, re-create?' Zdaj se baza podatkov obna\u0161a skrito in ne obve\u0161\u010da o spremembah v stavkih. <\/p>\n<p><\/p>\n<p>In \u0161e enkrat poudarjam \u2013 to ni tipi\u010dno za Javo. Enako bomo videli v PL\/pgSQL enakovredno. A tam se bo reproduciralo.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a4e7b201d0c0aa4a0092d2b6ff152df7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Poskusimo \u0161e enkrat izbrati podatke. Izbiramo. Imamo tabelo z milijonom vrstic. Vsaka vrstica ima en kilobajt. Pribli\u017eno gigabajt podatkov. In imamo delovni pomnilnik v Java stroju 128 megabajtov. <\/p>\n<p><\/p>\n<p>Kot obi\u010dajno, kot priporo\u010dajo vse knjige, uporabljamo procesiranje tokov. T.j. odpreti moramo resultSet in brati podatke postopoma. Bo to delovalo? Ali bomo presegli pomnilnik? Bo bral postopoma? Poglejmo v bazo, poglejmo v Postgres. Ne verjamemo. Bomo naleteli na OutOFMemory? Kdo je do\u017eivel OutOfMemory? Kdo je uspel popraviti po tem? Nekdo je uspel popraviti. <\/p>\n<p><\/p>\n<p>\u010ce imate milijon vrstic, ne morete kar tako izbirati. Obvezno je treba uporabiti OFFSET\/LIMIT. Kdo se strinja s to mo\u017enostjo? In kdo se ve\u017ee na mo\u017enost, da je treba igrati z autoCommit? <\/p>\n<p><\/p>\n<p>Tukaj se obi\u010dajno izka\u017ee, da je najbolj nepri\u010dakovana mo\u017enost pravilna. In \u010de nenadoma izklopite autoCommit, vam bo to pomagalo. Zakaj? O tem znanost ne ve. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2e5d9d2a8450a9069155de86a8ec387a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Toda privzeto vsi odjemalci, ki se povezujejo z bazo podatkov Postgres, izberejo podatke v celoti. PgJDBC v tem smislu ni izjema, izbere vse vrstice.<\/p>\n<p><\/p>\n<p>Obstaja variacija na temo FetchSize, t.j. na ravni posameznega stavka lahko poveste, da naj izbere podatke po 10, 50. Toda to ne deluje, dokler ne izklopite autoCommit. Ko izklopite autoCommit \u2013 za\u010dne delovati. <\/p>\n<p><\/p>\n<p>Toda hoja secciones por el c\u00f3digo y establece setFetchSize en todos lados es inc\u00f3modo. As\u00ed que hemos creado una configuraci\u00f3n que establece un valor predeterminado para toda la conexi\u00f3n.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c9ac8e483dc6bfdbbc300972ee1ab1e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ya lo hemos dicho. Hemos configurado el par\u00e1metro. \u00bfY qu\u00e9 hemos logrado? Si seleccionamos un n\u00famero peque\u00f1o, por ejemplo, seleccionando 10 filas, tenemos sobrecargas bastante grandes. Por lo tanto, deber\u00edamos establecer este valor en alrededor de cien. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/073e7a4af63688396eefe332ba8261d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En ideal, claro, aprender a limitar a\u00fan en bytes, pero la receta es la siguiente: establecemos defaultRowFetchSize a m\u00e1s de cien y estamos felices. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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. La inserci\u00f3n es m\u00e1s simple, hay diferentes opciones. Por ejemplo, INSERT, VALUES. Esta es una buena opci\u00f3n. Tambi\u00e9n se puede decir \u2018INSERT SELECT\u2019. En la pr\u00e1ctica, es lo mismo. No hay diferencia en el rendimiento. <\/p>\n<p><\/p>\n<p>Los libros dicen que se debe realizar una declaraci\u00f3n de BATCH, y los libros 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 in JDBC iztisnemo vse sokove. 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 nuevamente varios descubrimientos interesantes. \u00bfC\u00f3mo queremos que funcione? Queremos no analizar y no ejecutar comandos innecesarios. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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, mientras que la base de datos espera al cliente a que lea la respuesta. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/17a062c30ddd83cb890775ec1722044f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Por lo tanto, 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 in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ae7a4f32e2949c1d0550da051937de02.jpg\" style=\"display:block;margin: 0 auto;\" \/>Y cuanto m\u00e1s los 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 in JDBC iztisnemo vse sokove. 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, puedes corregir solo una l\u00ednea y todo se acelera diez veces. Eso sucede. \u00bfPor qu\u00e9? Como siempre, una constante ya fue utilizada en alg\u00fan lugar. Y el valor \u2018128\u2019 significaba no utilizar batching.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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. Se detect\u00f3 antes de comenzar a lanzar la versi\u00f3n. Todos los valores que menciono se basan en versiones modernas. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28c82d9e11f6bdaf3cf62b49fc074d68.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Midamos. Medimos InsertBatch simple. Medimos InsertBatch m\u00faltiple, es decir, lo mismo, pero con muchos valores. Un movimiento astuto. No todos pueden hacerlo, pero es un movimiento simple, mucho m\u00e1s f\u00e1cil que COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. 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 in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2b0d8bbcc50f1293c9a8a1eb8eb70d2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>In structures, this can be done. Declare the User default type, pass an array and INSERT directly into the table. <\/p>\n<p><\/p>\n<p>If you open the link: pgjdbc\/ubenchmsrk\/InsertBatch.java, this code is available on GitHub. You can specifically see what queries are generated there. It's not essential.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28dede211fe401286685ca62081453de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>We ran it. And the first thing we realized was that not using batch is simply not an option. All batching alternatives yield nearly zero time, meaning execution time is practically zero compared to a single execution. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4ea68f712bbdeadd35f5baa4ddaeff33.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>We are inserting data. It's a quite simple table with three columns. And what do we see here? We see that all three options are roughly comparable. And COPY is certainly better.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2686f1d7eea347a839ac23aef2a27e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>This is when we insert in chunks. When we said one value VALUES, two values VALUES, three values VALUES, or when we indicated 10 separated by commas. This is just horizontally now. 1, 2, 4, 128. It's clear that the Batch Insert, which is shown in blue, benefits significantly from this. So when you insert one at a time or even when you insert four, it gets twice as better, simply because we packed a bit more into VALUES. Fewer EXECUTE operations.<\/p>\n<p><\/p>\n<p>Using COPY for small volumes is extremely unpromising. I didn't even draw the first two. They go to infinity, meaning those green numbers for COPY.<\/p>\n<p><\/p>\n<p>COPY should be used when you have at least more than a hundred rows of data. The overhead of opening this connection is significant. And, to be honest, I haven't dug into this direction. I've optimized the batch, but not COPY. <\/p>\n<p><\/p>\n<p>What do we do next? We measured. We understand that we need to use either structures or a clever batch that combines several values. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL in JDBC iztisnemo vse sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e02fa2574e2d1b678382db15064610d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>What should be taken away from today's presentation?<\/p>\n<p><\/p>\n<ul>\n<li>PreparedStatement is everything for us. It gives a lot for performance. However, it gives a large barrel of tar. <\/li>\n<li>And we need to do EXPLAIN ANALYZE 6 times.<\/li>\n<li>And we need to dilute OFFSET 0, and tricks like +0 to correct the remaining percentage of our problematic queries.<\/li>\n<\/ul>\n<p>Izvor: <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.4 - 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\/sl\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sl_SI\" \/>\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\/sl\/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\udd47We are squeezing all the juice from PostgreSQL and JDBC. Vladimir Sitnikov | ProHoster","description":"Predlagam, da se spoznate z razlago poro\u010dila iz za\u010detka leta 2016 Vladimira Sitnikova \"PostgreSQL in JDBC - iztisnemo vse sokove\"","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sl_SI","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\/sl\/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\/sl\/wp-json\/wp\/v2\/posts\/79893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/comments?post=79893"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/79893\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media\/79894"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=79893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=79893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=79893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}