{"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\/hr\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","title":{"rendered":"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Predla\u017eem da se upoznate s transkriptom izlaganja Vladimira Sitnikova iz po\u010detka 2016. godine \"PostgreSQL i JDBC: izvla\u010dimo maksimum\"<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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 i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/030666abda53aa388b1cb1d0c46a7524.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dobar dan! Zovem se Vladimir Sitnikov. Radim 10 godina u kompaniji NetCracker. Uglavnom se bavim performansama. Sve \u0161to je povezano s Javom, sve \u0161to je povezano s SQL-om - to je ono \u0161to volim. <\/p>\n<p><\/p>\n<p>Danas \u0107u govoriti o tome s \u010dime smo se susreli u kompaniji kada smo po\u010deli koristiti PostgreSQL kao server za baze podataka. Uglavnom radimo s Javom. No, ono \u0161to \u0107u danas ispri\u010dati, odnosi se ne samo na Javu. Kao \u0161to praksa pokazuje, to se javlja i u drugim jezicima. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b01a214d782c7e32797a6c6466457979.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Govorit \u0107emo o:<\/p>\n<p><\/p>\n<ul>\n<li>prikupljanju podataka. <\/li>\n<li>O spremanju podataka. <\/li>\n<li>I o performansama. <\/li>\n<li>I o zamkama koje se tu kriju. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/57da0c6aa4bb62e1beb77160f5aee7e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Zapo\u010dnimo s jednostavnim pitanjem. Biramo jedan redak iz tablice prema primarnom klju\u010du. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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 nalazi na istom hostu. I sve to traje 20 milisekundi.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/103b7f9736b82a3313491b2f0d2a5824.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ovih 20 milisekundi - to je jako puno. Ako imate 100 takvih upita, gubite vrijeme u sekundi kako biste obradili te upite, tj. tro\u0161ite vrijeme uzalud.<\/p>\n<p><\/p>\n<p>Ne volimo to raditi i gledamo \u0161to nam baza nudi za to. Baza nam nudi dva na\u010dina izvr\u0161enja upita. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b467e86a0f8c4c32cea182fe27a28e6e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Prvi na\u010din - to je jednostavni upit. \u0160to je dobro u njemu? Uzimamo ga i \u0161aljemo, i ni\u0161ta vi\u0161e. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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 tako\u0111er ima pro\u0161ireni upit, koji je slo\u017eeniji, ali funkcionalniji. Mo\u017eete posebno slati upite za parsiranje, izvr\u0161avanje, povezivanje varijabli itd. <\/p>\n<p><\/p>\n<p>Super pro\u0161ireni upit - to je ono \u0161to ne\u0107emo pokrivati u trenutnom izlaganju. Mo\u017eda imamo ne\u0161to \u0161to \u017eelimo od baze podataka i postoji popis \u017eelja koji je oblikovan na neki na\u010din, tj. to je ono \u0161to \u017eelimo, ali trenutno nije mogu\u0107e i ne\u0107e biti sljede\u0107e godine. Zato smo to jednostavno zabilje\u017eili i idemo pitati glavne osobe.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/19094729074fd28c5b9f236833a9a266.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A ono \u0161to mo\u017eemo napraviti jest - to su jednostavan upit i pro\u0161ireni upit.<\/p>\n<p><\/p>\n<p>Koja je posebnost svakog pristupa? <\/p>\n<p><\/p>\n<p>Jednostavan upit je dobro koristiti za jednokratno izvr\u0161avanje. Jedan puta izvr\u0161ite i zaboravite. A problem je u tome \u0161to ne podr\u017eava binarni format podataka, tj. za neke visoko performantne sustave nije prikladan.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/062c0e45cefd91ece331a306a7651bde.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Extended query \u2013 omogu\u0107uje u\u0161tedu vremena prilikom parsiranja. To je ono \u0161to smo u\u010dinili i po\u010deli koristiti. Ovo nam je iznimno pomoglo. Tu nije samo u\u0161teda na parsiranju. U\u0161teda je i u prijenosu podataka. Prijenos podataka u binarnom formatu je znatno efikasniji. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6df83a2f3736568668cf9d74de5d9758.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pre\u0111imo na praksu. Ovako izgleda tipi\u010dna aplikacija. To mo\u017ee biti Java itd. <\/p>\n<p><\/p>\n<p>Stvorili smo statement. Izvr\u0161ili smo naredbu. Stvorili smo close. Gdje je ovdje gre\u0161ka? Koji je problem? Nema problema. Tako pi\u0161e u svim knjigama. Tako treba pisati. Ako \u017eelite maksimalnu izvedbu, pi\u0161ite tako. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6923293946dec45b3fd508235728ab95.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No praksa je pokazala da to ne funkcionira. Za\u0161to? Zato \u0161to imamo metodu \u201eclose\u201c. I kada to radimo, iz perspektive baze podataka izgleda \u2013 to je kao rad pu\u0161a\u010da s bazom podataka. Rekli smo \u201ePARSE EXECUTE DEALLOCATE\u201c.<\/p>\n<p><\/p>\n<p>Za\u0161to ova suvi\u0161na stvaranja i u\u010ditavanje statements? Nikome nisu potrebni. No obi\u010dno u PreparedStatement tako i bude, kada ih zatvaramo, zatvaraju sve u bazi podataka. To nije ono \u0161to \u017eelimo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5a357a209e414024c437d042f600f251.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u017delimo, kao zdravi ljudi, raditi s bazom. Jednom smo uzeli i pripremili na\u0161 statement, a zatim ga izvr\u0161avamo mnogo puta. U stvarnosti mnogo puta \u2013 to je jednom za cijeli \u017eivot aplikacije parsirano. I na razli\u010ditim REST-ima koristimo isti id statementa. To je na\u0161 cilj. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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 mo\u017eemo posti\u0107i? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0f101d890d1a2af8e99f8a3a8a06fd5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vrlo jednostavno \u2013 ne trebamo zatvarati statements. Pi\u0161emo ovako: \u201eprepare\u201c \u201eexecute\u201c. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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 i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/724646bfc55b5e2b611b1584ca8ba6aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ako ovo pokrenemo, jasno je da \u0107e nam negdje ne\u0161to preplaviti. Ako nije jasno, mo\u017eemo izmjeriti. Uzmi \u0107emo i napisati benchmark, u kojem je takva jednostavna metoda. Stvaramo statement. Pokre\u0107emo na nekoj verziji drajvera i dobijamo da se prili\u010dno brzo uru\u0161ava gubitkom cijele memorije koju smo imali. <\/p>\n<p><\/p>\n<p>Jasno je da se takve gre\u0161ke lako ispravljaju. Ne\u0107u o njima govoriti. Ali re\u0107i \u0107u da u novoj verziji radi puno br\u017ee. Metoda je glupa, ali unato\u010d tome. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b232a6205e708c70f52be0024bbe9980.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kako raditi ispravno? \u0160to trebamo u\u010diniti za to?<\/p>\n<p><\/p>\n<p>U stvarnosti, aplikacije uvijek zatvaraju statements. U svim knjigama pi\u0161e da ih treba zatvoriti, ina\u010de \u0107e do\u0107i do curenja memorije. <\/p>\n<p><\/p>\n<p>I PostgreSQL ne mo\u017ee ke\u0161irati upite. Svaka sesija treba sama slabiti ovaj ke\u0161. <\/p>\n<p><\/p>\n<p>I ne \u017eelimo tro\u0161iti vrijeme na parsiranje. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/85b9574938aa6e6bf59c956e3728bdc3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A kao i obi\u010dno, imamo dva na\u010dina. <\/p>\n<p><\/p>\n<p>Prva opcija je da uzmemo i ka\u017eemo, da sve obavijemo u PgSQL. Tamo postoji ke\u0161. On sve ke\u0161ira. Iza\u0107i \u0107e sjajno. To smo pogledali. Imamo 100500 upita. Ne radi. Nismo saglasni s tim da ru\u010dno pretvaramo upite u procedure. Ne-ne. <\/p>\n<p><\/p>\n<p>Imamo drugu opciju \u2013 uzeti i sami napraviti. Otvaramo izvorne kodove, po\u010dinjemo raditi. Radimo-radimo. Ispostavilo se da to nije tako te\u0161ko napraviti. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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. godine. Sada je ve\u0107 dostupna modernija verzija. I sve je sjajno. Radi toliko dobro, da ni\u0161ta ne menjamo u aplikaciji. \u010cak smo prestali razmi\u0161ljati u pravcu PgSQL, tj. to nam je bilo sasvim dovoljno da smanjimo sve administrativne tro\u0161kove prakti\u010dno na nulu. <\/p>\n<p><\/p>\n<p>Samim tim, Server-pripremljene izjave aktiviraju se pri 5. izvr\u0161enju kako ne bismo tro\u0161ili memoriju u bazi podataka na svaki jednokratni upit. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8ee95e71f92187941989ad0c18ece0c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mo\u017ee se pitati \u2013 gde su brojevi? \u0160ta dobijate? I ovde ne\u0107u dati brojeve, jer svaki upit ima svoje.<\/p>\n<p><\/p>\n<p>Imali smo upite takve da smo na OLTP-upitima tro\u0161ili oko 20 milisekundi na parsiranje. Bilo je 0,5 milisekundi za izvr\u0161enje, 20 milisekundi za parsiranje. Upit \u2013 10 KiB teksta, 170 redova plana. To je OLTP upit. Tra\u017ei 1, 5, 10 redova, ponekad vi\u0161e. <\/p>\n<p><\/p>\n<p>Ali nismo \u017eeleli tro\u0161iti 20 milisekundi. Sveli smo to na 0. Sve je sjajno. <\/p>\n<p><\/p>\n<p>\u0160ta mo\u017eete izvu\u0107i iz ovoga? Ako imate Javu, uzmite modernu verziju drajvera i radujte se. <\/p>\n<p><\/p>\n<p>Ako imate neki drugi jezik, razmislite \u2013 mo\u017eda \u0107e vam to tako\u0111e biti potrebno? Zato \u0161to s aspekta krajnjeg jezika, na primer, ako je PL 8 ili imate LibPQ, nije vam o\u010digledno da tro\u0161ite vreme ne na izvr\u0161enje, nego na parsiranje i to vredi proveriti. Kako? Sve je besplatno. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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 posebnosti. I o njima \u0107emo sada govoriti. Ve\u0107i deo \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 i JDBC - istiskujemo sve 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, nastaje SQL-upit.<\/p>\n<p><\/p>\n<p>\u0160ta je lo\u0161e u tome? Lo\u0161e je to \u0161to svaki put na kraju dobijamo druga\u010diji string.<\/p>\n<p><\/p>\n<p>I ova razli\u010dita linija treba ponovno izra\u010dunati hashCode. To je doista CPU zadatak \u2013 prona\u0107i dugi tekst upita nije lako ni u postoje\u0107em hash-u. Stoga je jednostavna poruka \u2013 nemojte generirati upite. Pohranite ih u jednu varijablu. I u\u017eivajte.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/bcd4f729204cecdb572a98f357bcc33f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Sljede\u0107i problem. Tipovi podataka su va\u017eni. Postoje ORM alati koji ka\u017eu da nije va\u017eno koji NULL, neka bude neki. Ako je Int, ka\u017eemo setInt. A ako je NULL, neka uvijek bude VARCHAR. I koja je u kona\u010dnici razlika koji je tu NULL? Baza podataka \u0107e sve razumjeti sama. I takva slika ne funkcionira. <\/p>\n<p><\/p>\n<p>U praksi bazi podataka nije svejedno. <strong>Ako prvi put ka\u017eete da imate broj, a drugi put ka\u017eete da je to VARCHAR, nemogu\u0107e je ponovno koristiti unaprijed pripremljene izjave na serveru. U tom slu\u010daju morate ponovno kreirati na\u0161u izjavu.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/552d9c2e25cf9abbdfef12c98d027740.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ako izvr\u0161avate isti upit, pazite da se tipovi podataka u va\u0161im kolonama ne pomije\u0161aju. Treba paziti na NULL. To je \u010desta pogre\u0161ka koja nam se dogodila nakon \u0161to smo po\u010deli koristiti PreparedStatements.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5d73c8f5dfa281c3bda962fc3e5edd84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dobro, uklju\u010deno. Uzeli smo, mo\u017eda, drajver. I performanse su opale. Sve je postalo lo\u0161e. <\/p>\n<p><\/p>\n<p>Kako se to doga\u0111a? Je li to gre\u0161ka ili zna\u010dajka? Na\u017ealost, nismo uspjeli shvatiti \u2013 je li to gre\u0161ka ili zna\u010dajka. Ali postoji sasvim jednostavan scenarij za reprodukciju ovog problema. Potpuno nas je iznenadio. Sastoji se od selekcije iz doslovno jedne tablice. Imali smo, naravno, vi\u0161e takvih upita. Obi\u010dno su uklju\u010divali dvije do tri tablice, ali ima i ovakav scenarij reprodukcije. Uzmite na va\u0161oj bazi bilo koju verziju i reproducirajte.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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>Bit je u tome da imamo dvije kolone, od kojih je svaka indeksirana. U jednoj koloni ima milion redaka s vrijedno\u0161\u0107u NULL. A u drugoj koloni ima samo 20 redaka. Kada izvr\u0161avamo bez povezanih varijabli, sve dobro funkcionira. <\/p>\n<p><\/p>\n<p>Ako po\u010dnemo izvr\u0161avati s povezanim varijablama, tj. izvr\u0161avamo znak \u00ab?\u00bb ili \u00ab$1\u00bb za na\u0161 upit, \u0161to na kraju dobivamo?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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 izvo\u0111enje \u2013 kako se o\u010dekuje. Drugo \u2013 malo br\u017ee. Ne\u0161to je pohranjeno u cache. Tre\u0107e-\u010detvrto-peto. Onda bum \u2013 i tako. I najgore je \u0161to se to doga\u0111a pri \u0161estom izvo\u0111enju. Tko je znao da treba napraviti to\u010dno \u0161est izvo\u0111enja da bi se shvatilo koji je pravi plan izvr\u0161enja?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/893c955bc1e2e15a6986690e516f72a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tko je kriv? \u0160to se dogodilo? Baza podataka sadr\u017ei optimizaciju. I ona je nekako optimizirana za generi\u010dki slu\u010daj. Tako da, po\u010dev\u0161i od nekog trenutka, prelazi na generi\u010dki plan, koji, na\u017ealost, mo\u017ee biti druga\u010diji. Mo\u017ee biti jednak, ali mo\u017ee i biti razli\u010dit. Tu postoji neki prag koji dovodi do takvog pona\u0161anja. <\/p>\n<p><\/p>\n<p>\u0160to mo\u017eemo u\u010diniti s tim? Tu je, naravno, malo te\u017ee ne\u0161to pretpostaviti. Postoji jednostavno rje\u0161enje koje koristimo. To je +0, OFFSET 0. Sigurno poznajete takva rje\u0161enja. Jednostavno uzmemo i u upit dodamo \u00ab+0\u00bb i sve je u redu. Pokazat \u0107u kasnije. <\/p>\n<p><\/p>\n<p>I postoji jo\u0161 jedna opcija - pa\u017eljivije pregledati planove. Razvija\u010d ne bi trebao samo napisati upit, ve\u0107 i 6 puta re\u0107i \u00abexplain analyze\u00bb. Ako je 5, ne\u0107e odgovarati. <\/p>\n<p><\/p>\n<p>I postoji jo\u0161 tre\u0107a opcija - napisati pismo na pgsql-hackers. Ja sam napisao, ali za sada nije jasno - je li to gre\u0161ka ili funkcija.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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>Dok razmi\u0161ljamo - je li to gre\u0161ka ili funkcija, hajde da to sredimo. Uze\u0107emo na\u0161 upit i dodati \u00ab+0\u00bb. Sve je u redu. Dva simbola i ne treba misliti kako i \u0161to. Vrlo jednostavno. Samo smo bazi podataka zabranili kori\u0161tenje indeksa po toj koloni. Nemamo indeks po koloni \u00ab+0\u00bb i sve, baza podataka ne koristi indeks, sve je dobro. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5261d80d084786a15b9764f6367014cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Evo pravilo 6 explain-a. U trenutnim verzijama treba napraviti 6 puta, ako imate povezane varijable. Ako nemate povezane varijable, onda to radimo ovako. I u kona\u010dnici, ba\u0161 taj upit pada. Nije slo\u017eeno.<\/p>\n<p><\/p>\n<p>\u010cinilo bi se, koliko mo\u017ee? Ovdje gre\u0161ka, ondje gre\u0161ka. Stvarno, gre\u0161ka svuda. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/674dc7e7b4624baa5c79eee9e1e89db0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pogledajmo jo\u0161 jednom. Na primjer, imamo dva sheme. Shema A s tablicom \u042b i shema B s tablicom \u042b. Upit - izabrati podatke iz tablice. \u0160to \u0107e se dogoditi? Imat \u0107emo gre\u0161ku. Imat \u0107emo sve prethodno navedeno. Pravilo je takvo - gre\u0161ka je svuda, imat \u0107emo sve prethodno navedeno.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dd6f544bb9e930c39e36523c9afe6003.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Sada pitanje: \u00abZa\u0161to?\u00bb. \u010cinilo bi se, postoji dokumentacija koja ka\u017ee da, ako imamo shemu, postoji varijabla \u00absearch_path\u00bb koja govori gdje treba tra\u017eiti tablicu. \u010cinilo bi se, varijabla postoji.<\/p>\n<p><\/p>\n<p>U \u010demu je problem? Problem je u tome \u0161to server-prepared statements ne sumnjaju da bi netko mogao mijenjati search_path. Ova vrijednost ostaje kao da je konstantna za bazu podataka. I neki dijelovi mo\u017eda ne\u0107e preuzeti nove vrijednosti. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f738301606d84d72bfa7cc5b568c0df8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Naravno, to ovisi o verziji na kojoj testirate. Ovisi o tome koliko se ozbiljno va\u0161i podaci razlikuju. Verzija 9.1 jednostavno \u0107e izvr\u0161iti stare upite. Nove verzije mogu prepoznati prevaru i re\u0107i da imate pogre\u0161ku.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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\">Postavi search_path + server-prepared statements =<br \/>\npredmemorirani plan ne smije promijeniti tip rezultata<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Kako to lije\u010diti? Postoji jednostavan recept \u2013 nemojte to raditi. Ne mijenjajte search_path tijekom rada aplikacije. Ako ga promijenite, bolje je stvoriti novu vezu.<\/p>\n<p><\/p>\n<p>Mo\u017eemo razgovarati, tj. otvoriti, raspraviti, dopisati. Mo\u017eda \u0107emo uvjeriti developere baze podataka da u slu\u010daju kada netko promijeni vrijednost, baza podataka treba obavijestiti klijenta: \"Pogledajte, ovdje vam se vrijednost a\u017eurirala. Mo\u017eda biste trebali resetirati izjave, ponovo ih stvoriti?\". Trenutno se baza podataka pona\u0161a neprimjetno i ne javlja o tome da su unutra izjave promijenjene. <\/p>\n<p><\/p>\n<p>I ponovno \u0107u naglasiti \u2013 to nije tipi\u010dno za Javu. Ista stvar \u0107e se vidjeti u PL\/pgSQL jedan na jedan. Ali \u0107e se tu reproducirati.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a4e7b201d0c0aa4a0092d2b6ff152df7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Poku\u0161ajmo jo\u0161 odabrati podatke. Biramo, biramo. Imamo tablicu s milijun redaka. Svaki redak je oko kilobajta. Pribli\u017eno gigabajt podataka. A imamo radnu memoriju u Java ma\u0161ini od 128 megabajta. <\/p>\n<p><\/p>\n<p>Kao \u0161to preporu\u010duje u svim knjigama, koristimo stream obradu. Tj. otvaramo resultSet i \u010ditamo podatke polako. Ho\u0107e li to raditi? Ho\u0107e li pasti zbog memorije? Ho\u0107e li \u010ditati malo po malo? Vjerujmo u bazu, vjerujmo u Postgres. Ne vjerujemo. Ho\u0107e li pasti OutOfMemory? Tko je imao OutOfMemory? A tko je uspio popraviti nakon toga? Netko je uspio popraviti. <\/p>\n<p><\/p>\n<p>Ako imate milijun redaka, ne mo\u017eete jednostavno birati. Obavezno je koristiti OFFSET\/LIMIT. Tko se sla\u017ee s tom opcijom? I tko se sla\u017ee s varijantom da se igra s autoCommitom? <\/p>\n<p><\/p>\n<p>Ovdje, kao obi\u010dno, najneobi\u010dnija opcija pokazuje se ispravnom. I ako iznenada isklju\u010dite autoCommit, to \u0107e pomo\u0107i. Za\u0161to? Znanosti o tome nije poznato. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2e5d9d2a8450a9069155de86a8ec387a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>No prema zadanim postavkama svi klijenti koji se povezuju s bazom podataka Postgres odabiru podatke u cijelosti. PgJDBC u tom pogledu nije iznimka, odabire sve redke.<\/p>\n<p><\/p>\n<p>Postoji varijacija na temu FetchSize, tj. na razini pojedina\u010dne izjave mo\u017eete re\u0107i da ovdje, molim vas, odabirete podatke po 10, 50. No to ne radi dok ne isklju\u010dite autoCommit. Isklju\u010dite autoCommit \u2013 po\u010dinje raditi. <\/p>\n<p><\/p>\n<p>No, hodati kroz kod i svuda postavljati setFetchSize \u2013 to je neprakti\u010dno. Zato smo napravili takvu postavku koja \u0107e za cijelu vezu re\u0107i zadanu vrijednost.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c9ac8e483dc6bfdbbc300972ee1ab1e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>To smo rekli. Postavili smo parametar. I \u0161to smo dobili? Ako biramo malo, na primjer, biraju\u0107i 10 redaka, imamo prili\u010dno velike tro\u0161kove. Zato bi ovu vrijednost trebalo postaviti na otprilike stotinu. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/073e7a4af63688396eefe332ba8261d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Idealno, naravno, nau\u010diti ograni\u010diti i u bajtovima, ali recept je takav: postavljamo defaultRowFetchSize iznad stotinu i radujemo se. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e3078faf2078fcaec10d6d99872a9990.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hajde da pre\u0111emo na umetanje podataka. Umetanje je jednostavnije, tu su razli\u010dite varijante. Na primjer, INSERT, VALUES. To je dobra opcija. Mo\u017ee se re\u0107i \"INSERT SELECT\". U praksi je to zapravo isto. Nema razlike u performansama. <\/p>\n<p><\/p>\n<p>Knjige govore da treba izvoditi Batch izjave, knjige govore da se mogu izvoditi slo\u017eenije naredbe s vi\u0161e zagrada. A u Postgresu postoji divna funkcija \u2013 mo\u017eete raditi COPY, tj. raditi to br\u017ee. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4d281c9515bdf8de7fbf1e9922d192d0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ako mjerimo, mo\u017eemo ponovo napraviti nekoliko zanimljivih otkri\u0107a. Kako \u017eelimo da to radi? \u017delimo da ne analiziramo i da ne izvr\u0161avamo suvi\u0161ne naredbe. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b2e4343c51dab3ddb6919bf0f117c4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>U praksi nam TCP to ne omogu\u0107ava. Ako je klijent zauzet slanjem zahtjeva, baza podataka ne \u010dita zahtjeve u poku\u0161aju da nam po\u0161alje odgovore. Na kraju, klijent \u010deka bazu podataka dok ona ne pro\u010dita zahtjev, a baza podataka \u010deka klijenta dok on ne pro\u010dita odgovor. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/17a062c30ddd83cb890775ec1722044f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I zato je klijent prisiljen s vremena na vrijeme slati paket sinkronizacije. Suvi\u0161ne mre\u017ene interakcije, suvi\u0161no gubljenje vremena.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ae7a4f32e2949c1d0550da051937de02.jpg\" style=\"display:block;margin: 0 auto;\" \/>I \u0161to vi\u0161e njih dodajemo, to je gore. Driver je prili\u010dno pesimisti\u010dan i dodaje ih prili\u010dno \u010desto, otprilike jednom na 200 redaka, ovisno o veli\u010dini redaka itd. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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>Dogodi se da ispravi\u0161 samo jedan redak i svi procesi se ubrzaju 10 puta. To se de\u0161ava. Za\u0161to? Kao obi\u010dno, neka konstanta je ve\u0107 bila kori\u0161tena. A vrijednost \"128\" zna\u010dila je \u2013 ne koristiti batching.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve 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>Dobro je \u0161to to nije u\u0161lo u slu\u017ebenu verziju. Otkriveno je prije nego \u0161to smo po\u010deli izdavati verziju. Sve vrijednosti koje spominjem temelje se na suvremenim verzijama. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28c82d9e11f6bdaf3cf62b49fc074d68.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hajde da mjerimo. Mjerimo jednostavni InsertBatch. Mjerimo vi\u0161ekratni InsertBatch, tj. isto, ali s mnogo values. Spretan potez. Ne znaju svi to raditi, ali to je jednostavan potez, puno lak\u0161e nego COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/72f7cf6c3b9d9175d3e5a6d5410fe209.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Mo\u017ee se raditi COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2b0d8bbcc50f1293c9a8a1eb8eb70d2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I to se mo\u017ee raditi na strukturama. Deklarirajte User default type, predajte niz i INSERT izravno u tablicu. <\/p>\n<p><\/p>\n<p>Ako otvorite poveznicu: pgjdbc\/ubenchmsrk\/InsertBatch.java, taj kod je na GitHubu. Mo\u017eete vidjeti konkretno koje se upiti generiraju. Nije ni va\u017eno.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28dede211fe401286685ca62081453de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pokrenuli smo. I prvo \u0161to smo shvatili je da ne koristiti batch \u2013 to jednostavno nije mogu\u0107e. Sve opcije batching su jednake nuli, tj. vrijeme izvr\u0161enja prakti\u010dki je jednako nuli u usporedbi s pojedina\u010dnim izvr\u0161enjem. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4ea68f712bbdeadd35f5baa4ddaeff33.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Unosimo podatke. Tablica je prili\u010dno jednostavna. Ima tri kolone. I \u0161to ovdje vidimo? Vidimo da su sve te tri opcije otprilike jednake. I COPY je svakako bolji.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2686f1d7eea347a839ac23aef2a27e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>To je kada unosimo u dijelovima. Kada smo govorili da jedno vrijednost VALUES, dva vrijednost VALUES, tri vrijednost VALUES ili smo ih tamo 10 naveli zarezom. To se upravo sada prikazuje horizontalno. 1, 2, 4, 128. Vidljivo je da Batch Insert, koji je prikazan plavom bojom, olak\u0161ava stvar. Tj. kada unosite po jedan ili \u010dak kada unosite po \u010detiri, postaje dvostruko bolje, samo zato \u0161to smo u VALUES stavili malo vi\u0161e. Manje EXECUTE operacija.<\/p>\n<p><\/p>\n<p>Koristiti COPY na malim volumena je izuzetno neperspektivno. Prve dvije \u010dak nisam ni prikazao. One idu u nebo, tj. te zelene cifre za COPY.<\/p>\n<p><\/p>\n<p>COPY treba koristiti kada imate obim podataka od bar vi\u0161e od sto redaka. Tro\u0161kovi otvaranja te veze su veliki. I, iskreno, nisam se time dublje bavio. Batch sam optimizirao, COPY \u2013 ne. <\/p>\n<p><\/p>\n<p>\u0160to radimo dalje? Mjerimo. Shva\u0107amo da trebamo koristiti ili strukture, ili pametan batch koji kombinira nekoliko vrijednosti. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL i JDBC - istiskujemo sve sokove. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e02fa2574e2d1b678382db15064610d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0160to trebamo iznijeti iz dana\u0161njeg izlaganja?<\/p>\n<p><\/p>\n<ul>\n<li>PreparedStatement \u2013 to je sve za nas. To puno poma\u017ee u performansama. Donosi veliku ba\u010dvu katrana. <\/li>\n<li>I treba napraviti EXPLAIN ANALYZE 6 puta.<\/li>\n<li>I treba razbla\u017eiti OFFSET 0, i trikovima poput +0 kako bi se ispravio preostali postotak na\u0161ih problemati\u010dnih upita.<\/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\/hr\/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=\"hr_HR\" \/>\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\/hr\/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 i JDBC izvu\u010demo sve sokove. Vladimir Sitnikov | ProHoster","description":"Predla\u017eem da se upoznate s transkripcijom izlaganja Vladimira Sitnikova iz po\u010detka 2016. godine \"PostgreSQL i JDBC - izvu\u010dimo sve \u0161to mo\u017eemo\"","canonical_url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hr_HR","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\/hr\/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\/hr\/wp-json\/wp\/v2\/posts\/79893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=79893"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/79893\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media\/79894"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=79893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=79893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=79893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}