{"id":83649,"date":"2020-06-02T07:42:21","date_gmt":"2020-06-02T05:42:21","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/database-as-sode-experience"},"modified":"2020-06-02T07:42:21","modified_gmt":"2020-06-02T05:42:21","slug":"database-as-sode-experience","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/database-as-sode-experience","title":{"rendered":"\u201eDatenbank als Code\u201c Erfahrung","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"\u201eDatenbank als Code\u201c Erfahrung\" src=\"\/wp-content\/uploads\/2020\/06\/a1ac23deeded97559fbe787ed09184a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>SQL, was k\u00f6nnte einfacher sein? Jeder von uns kann eine einfache Anfrage schreiben \u2013 wir geben ein <strong><em>select<\/em><\/strong>, listen die ben\u00f6tigten Spalten auf, dann <strong><em>from<\/em><\/strong>, den Tabellennamen, ein paar Bedingungen in <strong><em>wo<\/em><\/strong> und schon \u2013 n\u00fctzliche Daten sind in unserer Tasche, fast unabh\u00e4ngig davon, welche DBMS gerade im Hintergrund l\u00e4uft (oder vielleicht ist es sogar <noindex><a rel=\"nofollow\" href=\"https:\/\/osquery.io\/\">gar kein DBMS<\/a><\/noindex>). In der Folge kann die Arbeit mit nahezu jeder Datenquelle (relational oder nicht) aus der Sicht gew\u00f6hnlichen Codes betrachtet werden (mit all seinen Konsequenzen \u2014 Versionskontrolle, Code-Review, statische Analyse, automatisierte Tests und all das). Dies betrifft nicht nur die Daten selbst, Schemata und Migrationen, sondern das gesamte Leben des Repositories. In diesem Artikel sprechen wir \u00fcber allt\u00e4gliche Aufgaben und Probleme bei der Arbeit mit verschiedenen Datenbanken aus der Perspektive von \"Datenbank als Code\".<\/p>\n<p><\/p>\n<p>Und wir beginnen direkt mit <noindex><a rel=\"nofollow\" href=\"https:\/\/www.yegor256.com\/2014\/12\/01\/orm-offensive-anti-pattern.html\">ORM<\/a><\/noindex>. Die ersten K\u00e4mpfe im Stil von \"SQL gegen ORM\" wurden bereits beobachtet in <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/904343\/orm-vs-sql\">vorkolonialem Russland<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h5 id=\"obektno-relyacionnyy-maping\">Objekt-Relationales Mapping<\/h5>\n<p><\/p>\n<p>Bef\u00fcrworter von ORM sch\u00e4tzen traditionell die Geschwindigkeit und Einfachheit der Entwicklung, die Unabh\u00e4ngigkeit von DBMS und die Klarheit des Codes. F\u00fcr viele von uns sieht der Code zur Arbeit mit der Datenbank (und oft auch die Datenbank selbst)<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">sieht normalerweise ungef\u00e4hr so aus\u2026<\/b><\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = \"stock\", catalog = \"maindb\", uniqueConstraints = {\n        @UniqueConstraint(columnNames = \"STOCK_NAME\"),\n        @UniqueConstraint(columnNames = \"STOCK_CODE\") })\npublic class Stock implements java.io.Serializable {\n\n    @Id\n    @GeneratedValue(strategy = IDENTITY)\n    @Column(name = \"STOCK_ID\", unique = true, nullable = false)\n    public Integer getStockId() {\n        return this.stockId;\n    }\n  ...<\/code><\/pre>\n<p><\/p>\n<p>Das Modell ist mit intelligenten Annotationen ausgestattet, w\u00e4hrend im Hintergrund ein t\u00fcchtiger ORM Unmengen von SQL-Code generiert und ausf\u00fchrt. Es sei erw\u00e4hnt, dass Entwickler alles daran setzen, sich durch Kilometer von Abstraktionen von ihrer Datenbank abzugrenzen, was auf ein gewisses <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/1303231\/prichiny-nenavisti-k-yazyku-sql\">\"SQL-Diskriminierung\"<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Auf der anderen Seite der Barrikade betonen die Bef\u00fcrworter von purem \"handmade\"-SQL die M\u00f6glichkeit, die volle Leistung ihrer Datenbank ohne zus\u00e4tzliche Schichten und Abstraktionen auszusch\u00f6pfen. Infolgedessen entstehen \"data-centric\" Projekte, in denen speziell ausgebildete Personen (die auch als \"Datenbank-Spezialisten\", \"Datenbankentwickler\" oder \"Datenbankexperten\" bekannt sind) sich um die Datenbanken k\u00fcmmern, w\u00e4hrend die Entwickler lediglich vorbereitete Views und Stored Procedures nutzen, ohne sich mit den Details auseinanderzusetzen.<\/p>\n<p><\/p>\n<p>Was w\u00e4re, wenn wir das Beste aus beiden Welten kombinieren? So wie es mit dem wunderbaren Werkzeug mit dem lebensbejahenden Namen <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql\">Yesql<\/a><\/noindex>. Ich werde ein paar Zeilen aus dem allgemeinen Konzept in meiner freien \u00dcbersetzung anf\u00fchren; f\u00fcr detailliertere Informationen k\u00f6nnen Sie sich damit vertraut machen. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#rationale\">hier<\/a><\/noindex>.<\/p>\n<p><\/p>\n<blockquote><p>Clojure ist eine gro\u00dfartige Sprache zur Erstellung von DSLs, aber SQL ist bereits ein erstklassiger DSL und wir brauchen keinen weiteren. S-Ausdr\u00fccke sind wunderbar, aber hier bringen sie nichts Neues. Am Ende haben wir Klammern um der Klammern willen. Stimmen Sie nicht zu? Warten Sie den Moment ab, wenn die Abstraktion \u00fcber der Datenbank zu lecken beginnt und Sie in den Kampf mit der Funktion eintreten. <em>(raw-sql)<\/em><\/p>\n<p>Und was tun? Lassen Sie uns SQL einfach SQL sein \u2014 eine Datei pro Anfrage:<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"sql\">-- name: users-by-country\nselect *\n  from users\n where country_code = :country_code<\/code><\/pre>\n<p><\/p>\n<blockquote><p>\u2026 und dann lesen Sie diese Datei, indem Sie sie in eine regul\u00e4re Clojure-Funktion umwandeln:<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"lisp\">(defqueries \"some\/where\/users_by_country.sql\"\n   {:connection db-spec})\n\n;;; Eine Funktion mit dem Namen `users-by-country` wurde erstellt.\n;;; Lassen Sie uns diese verwenden:\n(users-by-country {:country_code \"GB\"})\n;=&gt; ({:name \"Kris\" :country_code \"GB\" ...} ...)<\/code><\/pre>\n<p><\/p>\n<blockquote><p>Wenn Sie nach dem Prinzip \"SQL separat, Clojure separat\" arbeiten, erhalten Sie:<\/p>\n<ul>\n<li>Keine syntaktischen \u00dcberraschungen. Ihre Datenbank (wie jede andere auch) entspricht nicht zu 100 % dem SQL-Standard \u2014 aber das ist f\u00fcr Yesql nicht wichtig. Sie werden niemals Zeit mit der Suche nach Funktionen mit dem syntaktischen \u00c4quivalent von SQL verschwenden. Sie m\u00fcssen niemals zur Funktion zur\u00fcckkehren. <em>(raw-sql \"some ('funky' :: SYNTAX)\"))<\/em>.<\/li>\n<li>Ausgezeichneter Support f\u00fcr den Editor. Ihr Editor bietet bereits hervorragende Unterst\u00fctzung f\u00fcr SQL. Indem Sie SQL als SQL speichern, k\u00f6nnen Sie es einfach verwenden.<\/li>\n<li>Teamkompatibilit\u00e4t. Ihre DBA k\u00f6nnen SQL lesen und schreiben, das in Ihrem Clojure-Projekt verwendet wird.<\/li>\n<li>Einfachere Leistungseinstellungen. M\u00fcssen Sie einen Plan f\u00fcr eine problematische Abfrage erstellen? Das ist kein Problem, wenn Ihre Abfrage einfaches SQL ist.<\/li>\n<li>Wiederverwendung von Abfragen. Ziehen Sie diese SQL-Dateien in andere Projekte, denn es ist einfach das gute alte SQL \u2013 teilen Sie es einfach.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>Ich finde die Idee wirklich gro\u00dfartig und gleichzeitig sehr einfach, wodurch das Projekt in vielerlei Hinsicht gewachsen ist. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#other-languages\">Nachfolgern<\/a><\/noindex> in ganz unterschiedlichen Sprachen. Wir werden versuchen, eine \u00e4hnliche Philosophie anzuwenden, indem wir SQL-Code von allem anderen deutlich abtrennen, weit \u00fcber ORM hinaus.<\/p>\n<p><\/p>\n<h5 id=\"ide--db-menedzhery\">IDE &amp; DB-Manager<\/h5>\n<p><\/p>\n<p>Beginnen wir mit einer einfachen allt\u00e4glichen Aufgabe. H\u00e4ufig m\u00fcssen wir in der Datenbank nach bestimmten Objekten suchen, zum Beispiel eine Tabelle im Schema finden und ihre Struktur untersuchen (welche Spalten, Schl\u00fcssel, Indizes, Einschr\u00e4nkungen usw. verwendet werden). Von jeder grafischen IDE oder einem grundlegenden DB-Manager erwarten wir in erster Linie diese F\u00e4higkeiten. Es sollte schnell gehen und wir sollten nicht eine halbe Stunde warten m\u00fcssen, bis ein Fenster mit den ben\u00f6tigten Informationen erscheint (insbesondere bei langsamen Verbindungen zu einer entfernten Datenbank), und die erhaltenen Informationen sollten frisch und aktuell sein und keine zwischengespeicherten alten Daten. Je komplexer und gr\u00f6\u00dfer die Datenbank ist und je mehr davon vorhanden sind, desto schwieriger wird es, dies zu bewerkstelligen.<\/p>\n<p><\/p>\n<p>Aber in der Regel lege ich die Maus beiseite und schreibe einfach den Code. Angenommen, ich m\u00f6chte herausfinden, welche Tabellen (und mit welchen Eigenschaften) im Schema \"HR\" enthalten sind. In den meisten DBMS kann man das gew\u00fcnschte Ergebnis mit dieser einfachen Abfrage aus information_schema erreichen:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Der Inhalt solcher Nachschlagetabellen variiert je nach den M\u00f6glichkeiten jeder Datenbank. Beispielsweise k\u00f6nnen spezifische f\u00fcr MySQL relevante Parameter dieser Tabelle aus demselben Nachschlagewerk abgerufen werden:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , storage_engine -- Verwendeter \"Engine\" (\"MyISAM\", \"InnoDB\" etc)\n     , row_format     -- Zeilenformat (\"Fixed\", \"Dynamic\" etc)\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Oracle hat kein information_schema, aber es hat <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Oracle_metadata\">Oracle-Metadaten<\/a><\/noindex>, und es treten keine gr\u00f6\u00dferen Probleme auf:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , pct_free       -- Mindestfreier Platz im Datenblock (%)\n     , pct_used       -- Mindestgenutzter Platz im Datenblock (%)\n     , last_analyzed  -- Datum der letzten Statistiksammlung\n     , ...\n  from all_tables\n where owner = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Das gilt auch f\u00fcr ClickHouse:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">W\u00e4hlen Sie den Namen\n     , Engine -- Der verwendete \"Engine\" (\"MergeTree\", \"Dictionary\" usw.)\n     , ...\n  aus system.tables\n wo die Datenbank = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>\u00c4hnliches kann auch in Cassandra gemacht werden (wo es Columnfamilien anstelle von Tabellen und Keyspaces anstelle von Schemata gibt):<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select columnfamily_name\n     , compaction_strategy_class  -- M\u00fcllabfuhrstrategie\n     , gc_grace_seconds           -- Lebensdauer von M\u00fcll\n     , ...\n  from system.schema_columnfamilies\n where keyspace_name = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>F\u00fcr die meisten anderen Datenbanken lassen sich ebenfalls \u00e4hnliche Abfragen konstruieren (sogar in Mongo gibt es <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/reference\/system-collections\/#%3Cdatabase%3E.system.namespaces\">eine spezielle Systemkollektion<\/a><\/noindex>, die Informationen zu allen Sammlungen im System enth\u00e4lt).<\/p>\n<p><\/p>\n<p>Nat\u00fcrlich kann man auf diese Weise Informationen nicht nur \u00fcber Tabellen, sondern \u00fcber jedes Objekt erhalten. Gelegentlich teilen nette Leute solchen Code f\u00fcr verschiedene Datenbanken, wie zum Beispiel in der Reihe von Hub-Artikel \"Funktionen zur Dokumentation von PostgreSQL-Datenbanken\" (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/415575\">ayb<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/415897\">ben<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/418597\">gym<\/a><\/noindex>). Nat\u00fcrlich ist es \"nicht so angenehm\", all diese Abfragen im Kopf zu behalten und st\u00e4ndig einzugeben, deshalb habe ich in meiner bevorzugten IDE\/Editor eine vorgefertigte Sammlung von Snippets f\u00fcr h\u00e4ufig verwendete Abfragen, und ich muss nur die Objektnamen in die Vorlage eingeben.<\/p>\n<p><\/p>\n<p>Infolgedessen ist diese Art der Navigation und Objektsuche viel flexibler, spart viel Zeit und erm\u00f6glicht es, genau die Informationen in der Form zu erhalten, die derzeit erforderlich ist (wie beispielsweise in dem Beitrag beschrieben, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/JetBrains\/blog\/342094\">\"Datenexport aus der Datenbank im beliebigen Format: Was IDEs auf der IntelliJ-Plattform k\u00f6nnen\"<\/a><\/noindex>).<\/p>\n<p><\/p>\n<h5 id=\"operacii-s-obektami\">Operationen mit Objekten<\/h5>\n<p><\/p>\n<p>Nachdem wir die ben\u00f6tigten Objekte gefunden und untersucht haben, ist es an der Zeit, etwas N\u00fctzliches damit zu tun. Nat\u00fcrlich, ohne die Finger von der Tastatur zu nehmen.<\/p>\n<p><\/p>\n<p>Es ist kein Geheimnis, dass das einfache L\u00f6schen einer Tabelle in fast allen Datenbanken gleich aussieht:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">drop table hr.persons<\/code><\/pre>\n<p><\/p>\n<p>Die Erstellung einer Tabelle ist schon spannender. Praktisch jedes DBMS (einschlie\u00dflich vieler NoSQL-Systeme) unterst\u00fctzt in irgendeiner Form 'create table', und der Hauptteil wird sich kaum unterscheiden (Name, Spaltenliste, Datentypen), aber die anderen Details k\u00f6nnen stark variieren und h\u00e4ngen von der internen Struktur und den M\u00f6glichkeiten des jeweiligen DBMS ab. Mein Lieblingsbeispiel \u2014 in der Oracle-Dokumentation gibt es nur die 'nackten' BNF-Regeln f\u00fcr die Syntax von 'create table'. <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/19\/sqlrf\/sql-language-reference.pdf\">Sie nehmen 31 Seiten in Anspruch.<\/a><\/noindex>Andere DBMS haben bescheidenere M\u00f6glichkeiten, aber jede von ihnen bietet ebenfalls viele interessante und einzigartige Funktionen zum Erstellen von Tabellen (<noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/sql-createtable.html\">postgres<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/create-table.html\">mysql<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.cockroachlabs.com\/docs\/stable\/create-table.html#expanded\">cockroach<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.datastax.com\/en\/cql\/3.3\/cql\/cql_reference\/cqlCreateTable.html\">cassandra<\/a><\/noindex>). Kaum ein grafischer 'Wizard' aus einer beliebigen IDE (besonders einer universellen) wird all diese F\u00e4higkeiten vollst\u00e4ndig abdecken k\u00f6nnen, und selbst wenn, wird es ein Anblick f\u00fcr die Nervenstarken sein. Gleichzeitig ist ein korrekt und rechtzeitig geschriebener Befehl <strong><em>create table<\/em><\/strong> es Ihnen erm\u00f6glichen, alle diese Funktionen m\u00fchelos zu nutzen und die Speicherung sowie den Zugriff auf Ihre Daten zuverl\u00e4ssig, optimal und so angenehm wie m\u00f6glich zu gestalten.<\/p>\n<p><\/p>\n<p>In vielen DBMS gibt es auch spezifische Objektarten, die in anderen DBMS fehlen. Dar\u00fcber hinaus k\u00f6nnen wir nicht nur Operationen an den Datenbankobjekten durchf\u00fchren, sondern auch an der Datenbank selbst, zum Beispiel einen Prozess 'terminieren', einen bestimmten Speicherbereich freigeben, das Tracing aktivieren, in den 'read only'-Modus wechseln und vieles mehr.<\/p>\n<p><\/p>\n<h5 id=\"a-teper-nemnogo-porisuem\">Jetzt lassen Sie uns ein wenig Zeichnen.<\/h5>\n<p><\/p>\n<p>Eine der h\u00e4ufigsten Aufgaben besteht darin, ein Diagramm mit Datenbankobjekten zu erstellen und auf einem ansprechenden Bild die Objekte und die Beziehungen zwischen ihnen zu sehen. Das kann praktisch jede grafische IDE, einige \u201eCommand-Line\u201c-Hilfsprogramme, spezialisierte grafische Tools und Modellierungsanwendungen. Diese zeichnen Ihnen etwas \u201ewie sie k\u00f6nnen\u201c, und ein wenig Einfluss auf diesen Prozess hat man nur durch einige Parameter in der Konfigurationsdatei oder durch Optionen in der Benutzeroberfl\u00e4che.<\/p>\n<p><\/p>\n<p>Aber dieses Problem kann viel einfacher, flexibler und eleganter gel\u00f6st werden \u2014 und nat\u00fcrlich mit Hilfe von Code. F\u00fcr die Erstellung von Diagrammen jeder Komplexit\u00e4t haben wir mehrere spezialisierte Auszeichnungssprachen (DOT, GraphML usw.), sowie eine Vielzahl von Anwendungen (GraphViz, PlantUML, Mermaid), die diese Anweisungen lesen und in den unterschiedlichsten Formaten visualisieren k\u00f6nnen. Informationen \u00fcber Objekte und ihre Beziehungen wissen wir bereits abzurufen.<\/p>\n<p><\/p>\n<p>Hier ist ein kleines Beispiel, wie das aussehen k\u00f6nnte, unter Verwendung von PlantUML und <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/316428\/\">einer Demodatenbank f\u00fcr PostgreSQL.<\/a><\/noindex> (links der SQL-Befehl, der die ben\u00f6tigte Anweisung f\u00fcr PlantUML generiert, und rechts das Ergebnis):<\/p>\n<p>\n<img decoding=\"async\" alt=\"\u201eDatenbank als Code\u201c Erfahrung\" src=\"\/wp-content\/uploads\/2020\/06\/c5cb2a138df1527abe47cbf8d695cb36.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<pre><code class=\"sql\">select '@startuml'||chr(10)||'hide methods'||chr(10)||'hide stereotypes' union all\nselect distinct ccu.table_name || ' --|&gt; ' ||\n       tc.table_name as val\n  from table_constraints as tc\n  join key_column_usage as kcu\n    on tc.constraint_name = kcu.constraint_name\n  join constraint_column_usage as ccu\n    on ccu.constraint_name = tc.constraint_name\n where tc.constraint_type = 'FOREIGN KEY'\n   and tc.table_name ~ '.*' union all\nselect '@enduml'<\/code><\/pre>\n<p><\/p>\n<p>Wenn man sich ein wenig anstrengt, kann man auf Basis <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/QuantumGhost\/0955a45383a0b6c0bc24f9654b3cb561\">der ER-Vorlage f\u00fcr PlantUML<\/a><\/noindex> etwas schaffen, das einer echten ER-Diagramm sehr \u00e4hnlich sieht:<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">Der SQL-Befehl ist ein wenig komplizierter.<\/b><\/p>\n<pre><code class=\"sql\">-- Kopf\nselect &#039;@startuml\n        !define Table(name,desc) class name as &quot;desc&quot; &lt;&lt; (T,#FFAAAA) &gt;&amp;gt;\n        !define primary_key(x) &lt;b&gt;x&lt;\/b&gt;\n        !define unique(x) &lt;color:green&gt;x&lt;\/color&gt;\n        !define not_null(x) &lt;u&gt;x&lt;\/u&gt;\n        hide methods\n        hide stereotypes&#039;\n union all\n-- Tabellen\nselect format(&#039;Table(%s, &quot;%s n Informationen &uuml;ber %s&quot;) {&#039;||chr(10), table_name, table_name, table_name) ||\n       (select string_agg(column_name || &#039; &#039; || upper(udt_name), chr(10))\n          from information_schema.columns\n         where table_schema = &#039;public&#039;\n           and table_name = t.table_name) || chr(10) || &#039;}&#039;\n  from information_schema.tables t\n where table_schema = &#039;public&#039;\n union all\n-- Beziehungen zwischen Tabellen\nselect distinct ccu.table_name || &#039; &quot;1&quot; --&amp;gt; &quot;0..N&quot; &#039; || tc.table_name || format(&#039; : &quot;Ein %s kann viele %s haben&quot;&#039;, ccu.table_name, tc.table_name)\n  from information_schema.table_constraints as tc\n  join information_schema.key_column_usage as kcu on tc.constraint_name = kcu.constraint_name\n  join information_schema.constraint_column_usage as ccu on ccu.constraint_name = tc.constraint_name\n where tc.constraint_type = &#039;FOREIGN KEY&#039;\n   and ccu.constraint_schema = &#039;public&#039;\n   and tc.table_name ~ &#039;.*&#039;\n union all\n-- Fu&szlig;zeile\nselect &#039;@enduml&#039;<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"\u201eDatenbank als Code\u201c Erfahrung\" src=\"\/wp-content\/uploads\/2020\/06\/bd45420a4fd1bdfcf20cbe74a0638c7b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Wenn man genauer hinsieht, verwenden viele Visualisierungstools im Grunde \u00e4hnliche Abfragen. Diese Abfragen sind allerdings meistens tief <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgmodeler\/pgmodeler\/blob\/9c615c0b0871df3cd649983ce61e802b0ff0137b\/schemas\/catalog\/table.sch\">im Code der Anwendung selbst verankert und schwer verst\u00e4ndlich<\/a><\/noindex>, ganz zu schweigen von jeglicher Modifikation.<\/p>\n<p><\/p>\n<h5 id=\"metriki-i-monitoring\">Metriken und \u00dcberwachung<\/h5>\n<p><\/p>\n<p>Kommen wir zu einem traditionell komplexen Thema \u2013 der \u00dcberwachung der Datenbankleistung. Ich erinnere mich an eine kleine wahre Geschichte, die mir \"ein Freund von mir\" erz\u00e4hlt hat. In einem Projekt gab es einen m\u00e4chtigen DBA, den nur wenige Entwickler pers\u00f6nlich kannten, und von dem auch kaum jemand je das Gesicht gesehen hatte (obwohl man h\u00f6rte, dass er irgendwo im benachbarten Geb\u00e4ude arbeitete). Zum \"X-Zeitpunkt\", als das Produktionssystem eines gro\u00dfen Einzelh\u00e4ndlers wieder einmal \"schlecht lief\", schickte er stillschweigend Screenshots von Diagrammen aus dem Oracle Enterprise Manager, in denen er die kritischen Stellen zur \"Verst\u00e4ndlichkeit\" mit einem roten Marker hervorgehoben hatte (was, milde ausgedr\u00fcckt, wenig half). Und anhand dieses \"Bildes\" musste man die Probleme beheben. Niemand hatte jedoch Zugriff auf den kostbaren (in doppeltem Sinne) Enterprise Manager, da das System kompliziert und teuer war; man wollte nicht, dass die \"Entwickler irgendetwas durcheinanderbringen und alles kaputt machen\". Daher fanden die Entwickler auf \"empirischem\" Weg die Ursachen f\u00fcr die Verz\u00f6gerungen und ver\u00f6ffentlichten ein Patch. Wenn das ernste Schreiben des DBA nicht innerhalb kurzer Zeit erneut eintraf, atmeten alle erleichtert auf und kehrten zu ihren aktuellen Aufgaben zur\u00fcck (bis zum n\u00e4chsten Schreiben).<\/p>\n<p><\/p>\n<p>Der \u00dcberwachungsprozess kann jedoch freundlicher und einladender gestaltet werden, vor allem aber f\u00fcr alle zug\u00e4nglich und transparent. Zumindest der grundlegende Teil, als Erg\u00e4nzung zu den Haupt\u00fcberwachungssystemen, die zweifellos n\u00fctzlich und in vielen F\u00e4llen unverzichtbar sind. Jede Datenbank kann problemlos und kostenlos Informationen \u00fcber ihren aktuellen Zustand und ihre Leistung bereitstellen. In der \u201eblutigen\u201c Oracle DB kann nahezu jede Leistungsinformation aus den systemeigenen Ansichten abgerufen werden, angefangen bei Prozessen und Sitzungen bis hin zum Status des Zwischenspeicherpuffers. <noindex><a rel=\"nofollow\" href=\"https:\/\/oracle-base.com\/dba\/scripts\">DBA-Skripte<\/a><\/noindex>, Abschnitt \"Monitoring\". In Postgresql gibt es ebenfalls eine Vielzahl von systemeigenen Ansichten f\u00fcr <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html\">\u00dcberwachung der Datenbank<\/a><\/noindex>, insbesondere solche, die im Alltag eines jeden DBA unverzichtbar sind, wie <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html#PG-STAT-ACTIVITY-VIEW\">pg_stat_activity<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html#PG-STAT-DATABASE-VIEW\">pg_stat_database<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html#PG-STAT-BGWRITER-VIEW\">pg_stat_bgwriter<\/a><\/noindex>. In MySQL gibt es sogar ein separates Schema daf\u00fcr, <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/performance-schema-table-descriptions.html\">performance_schema<\/a><\/noindex>. In MongoDB aggregiert der eingebaute <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/\">Profiler<\/a><\/noindex> Leistungsdaten in einer systemischen Sammlung, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/#view-profiler-data\">system.profile<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>So kann man, ausgestattet mit einem beliebigen Metrik-Sammler (Telegraf, Metricbeat, Collectd), der in der Lage ist, benutzerdefinierte SQL-Abfragen auszuf\u00fchren, einem Speicher f\u00fcr diese Metriken (InfluxDB, Elasticsearch, Timescaledb) und einem Visualisierungswerkzeug (Grafana, Kibana), ein relativ einfaches und flexibles \u00dcberwachungssystem erhalten, das eng mit anderen allgemeinen Systemmetriken (z. B. von Anwendungsservern, Betriebssystemen usw. erhalten) integriert ist. Wie es beispielsweise in pgwatch2 umgesetzt ist, wo die Kombination InfluxDB + Grafana verwendet wird und eine Reihe von Abfragen an systemische Ansichten, zu denen auch benutzerdefinierte Abfragen hinzugef\u00fcgt werden k\u00f6nnen, erfolgt. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/cybertec-postgresql\/pgwatch2#adding-metrics\">benutzerdefinierte Abfragen hinzuf\u00fcgen<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"itogo\">Gesamt<\/h2>\n<p><\/p>\n<p>Und das ist nur eine ungef\u00e4hre Liste dessen, was man mit unserer Datenbank durch gew\u00f6hnlichen SQL-Code machen kann. Ich bin sicher, dass es noch viele weitere Anwendungsm\u00f6glichkeiten gibt, also hinterlasst eure Kommentare. \u00dcber das Automatisieren dieser Prozesse und deren Integration in euren CI\/CD-Pipeline werden wir beim n\u00e4chsten Mal sprechen.<\/p>\n<p>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/426833\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435? \u041a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u2014 \u043d\u0430\u0431\u0438\u0440\u0430\u0435\u043c select, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043b\u043e\u043d\u043a\u0438, \u0437\u0430\u0442\u0435\u043c from, \u0438\u043c\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432 where \u0438 \u0432\u0441\u0435 \u2014 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0443 \u043d\u0430\u0441 \u0432 \u043a\u0430\u0440\u043c\u0430\u043d\u0435, \u043f\u0440\u0438\u0447\u0435\u043c (\u043f\u043e\u0447\u0442\u0438) \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e \u043a\u0430\u043a\u0430\u044f \u0421\u0423\u0411\u0414 \u0432 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c (\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0421\u0423\u0411\u0414 \u0432\u043e\u0432\u0441\u0435). \u0412 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":83650,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-83649","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435? \u041a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u2014 \u043d\u0430\u0431\u0438\u0440\u0430\u0435\u043c select, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043b\u043e\u043d\u043a\u0438, \u0437\u0430\u0442\u0435\u043c from, \u0438\u043c\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432 where \u0438 \u0432\u0441\u0435 \u2014 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0443 \u043d\u0430\u0441 \u0432 \u043a\u0430\u0440\u043c\u0430\u043d\u0435, \u043f\u0440\u0438\u0447\u0435\u043c (\u043f\u043e\u0447\u0442\u0438) \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e \u043a\u0430\u043a\u0430\u044f \u0421\u0423\u0411\u0414 \u0432 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c (\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0421\u0423\u0411\u0414 \u0432\u043e\u0432\u0441\u0435). \u0412\" \/>\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\/de\/blog\/administrirovanie\/database-as-sode-experience\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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\u00abDatabase as \u0421ode\u00bb Experience | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435? \u041a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u2014 \u043d\u0430\u0431\u0438\u0440\u0430\u0435\u043c select, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043b\u043e\u043d\u043a\u0438, \u0437\u0430\u0442\u0435\u043c from, \u0438\u043c\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432 where \u0438 \u0432\u0441\u0435 \u2014 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0443 \u043d\u0430\u0441 \u0432 \u043a\u0430\u0440\u043c\u0430\u043d\u0435, \u043f\u0440\u0438\u0447\u0435\u043c (\u043f\u043e\u0447\u0442\u0438) \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e \u043a\u0430\u043a\u0430\u044f \u0421\u0423\u0411\u0414 \u0432 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c (\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0421\u0423\u0411\u0414 \u0432\u043e\u0432\u0441\u0435). \u0412\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/database-as-sode-experience\" \/>\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-06-02T05:42:21+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-06-02T05:42:21+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\udd47\u201eDatenbank als Code\u201c Erfahrung | ProHoster","description":"SQL, was k\u00f6nnte einfacher sein? Jeder von uns kann eine einfache Abfrage schreiben \u2013 wir tippen select, nennen die notwendigen Spalten, dann from, den Tabellennamen, f\u00fcgen ein paar Bedingungen in where hinzu, und voil\u00e0 \u2013 n\u00fctzliche Daten sind in unserer Tasche, und das (fast) unabh\u00e4ngig davon, welche DBMS gerade im Hintergrund arbeitet (oder vielleicht ist es \u00fcberhaupt kein DBMS). In","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/database-as-sode-experience","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","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\u00abDatabase as \u0421ode\u00bb Experience | ProHoster","og:description":"SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435? \u041a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u2014 \u043d\u0430\u0431\u0438\u0440\u0430\u0435\u043c select, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043b\u043e\u043d\u043a\u0438, \u0437\u0430\u0442\u0435\u043c from, \u0438\u043c\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432 where \u0438 \u0432\u0441\u0435 \u2014 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0443 \u043d\u0430\u0441 \u0432 \u043a\u0430\u0440\u043c\u0430\u043d\u0435, \u043f\u0440\u0438\u0447\u0435\u043c (\u043f\u043e\u0447\u0442\u0438) \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e \u043a\u0430\u043a\u0430\u044f \u0421\u0423\u0411\u0414 \u0432 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c (\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0421\u0423\u0411\u0414 \u0432\u043e\u0432\u0441\u0435). \u0412","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/database-as-sode-experience","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-06-02T05:42:21+00:00","article:modified_time":"2020-06-02T05:42:21+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"83649","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 15:13:28","updated":"2022-10-02 10:23:46"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/83649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=83649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/83649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/83650"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=83649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=83649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=83649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}