{"id":79465,"date":"2020-04-27T07:42:20","date_gmt":"2020-04-27T05:42:20","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh"},"modified":"2020-04-27T07:42:20","modified_gmt":"2020-04-27T05:42:20","slug":"istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","status":"publish","type":"post","link":"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","title":{"rendered":"Pravda p\u0159edev\u0161\u00edm, nebo pro\u010d by m\u011bl b\u00fdt syst\u00e9m navr\u017een na z\u00e1klad\u011b n\u00e1vrhu datab\u00e1ze","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Ahoj, Habr!<\/p>\n<p>Pokra\u010dujeme v zkoum\u00e1n\u00ed t\u00e9matu <noindex><a rel=\"nofollow\" href=\"https:\/\/www.piter.com\/collection\/all\/product\/sovremennyy-yazyk-java-lyambda-vyrazheniya-potoki-i-funktsionalnoe-programmirovanie\">Javy<\/a><\/noindex> a <noindex><a rel=\"nofollow\" href=\"https:\/\/storage.piter.com\/upload\/contents\/978544611587\/978544611587_X.pdf\">Jaro<\/a><\/noindex>, v\u010detn\u011b \u00farovn\u011b datab\u00e1z\u00ed. Dnes v\u00e1m nab\u00edz\u00edme \u010dl\u00e1nek o tom, pro\u010d by p\u0159i n\u00e1vrhu velk\u00fdch aplikac\u00ed m\u011bla m\u00edt struktura datab\u00e1ze rozhoduj\u00edc\u00ed v\u00fdznam, nikoli k\u00f3d Java, jak se to d\u011bl\u00e1 a jak\u00e1 v\u00fdjimky z tohoto pravidla existuj\u00ed.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex> <br \/>\nV tomto pon\u011bkud opo\u017ed\u011bn\u00e9m \u010dl\u00e1nku vysv\u011btl\u00edm, pro\u010d pova\u017euji za z\u00e1sadn\u00ed, aby byla datov\u00e1 model aplikace projektov\u00e1n \"na z\u00e1klad\u011b datab\u00e1ze\", a nikoli \"na z\u00e1klad\u011b mo\u017enost\u00ed Javy\" (nebo jin\u00e9ho klientsk\u00e9ho jazyka, se kter\u00fdm pracujete). V\u00fdb\u011br druh\u00e9ho p\u0159\u00edstupu v\u00e1s postav\u00ed na dlouhou cestu bolesti a utrpen\u00ed, jakmile v\u00e1\u0161 projekt za\u010dne r\u016fst.<\/p>\n<p>\u010cl\u00e1nek byl naps\u00e1n na z\u00e1klad\u011b <noindex><a rel=\"nofollow\" href=\"https:\/\/stackoverflow.com\/questions\/50706556\/kotlin-with-jooq-and-write-table-models-manually-without-code-generation\">jednoho dotazu<\/a><\/noindex>, kter\u00fd byl polo\u017een na Stack Overflow.<\/p>\n<p>Zaj\u00edmav\u00e9 diskuze na redditu v sekc\u00edch <noindex><a rel=\"nofollow\" href=\"https:\/\/www.reddit.com\/r\/java\/comments\/8p0uj3\/truth_first_or_why_you_should_mostly_implement\/\">\/r\/java<\/a><\/noindex> a <noindex><a rel=\"nofollow\" href=\"https:\/\/www.reddit.com\/r\/programming\/comments\/8p0qle\/truth_first_or_why_you_should_mostly_implement\/\">\/r\/programming<\/a><\/noindex>.<\/p>\n<h4>Generace k\u00f3du<\/h4>\n<p>\nJak moc jsem byl p\u0159ekvapen, \u017ee existuje tak mal\u00e1 skupina u\u017eivatel\u016f, kte\u0159\u00ed se, po sezn\u00e1men\u00ed se s jOOQ, roz\u010diluj\u00ed nad t\u00edm, \u017ee p\u0159i pr\u00e1ci s jOOQ se v\u00e1\u017en\u011b spol\u00e9h\u00e1 na generaci zdrojov\u00e9ho k\u00f3du. Nikdo v\u00e1m nebr\u00e1n\u00ed pou\u017e\u00edvat jOOQ tak, jak uzn\u00e1te za vhodn\u00e9, a nenut\u00ed v\u00e1s pou\u017e\u00edvat generaci k\u00f3du. Ale ve v\u00fdchoz\u00edm nastaven\u00ed (jak je pops\u00e1no v dokumentaci) se pr\u00e1ce s jOOQ prov\u00e1d\u00ed takto: za\u010d\u00edn\u00e1te s (zd\u011bd\u011bn\u00fdm) sch\u00e9matem datab\u00e1ze, prov\u00e1d\u00edte jeho zp\u011btn\u00e9 projektov\u00e1n\u00ed pomoc\u00ed gener\u00e1toru k\u00f3du jOOQ, abyste tak z\u00edskali sadu t\u0159\u00edd p\u0159edstavuj\u00edc\u00edch va\u0161e tabulky, a n\u00e1sledn\u011b p\u00ed\u0161ete typov\u011b bezpe\u010dn\u00e9 dotazy na tyto tabulky:<\/p>\n<pre><code class=\"java\">\tfor (Record2 record : DSL.using(configuration)\n\/\/   ^^^^^^^^^^^^^^^^^^^^^^^ Informace o typech jsou odvozeny na \n\/\/   z\u00e1klad\u011b vygenerovan\u00e9ho k\u00f3du, na kter\u00fd se odkazuje uveden\u00e9\n\/\/   n\u00ed\u017ee podm\u00ednka SELECT \n \n       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)\n\/\/           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ vygenerovan\u00e1 jm\u00e9na\n       .from(ACTOR)\n       .orderBy(1, 2)) {\n    \/\/ ...\n}<\/code><\/pre>\n<p>\nK\u00f3d se generuje bu\u010f ru\u010dn\u011b mimo sestaven\u00ed, nebo ru\u010dn\u011b p\u0159i ka\u017ed\u00e9m sestaven\u00ed. Nap\u0159\u00edklad takov\u00e1 regenerace m\u016f\u017ee n\u00e1sledovat hned po <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">migraci datab\u00e1ze Flyway, kterou je mo\u017en\u00e9 prov\u00e9st tak\u00e9 ru\u010dn\u011b nebo automaticky.<\/a><\/noindex>.<\/p>\n<h4>Generace zdrojov\u00e9ho k\u00f3du<\/h4>\n<p>\nS t\u011bmito p\u0159\u00edstupy k generov\u00e1n\u00ed k\u00f3du \u2013 ru\u010dn\u00edmi a automatick\u00fdmi \u2013 jsou spojeny r\u016fzn\u00e9 filozofie, v\u00fdhody a nev\u00fdhody, kter\u00e9 nehodl\u00e1m podrobn\u011b rozeb\u00edrat v tomto \u010dl\u00e1nku. Ale obecn\u011b je cel\u00e1 podstata generovan\u00e9ho k\u00f3du v tom, \u017ee umo\u017e\u0148uje reprodukovat v Jav\u011b tu \u201epravdu\u201c, kterou p\u0159ij\u00edm\u00e1me jako danost, a\u0165 u\u017e v r\u00e1mci na\u0161eho syst\u00e9mu, nebo mimo n\u011bj. V jist\u00e9m smyslu to sam\u00e9 d\u011blaj\u00ed kompil\u00e1tory, kter\u00e9 generuj\u00ed bytecode, strojov\u00fd k\u00f3d nebo n\u011bjak\u00fd jin\u00fd typ k\u00f3du na z\u00e1klad\u011b zdrojov\u00fdch soubor\u016f \u2013 dost\u00e1v\u00e1me zobrazen\u00ed na\u0161\u00ed \u201epravdy\u201c v jin\u00e9m jazyce, bez ohledu na konkr\u00e9tn\u00ed d\u016fvody. <\/p>\n<p>Existuje mnoho takov\u00fdch gener\u00e1tor\u016f k\u00f3du. Nap\u0159\u00edklad, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/technotes\/tools\/unix\/xjc.html\">XJC m\u016f\u017ee generovat Java k\u00f3d na z\u00e1klad\u011b soubor\u016f XSD nebo WSDL<\/a><\/noindex>. Princip je v\u017edy stejn\u00fd:<\/p>\n<ul>\n<li>Existuje n\u011bjak\u00e1 pravda (vnit\u0159n\u00ed nebo vn\u011bj\u0161\u00ed) \u2013 nap\u0159\u00edklad specifikace, datov\u00fd model atd.<\/li>\n<li>Pot\u0159ebujeme m\u00edstn\u00ed zobrazen\u00ed t\u00e9to pravdy v na\u0161em programovac\u00edm jazyce.<\/li>\n<\/ul>\n<p>\nA generovat takov\u00e9 zobrazen\u00ed je t\u00e9m\u011b\u0159 v\u017edy rozumn\u00e9 \u2013 aby se p\u0159ede\u0161lo nadbyte\u010dnosti.<\/p>\n<h4>Poskytovatel\u00e9 typ\u016f a zpracov\u00e1n\u00ed anotac\u00ed<\/h4>\n<p>\nNa pam\u011bti: je\u0161t\u011b jeden, modern\u011bj\u0161\u00ed a specifi\u010dt\u011bj\u0161\u00ed p\u0159\u00edstup k generov\u00e1n\u00ed k\u00f3du pro jOOQ je spojen s pou\u017eit\u00edm poskytovatel\u016f typ\u016f, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/fsharp\/tutorials\/type-providers\/\">v takov\u00e9 podob\u011b, jak je to realizov\u00e1no v F#<\/a><\/noindex>. V takov\u00e9m p\u0159\u00edpad\u011b je k\u00f3d generov\u00e1n kompil\u00e1torem, vlastn\u011b v dob\u011b kompilace. V podob\u011b zdrojov\u00fdch k\u00f3d\u016f takov\u00fd k\u00f3d v z\u00e1sad\u011b neexistuje. V Jav\u011b existuj\u00ed podobn\u00e9, i kdy\u017e ne tak elegantn\u00ed n\u00e1stroje \u2013 to jsou procesory anotac\u00ed, nap\u0159\u00edklad, <noindex><a rel=\"nofollow\" href=\"https:\/\/projectlombok.org\">Lombok<\/a><\/noindex>.<\/p>\n<p>V jist\u00e9m smyslu se zde d\u011bje to sam\u00e9 jako v prvn\u00edm p\u0159\u00edpad\u011b, s v\u00fdjimkou:<\/p>\n<ul>\n<li>Nevid\u00edte generovan\u00fd k\u00f3d (mo\u017en\u00e1, \u017ee to n\u011bkomu nep\u0159ipad\u00e1 tak odrazuj\u00edc\u00ed?)<\/li>\n<li>Mus\u00edte zaru\u010dit, \u017ee typy mohou b\u00fdt poskytov\u00e1ny, tedy \u201epravda\u201c mus\u00ed b\u00fdt v\u017edy dostupn\u00e1. To je snadn\u00e9 v p\u0159\u00edpad\u011b Lombok, kter\u00fd anotuje \u201epravdu\u201c. O n\u011bco slo\u017eit\u011bj\u0161\u00ed je to s datab\u00e1zov\u00fdmi modely, jejich\u017e fungov\u00e1n\u00ed z\u00e1vis\u00ed na trvale dostupn\u00e9m \u017eiv\u00e9m p\u0159ipojen\u00ed.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Jak\u00fd je probl\u00e9m s generov\u00e1n\u00edm k\u00f3du?<\/h4>\n<p>\nKrom\u011b slo\u017eit\u00e9 ot\u00e1zky, jak nejl\u00e9pe spustit generaci k\u00f3du \u2013 ru\u010dn\u011b nebo automaticky \u2013 mus\u00edme tak\u00e9 zm\u00ednit, \u017ee existuj\u00ed lid\u00e9, kte\u0159\u00ed v\u011b\u0159\u00ed, \u017ee generace k\u00f3du v\u016fbec nen\u00ed pot\u0159eba. Nej\u010dast\u011bj\u0161\u00ed obhajoba tohoto n\u00e1zoru, se kterou jsem se setkal, spo\u010d\u00edv\u00e1 v tom, \u017ee pak je obt\u00ed\u017en\u00e9 nastavit sestavovac\u00ed pipeline. Ano, skute\u010dn\u011b je to slo\u017eit\u00e9. Vznikaj\u00ed dal\u0161\u00ed infrastrukturn\u00ed n\u00e1klady. Pokud pr\u00e1v\u011b za\u010d\u00edn\u00e1te pracovat s n\u011bjak\u00fdm produktem (a\u0165 u\u017e jOOQ, JAXB, Hibernate atd.), \u010das str\u00e1ven\u00fd nastaven\u00edm pracovn\u00edho prost\u0159ed\u00ed byste rad\u011bji v\u011bnovali studiu samotn\u00e9ho API, abyste z n\u011bj pozd\u011bji dok\u00e1zali vyt\u011b\u017eit hodnotu.<\/p>\n<p>Pokud jsou n\u00e1klady spojen\u00e9 s porozum\u011bn\u00edm konstrukci gener\u00e1toru p\u0159\u00edli\u0161 vysok\u00e9 \u2013 pak je to skute\u010dn\u011b zn\u00e1mka \u0161patn\u00e9 pr\u00e1ce na pou\u017eitelnosti API gener\u00e1toru k\u00f3du (a nakonec se uk\u00e1\u017ee, \u017ee i u\u017eivatelsk\u00e9 nastaven\u00ed v n\u011bm je slo\u017eit\u00e9). Pohodl\u00ed pou\u017e\u00edv\u00e1n\u00ed by m\u011blo b\u00fdt nejvy\u0161\u0161\u00edm prioritou pro jak\u00e9koliv API. Ale to je jen jeden argument proti generaci k\u00f3du. Jinak je naprosto zbyte\u010dn\u00e9 ps\u00e1t lok\u00e1ln\u00ed reprezentaci vnit\u0159n\u00ed \u010di vn\u011bj\u0161\u00ed pravdy \u00fapln\u011b ru\u010dn\u011b.<\/p>\n<p>Mnoz\u00ed \u0159eknou, \u017ee nemaj\u00ed \u010das se t\u00edm v\u0161\u00edm zab\u00fdvat. Maj\u00ed term\u00edny pro dod\u00e1n\u00ed sv\u00fdch superprodukt\u016f. N\u011bkdy to naprav\u00edme s pipeline. Odpov\u00edm jim:<\/p>\n<p><img decoding=\"async\" alt=\"Pravda p\u0159edev\u0161\u00edm, nebo pro\u010d by m\u011bl b\u00fdt syst\u00e9m navr\u017een na z\u00e1klad\u011b n\u00e1vrhu datab\u00e1ze\" src=\"\/wp-content\/uploads\/2020\/04\/cd9aca1e0365fa5af28cfc72c201cb8c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/www.flickr.com\/photos\/toddle_email_newsletters\/15596940251\/in\/photostream\/\">Origin\u00e1l<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"http:\/\/audiencestack.com\/static\/blog.html\">Alan O'Rourk, Audience Stack<\/a><\/noindex> <\/p>\n<p><b>Ale v Hibernate \/ JPA je tak snadn\u00e9 ps\u00e1t k\u00f3d \u201epro Java\u201c. <\/b><\/p>\n<p>Skute\u010dn\u011b. Pro Hibernate a jeho u\u017eivatele to je z\u00e1rove\u0148 po\u017eehn\u00e1n\u00ed i proklet\u00ed. V Hibernate m\u016f\u017eete jednodu\u0161e napsat p\u00e1r entit, takto:<\/p>\n<pre><code class=\"java\">\t@Entity\nclass Book {\n  @Id\n  int id;\n  String title;\n}<\/code><\/pre>\n<p>\nA skoro je to hotov\u00e9. Nyn\u00ed je \u00fakol Hibernate generovat slo\u017eit\u00e9 \u201edetaily\u201c toho, jak p\u0159esn\u011b tato entita bude definov\u00e1na v DDL va\u0161eho \u201edialektu\u201c SQL:<\/p>\n<pre><code class=\"sql\">\tCREATE TABLE book (\n  id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,\n  title VARCHAR(50),\n \n  CONSTRAINT pk_book PRIMARY KEY (id)\n);\n \nCREATE INDEX i_book_title ON book (title);<\/code><\/pre>\n<p>\n\u2026 a za\u010dneme spou\u0161t\u011bt aplikaci. Opravdu skv\u011bl\u00e1 schopnost, jak rychle za\u010d\u00edt pracovat a vyzkou\u0161et r\u016fzn\u00e9 v\u011bci.<\/p>\n<p>Ale po\u010dkejte. \u0158ekl jsem to \u0161patn\u011b.<\/p>\n<ul>\n<li>Bude Hibernate skute\u010dn\u011b pou\u017e\u00edvat definici tohoto pojmenovan\u00e9ho prim\u00e1rn\u00edho kl\u00ed\u010de?<\/li>\n<li>Vytvo\u0159\u00ed Hibernate index v TITLE? \u2013 p\u0159esn\u011b v\u00edm, \u017ee ho budeme pot\u0159ebovat. <\/li>\n<li>A ud\u011bl\u00e1 Hibernate tento kl\u00ed\u010d identifikuj\u00edc\u00edm v Identity Specification?<\/li>\n<\/ul>\n<p>\nPravd\u011bpodobn\u011b ne. Pokud vyv\u00edj\u00edte sv\u016fj projekt od nuly, je v\u017edy v\u00fdhodn\u00e9 jednodu\u0161e zahodit starou datab\u00e1zi a vytvo\u0159it novou, jakmile p\u0159id\u00e1te pot\u0159ebn\u00e9 anotace. Tak bude entita Book vypadat nakonec takto: <\/p>\n<pre><code class=\"java\">\t@Entity\n@Table(name = \"book\", indexes = {\n  @Index(name = \"i_book_title\", columnList = \"title\")\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n  String title;\n}\n<\/code><\/pre>\n<p>\nSuper. Znovu vygenerovat. Op\u011bt bude v takov\u00e9m p\u0159\u00edpad\u011b na za\u010d\u00e1tku velmi snadn\u00e9.<\/p>\n<h4>Ale pozd\u011bji za to budete muset zaplatit.<\/h4>\n<p>\nD\u0159\u00edve nebo pozd\u011bji se budete muset dostat do produkce. Pr\u00e1v\u011b tehdy tento model p\u0159estane fungovat. Proto\u017ee: <\/p>\n<p>V produkci ji\u017e nebude mo\u017en\u00e9 v p\u0159\u00edpad\u011b pot\u0159eby zahodit starou datab\u00e1zi a za\u010d\u00edt v\u0161e od za\u010d\u00e1tku. Va\u0161e datab\u00e1ze se stane zd\u011bd\u011bnou.<\/p>\n<p>Od t\u00e9to chv\u00edle budete muset ps\u00e1t <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">migra\u010dn\u00ed skripty DDL, nap\u0159\u00edklad pomoc\u00ed Flyway.<\/a><\/noindex>. A co se tedy stane s va\u0161imi entitami? M\u016f\u017eete je bu\u010f ru\u010dn\u011b p\u0159izp\u016fsobit (a tak zdvojn\u00e1sobit objem pr\u00e1ce), nebo p\u0159ik\u00e1zat Hibernate, aby je znovu vygeneroval pro v\u00e1s (jak velk\u00e9 jsou \u0161ance, \u017ee vygenerovan\u00e9 takov\u00fdm zp\u016fsobem bude odpov\u00eddat va\u0161im o\u010dek\u00e1v\u00e1n\u00edm?) V ka\u017ed\u00e9m p\u0159\u00edpad\u011b prohr\u00e1v\u00e1te.<\/p>\n<p>Tak\u017ee jakmile p\u0159ejdete do produkce, budete pot\u0159ebovat hork\u00e9 opravy. A ty je pot\u0159eba rychle dostat do produkce. Proto\u017ee jste se nep\u0159ipravili a neorganizovali hladk\u00e9 nasazen\u00ed va\u0161ich migrac\u00ed do produkce, v\u0161echno budete \u0161\u00edlen\u011b patchovat. A pot\u00e9 u\u017e nebudete m\u00edt \u010das ud\u011blat to spr\u00e1vn\u011b. A budete nad\u00e1vat na Hibernate, proto\u017ee vinen je v\u017edy n\u011bkdo jin\u00fd, jen ne vy...<\/p>\n<p>M\u00edsto toho se to mohlo od sam\u00e9ho za\u010d\u00e1tku d\u011blat \u00fapln\u011b jinak. Nap\u0159\u00edklad d\u00e1t na kolo kulat\u00e1 kola.<\/p>\n<h4>Nejprve datab\u00e1ze.<\/h4>\n<p>\nSkute\u010dn\u00e1 \"pravda\" v sch\u00e9matu va\u0161\u00ed datab\u00e1ze a \"suverenita\" nad n\u00ed spo\u010d\u00edv\u00e1 uvnit\u0159 datab\u00e1ze. Sch\u00e9ma je ur\u010deno pouze uvnit\u0159 samotn\u00e9 datab\u00e1ze a nikde jinde, a ka\u017ed\u00fd z klient\u016f m\u00e1 kopii tohoto sch\u00e9matu, proto je zcela smyslupln\u00e9 prosazovat dodr\u017eov\u00e1n\u00ed sch\u00e9matu a jeho integrity p\u0159\u00edmo v datab\u00e1zi \u2013 tam, kde jsou ulo\u017eeny informace. <br \/>\nTo je star\u00e1, dokonce opot\u0159ebovan\u00e1 moudrost. Prim\u00e1rn\u00ed a unik\u00e1tn\u00ed kl\u00ed\u010de \u2013 to je dobr\u00e9. Vn\u011bj\u0161\u00ed kl\u00ed\u010de \u2013 to je dobr\u00e9. Kontrola omezen\u00ed \u2013 to je dobr\u00e9. <noindex><a rel=\"nofollow\" href=\"https:\/\/community.oracle.com\/ideas\/13028\">Prohl\u00e1\u0161en\u00ed<\/a><\/noindex> \u2013 to je dobr\u00e9. <\/p>\n<p>A co v\u00edc, to je\u0161t\u011b nen\u00ed v\u0161echno. Nap\u0159\u00edklad p\u0159i pou\u017eit\u00ed Oracle pravd\u011bpodobn\u011b budete cht\u00edt uv\u00e9st:<\/p>\n<ul>\n<li>Ve kter\u00e9m tabulkov\u00e9m prostoru se nach\u00e1z\u00ed va\u0161e tabulka <\/li>\n<li>Jak\u00e1 je jej\u00ed hodnota PCTFREE <\/li>\n<li>Jak\u00e1 je velikost cache ve va\u0161\u00ed sekvenci (za identifik\u00e1torem)<\/li>\n<\/ul>\n<p>\nMo\u017en\u00e1 to v\u0161echno nen\u00ed d\u016fle\u017eit\u00e9 v mal\u00fdch syst\u00e9mech, ale nemus\u00edte \u010dekat na p\u0159echod do oblasti \u201evelk\u00fdch dat\u201c \u2014 v\u00fdhody z optimalizac\u00ed \u00falo\u017ei\u0161t\u011b od dodavatele m\u016f\u017eete za\u010d\u00edt \u010derpat mnohem d\u0159\u00edve. \u017d\u00e1dn\u00fd z ORM, kter\u00e9 jsem vid\u011bl (v\u010detn\u011b jOOQ), neposkytuje p\u0159\u00edstup k pln\u00e9mu spektru mo\u017enost\u00ed DDL, kter\u00e9 mo\u017en\u00e1 budete cht\u00edt ve sv\u00e9 datab\u00e1zi pou\u017e\u00edt. ORM nab\u00edzej\u00ed n\u011bkter\u00e9 n\u00e1stroje, kter\u00e9 usnad\u0148uj\u00ed psan\u00ed DDL.<\/p>\n<p>Ale nakonec dob\u0159e navr\u017een\u00e1 sch\u00e9ma je ru\u010dn\u011b napsan\u00e1 v DDL. Jak\u00fdkoli generovan\u00fd DDL je jen jej\u00edm p\u0159ibl\u00ed\u017een\u00edm.<\/p>\n<h4>Co klientsk\u00fd model?<\/h4>\n<p>\nJak bylo zm\u00edn\u011bno v\u00fd\u0161e, na klientovi budete pot\u0159ebovat kopii sch\u00e9matu va\u0161\u00ed datab\u00e1ze, klientsk\u00e9 zobrazen\u00ed. Je zbyte\u010dn\u00e9 zmi\u0148ovat, \u017ee toto klientsk\u00e9 zobrazen\u00ed by m\u011blo b\u00fdt synchronizov\u00e1no se skute\u010dn\u00fdm modelem. Jak toho nejl\u00e9pe dos\u00e1hnout? Pomoc\u00ed gener\u00e1toru k\u00f3du.<\/p>\n<p>V\u0161echny datab\u00e1ze poskytuj\u00ed svou meta-informaci prost\u0159ednictv\u00edm SQL. Zde je, jak z\u00edskat ze sv\u00e9 datab\u00e1ze v\u0161echny tabulky v r\u016fzn\u00fdch dialektech SQL:<\/p>\n<pre><code class=\"sql\">\t-- H2, HSQLDB, MySQL, PostgreSQL, SQL Server\nSELECT table_schema, table_name\nFROM information_schema.tables\n \n-- DB2\nSELECT tabschema, tabname\nFROM syscat.tables\n \n-- Oracle\nSELECT owner, table_name\nFROM all_tables\n \n-- SQLite\nSELECT name\nFROM sqlite_master\n \n-- Teradata\nSELECT databasename, tablename\nFROM dbc.tables\n<\/code><\/pre>\n<p>\nTyto dotazy (nebo podobn\u00e9, v z\u00e1vislosti na tom, zda je t\u0159eba rovn\u011b\u017e zohlednit pohledy, materializovan\u00e9 pohledy, funkce se tabul\u00e1rn\u00edm hodnotou) se tak\u00e9 prov\u00e1d\u011bj\u00ed zavol\u00e1n\u00edm <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/javase\/10\/docs\/api\/java\/sql\/DatabaseMetaData.html#getTables(java.lang.String,java.lang.String,java.lang.String,java.lang.String%5B%5D)\"><code>DatabaseMetaData.getTables()<\/code><\/a><\/noindex> z JDBC, nebo pomoc\u00ed meta modulu jOOQ.<\/p>\n<p>Z v\u00fdsledk\u016f t\u011bchto dotaz\u016f lze pom\u011brn\u011b snadno vygenerovat jak\u00e9koli klientsk\u00e9 zobrazen\u00ed modelu va\u0161\u00ed datab\u00e1ze, bez ohledu na to, jak\u00e1 technologie je na klientovi pou\u017eita.<\/p>\n<ul>\n<li>Pokud pou\u017e\u00edv\u00e1te JDBC nebo Spring, m\u016f\u017eete vytvo\u0159it sadu konstant typu String <\/li>\n<li>Pokud pou\u017e\u00edv\u00e1te JPA, m\u016f\u017eete generovat vlastn\u00ed entity <\/li>\n<li>Pokud pou\u017e\u00edv\u00e1te jOOQ, m\u016f\u017eete vygenerovat meta-model jOOQ<\/li>\n<\/ul>\n<p>\nV z\u00e1vislosti na tom, jak\u00fd objem mo\u017enost\u00ed nab\u00edz\u00ed va\u0161e klientsk\u00e9 API (nap\u0159. jOOQ nebo JPA), m\u016f\u017ee b\u00fdt vygenerovan\u00fd meta-model skute\u010dn\u011b bohat\u00fd a kompletn\u00ed. Vezm\u011bme si nap\u0159\u00edklad mo\u017enost implicitn\u00edch spojen\u00ed, <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2018\/02\/20\/type-safe-implicit-join-through-path-navigation-in-jooq-3-11\/\">kter\u00e1 se objevila v jOOQ 3.11<\/a><\/noindex>, kter\u00e1 se op\u00edr\u00e1 o vygenerovan\u00e9 metainformace o vztaz\u00edch ciz\u00edch kl\u00ed\u010d\u016f mezi va\u0161imi tabulkami.<\/p>\n<p>Nyn\u00ed jak\u00e9koli zv\u00fd\u0161en\u00ed datab\u00e1ze automaticky povede k aktualizaci klientsk\u00e9ho k\u00f3du. P\u0159edstavte si nap\u0159\u00edklad:<\/p>\n<pre><code class=\"sql\">ALTER TABLE book RENAME COLUMN title TO book_title;<\/code><\/pre>\n<p>\nOpravdu byste cht\u011bli tuto pr\u00e1ci d\u011blat dvakr\u00e1t? Rozhodn\u011b ne. Sta\u010d\u00ed, kdy\u017e zachyt\u00edme DDL, projdeme j\u00edm v\u00e1\u0161 buildovac\u00ed pipeline a z\u00edsk\u00e1me aktualizovanou entitu:<\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = \"book\", indexes = {\n \n  \/\/ P\u0159em\u00fd\u0161leli jste o tom?\n  @Index(name = \"i_book_title\", columnList = \"book_title\")\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n \n  @Column(\"book_title\")\n  String bookTitle;\n}<\/code><\/pre>\n<p>\nNebo aktualizovanou t\u0159\u00eddu jOOQ. V\u011bt\u0161ina zm\u011bn DDL se rovn\u011b\u017e odr\u00e1\u017e\u00ed v s\u00e9mantice, nikoli pouze v syntaxi. Proto je n\u011bkdy u\u017eite\u010dn\u00e9 pod\u00edvat se do zkompilovan\u00e9ho k\u00f3du, jak\u00fd k\u00f3d bude (nebo m\u016f\u017ee b\u00fdt) ovlivn\u011bn zv\u00fd\u0161en\u00edm va\u0161\u00ed datab\u00e1ze.<\/p>\n<h4>Jedna jedin\u00e1 pravda<\/h4>\n<p>\nBez ohledu na to, jakou technologii pou\u017e\u00edv\u00e1te, v\u017edy existuje jeden model, kter\u00fd je jedin\u00fdm zdrojem pravdy pro ur\u010ditou podsyst\u00e9m \u2013 nebo se alespo\u0148 mus\u00edme sna\u017eit tomu vyhnout a p\u0159edej\u00edt takov\u00e9mu chaosu v podnic\u00edch, kde je \"pravda\" hned v\u0161ude a nikde. V\u0161echno m\u016f\u017ee b\u00fdt mnohem jednodu\u0161\u0161\u00ed. Pokud pouze vym\u011b\u0148ujete XML soubory s n\u011bjak\u00fdm jin\u00fdm syst\u00e9mem, vyu\u017eijte XSD. Pod\u00edvejte se na metamodel INFORMATION_SCHEMA z jOOQ ve form\u00e1tu XML:<br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/www.jooq.org\/xsd\/jooq-meta-3.10.0.xsd\">https:\/\/www.jooq.org\/xsd\/jooq-meta-3.10.0.xsd<\/a><\/noindex><\/p>\n<ul>\n<li>XSD je snadno pochopiteln\u00e1<\/li>\n<li>XSD velmi dob\u0159e popisuje obsah XML a umo\u017e\u0148uje validaci ve v\u0161ech klientsk\u00fdch jazyc\u00edch <\/li>\n<li>XSD se dob\u0159e verzionuje a m\u00e1 vyvinutou zp\u011btnou kompatibilitu <\/li>\n<li>XSD lze p\u0159ev\u00e9st do Java k\u00f3du pomoc\u00ed XJC<\/li>\n<\/ul>\n<p>\nPosledn\u00ed bod je d\u016fle\u017eit\u00fd. P\u0159i komunikaci s extern\u00edm syst\u00e9mem pomoc\u00ed XML zpr\u00e1v chceme m\u00edt jistotu o platnosti na\u0161ich zpr\u00e1v. Toho lze snadno dos\u00e1hnout pomoc\u00ed JAXB, XJC a XSD. Bylo by naprost\u00fdm \u0161\u00edlenstv\u00edm p\u0159edpokl\u00e1dat, \u017ee p\u0159i p\u0159\u00edstupu k n\u00e1vrhu \u201enejprve Java\u201c, kde vytv\u00e1\u0159\u00edme na\u0161e zpr\u00e1vy jako objekty Java, je mo\u017en\u00e9 je n\u011bjak rozumn\u011b p\u0159ev\u00e9st na XML a odeslat pro spot\u0159ebu v jin\u00e9m syst\u00e9mu. XML generovan\u00e9 t\u00edmto zp\u016fsobem by bylo velmi nekvalitn\u00ed, nedokumentovan\u00e9 a t\u011b\u017eko udr\u017eovateln\u00e9. Kdyby pro takov\u00e9 rozhran\u00ed existovala dohoda o \u00farovni poskytov\u00e1n\u00ed slu\u017eeb (SLA), ihned bychom ji poru\u0161ili.<\/p>\n<p>Up\u0159\u00edmn\u011b \u0159e\u010deno, pr\u00e1v\u011b to se neust\u00e1le d\u011bje s API na JSON, ale to je jin\u00fd p\u0159\u00edb\u011bh, p\u0159\u00ed\u0161t\u011b si post\u011b\u017euju\u2026 <\/p>\n<h4>Datab\u00e1ze: to je tot\u00e9\u017e<\/h4>\n<p>\nP\u0159i pr\u00e1ci s datab\u00e1zemi ch\u00e1pete, \u017ee v\u0161echny jsou v z\u00e1sad\u011b podobn\u00e9. Datab\u00e1ze vlastn\u00ed sv\u00e1 data a mus\u00ed \u0159\u00eddit sch\u00e9ma. Jak\u00e9koli zm\u011bny proveden\u00e9 ve sch\u00e9matu mus\u00ed b\u00fdt realizov\u00e1ny p\u0159\u00edmo na DDL, aby se aktualizoval jedin\u00fd zdroj pravdy.<\/p>\n<p>Kdy\u017e k aktualizaci zdroje dojde, v\u0161ichni klienti by tak\u00e9 m\u011bli aktualizovat sv\u00e9 kopie modelu. N\u011bkte\u0159\u00ed klienti mohou b\u00fdt naps\u00e1ni v Jav\u011b pomoc\u00ed jOOQ a Hibernate nebo JDBC (nebo v\u0161ech najednou). Jin\u00ed klienti mohou b\u00fdt naps\u00e1ni v Perlu (p\u0159ejeme jim hodn\u011b \u0161t\u011bst\u00ed), dal\u0161\u00ed pak v C#. Na tom nez\u00e1le\u017e\u00ed. Hlavn\u00ed model se nach\u00e1z\u00ed v datab\u00e1zi. Modely generovan\u00e9 pomoc\u00ed ORM jsou obvykle nekvalitn\u00ed, \u0161patn\u011b dokumentovan\u00e9 a t\u011b\u017eko udr\u017eovateln\u00e9.<\/p>\n<p>Tak\u017ee ned\u011blejte chyby. Od za\u010d\u00e1tku ned\u011blejte chyby. Pracujte na z\u00e1klad\u011b datab\u00e1ze. Vytvo\u0159te takov\u00fd pipeline pro nasazen\u00ed, kter\u00fd lze automatizovat. Za\u0159a\u010fte gener\u00e1tory k\u00f3du, aby bylo pohodln\u00e9 kop\u00edrovat model va\u0161\u00ed datab\u00e1ze a p\u0159ed\u00e1vat ho klient\u016fm. A p\u0159esta\u0148te se ob\u00e1vat gener\u00e1tor\u016f k\u00f3du. Jsou dobr\u00e9. S nimi budete produktivn\u011bj\u0161\u00ed. Sta\u010d\u00ed na za\u010d\u00e1tku investovat trochu \u010dasu do jejich nastaven\u00ed \u2013 a pak na v\u00e1s \u010dekaj\u00ed roky zv\u00fd\u0161en\u00e9 produktivity, kter\u00e9 utvo\u0159\u00ed p\u0159\u00edb\u011bh va\u0161eho projektu.<\/p>\n<p>Zat\u00edm nepod\u011bkujte, pozd\u011bji.<\/p>\n<h4>Vysv\u011btlen\u00ed<\/h4>\n<p>\nPro jasno: Tento \u010dl\u00e1nek rozhodn\u011b nepropaguje, \u017ee byste m\u011bli p\u0159izp\u016fsobit cel\u00fd syst\u00e9m modelu va\u0161\u00ed datab\u00e1ze (t.j. dom\u00e9n\u011b, obchodn\u00ed logice atd.). V tomto \u010dl\u00e1nku se zam\u011b\u0159uji na to, \u017ee klientsk\u00fd k\u00f3d, kter\u00fd interaguje s datab\u00e1z\u00ed, by m\u011bl fungovat na z\u00e1klad\u011b modelu datab\u00e1ze, tak aby samotn\u00fd k\u00f3d neodr\u00e1\u017eel model datab\u00e1ze jako \u201eprvn\u00ed t\u0159\u00eddy\u201c. Takov\u00e1 logika se obvykle nach\u00e1z\u00ed na \u00farovni p\u0159\u00edstupu k dat\u016fm na va\u0161\u00ed stran\u011b klienta.<\/p>\n<p>V dvouvrstv\u00fdch architektur\u00e1ch, kter\u00e9 se dosud na mnoha m\u00edstech udr\u017eely, m\u016f\u017ee b\u00fdt takov\u00fd model syst\u00e9mu jedin\u011b mo\u017en\u00fd. Nicm\u00e9n\u011b ve v\u011bt\u0161in\u011b syst\u00e9m\u016f se \u00farove\u0148 p\u0159\u00edstupu k dat\u016fm jev\u00ed jako \u201epodt\u0159\u00eddou\u201c, kter\u00e1 inkapsuluje model datab\u00e1ze.<\/p>\n<h4>V\u00fdjimky<\/h4>\n<p>\nZ ka\u017ed\u00e9ho pravidla existuj\u00ed v\u00fdjimky a ji\u017e jsem zm\u00ednil, \u017ee p\u0159\u00edstup prim\u00e1rn\u00ed datab\u00e1ze a generov\u00e1n\u00ed zdrojov\u00e9ho k\u00f3du m\u016f\u017ee n\u011bkdy b\u00fdt nevhodn\u00fd. Zde je p\u00e1r takov\u00fdch v\u00fdjimek (pravd\u011bpodobn\u011b existuj\u00ed i jin\u00e9):<\/p>\n<ul>\n<li>Kdy\u017e je sch\u00e9ma nezn\u00e1m\u00e9 a je nutn\u00e9 je odhalit. Nap\u0159\u00edklad, pokud jste dodavatel n\u00e1stroje, kter\u00fd pom\u00e1h\u00e1 u\u017eivatel\u016fm zorientovat se v jak\u00e9mkoli sch\u00e9matu. Uf. Tady bez generov\u00e1n\u00ed k\u00f3du. Ale p\u0159esto \u2013 datab\u00e1ze je na prvn\u00edm m\u00edst\u011b.<\/li>\n<li>Kdy\u017e mus\u00ed b\u00fdt sch\u00e9ma generov\u00e1no za b\u011bhu pro \u0159e\u0161en\u00ed ur\u010dit\u00e9ho \u00fakolu. Tento p\u0159\u00edklad se zd\u00e1 b\u00fdt pon\u011bkud vyt\u0159\u00edbenou verz\u00ed vzoru <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">entity attribute value<\/a><\/noindex>, t.j. opravdu nem\u00e1te jasn\u011b definovan\u00e9 sch\u00e9ma. V tomto p\u0159\u00edpad\u011b \u010dasto ani nen\u00ed mo\u017en\u00e9 b\u00fdt si jisti, \u017ee v\u00e1m bude n\u011bjak\u00fd RDBMS vyhovovat.<\/li>\n<\/ul>\n<p>\nV\u00fdjimky jsou sv\u00fdm zp\u016fsobem v\u00fdjime\u010dn\u00e9. V\u011bt\u0161inou, co se t\u00fd\u010de pou\u017e\u00edv\u00e1n\u00ed RDBMS, je sch\u00e9ma zn\u00e1mo dop\u0159edu, nach\u00e1z\u00ed se uvnit\u0159 RDBMS a je jedin\u00fdm zdrojem \u201epravdy\u201c, a v\u0161ichni klienti mus\u00ed m\u00edt kopie, kter\u00e9 z n\u00ed vych\u00e1zej\u00ed. Ide\u00e1ln\u011b by m\u011bl b\u00fdt zapojen gener\u00e1tor k\u00f3du.<br \/>\n<br \/>Zdroj: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/piter\/blog\/498816\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443 Java \u0438 Spring, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u043a\u043e\u0434 Java, \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u043e\u0437\u0434\u0430\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79466,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79465","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\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443\" \/>\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\/cs\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"cs_CZ\" \/>\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\udd47\u0418\u0441\u0442\u0438\u043d\u0430 \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0438\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh\" \/>\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-04-27T05:42:20+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-04-27T05:42:20+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\udd47Pravda na prvn\u00edm m\u00edst\u011b, nebo pro\u010d je d\u016fle\u017eit\u00e9 navrhovat syst\u00e9m na z\u00e1klad\u011b struktury datab\u00e1ze | ProHoster","description":"Ahoj, Habr! Pokra\u010dujeme v prozkoum\u00e1v\u00e1n\u00ed t\u00e9matu","canonical_url":"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"cs_CZ","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\udd47\u0418\u0441\u0442\u0438\u043d\u0430 \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0438\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443","og:url":"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","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-04-27T05:42:20+00:00","article:modified_time":"2020-04-27T05:42:20+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79465","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:37:24","updated":"2022-09-29 16:13:15","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts\/79465","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/comments?post=79465"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts\/79465\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/media\/79466"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/media?parent=79465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/categories?post=79465"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/tags?post=79465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}