{"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\/es\/blog\/administrirovanie\/database-as-sode-experience","title":{"rendered":"Experiencia de \u00abDatabase as Code\u00bb","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Experiencia de \u00abDatabase as Code\u00bb\" src=\"\/wp-content\/uploads\/2020\/06\/a1ac23deeded97559fbe787ed09184a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>SQL, \u00bfqu\u00e9 puede ser m\u00e1s sencillo? Todos nosotros podemos escribir una consulta simple: escribimos <strong><em>select<\/em><\/strong>, enumeramos las columnas necesarias, luego <strong><em>from<\/em><\/strong>, el nombre de la tabla, un poco de condiciones en <strong><em>donde<\/em><\/strong> y voil\u00e0, tenemos datos \u00fatiles en nuestras manos, casi independientemente de qu\u00e9 sistema de gesti\u00f3n de bases de datos est\u00e9 en funcionamiento (o puede que no sea una <noindex><a rel=\"nofollow\" href=\"https:\/\/osquery.io\/\">base de datos en absoluto<\/a><\/noindex>). Como resultado, se puede considerar el trabajo con pr\u00e1cticamente cualquier fuente de datos (relacional y no tan relacional) desde la perspectiva del c\u00f3digo normal (con todas las implicaciones: control de versiones, revisi\u00f3n de c\u00f3digo, an\u00e1lisis est\u00e1tico, pruebas autom\u00e1ticas y todo eso). Y esto se aplica no solo a los propios datos, esquemas y migraciones, sino a toda la actividad del almacenamiento. En este art\u00edculo, hablaremos sobre las tareas cotidianas y los problemas al trabajar con diversas bases de datos bajo la perspectiva de &quot;la base de datos como c\u00f3digo&quot;.<\/p>\n<p><\/p>\n<p>Y comenzaremos justo con <noindex><a rel=\"nofollow\" href=\"https:\/\/www.yegor256.com\/2014\/12\/01\/orm-offensive-anti-pattern.html\">ORM<\/a><\/noindex>. Las primeras batallas del tipo &quot;SQL vs ORM&quot; se observaron ya en <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/904343\/orm-vs-sql\">la antigua Rus<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h5 id=\"obektno-relyacionnyy-maping\">Mapeo objeto-relacional<\/h5>\n<p><\/p>\n<p>Los defensores de ORM valoran tradicionalmente la velocidad y la simplicidad en el desarrollo, la independencia del sistema de gesti\u00f3n de bases de datos y la limpieza del c\u00f3digo. Para muchos de nosotros, el c\u00f3digo que trabaja con la base de datos (y a menudo la propia base de datos)<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">generalmente se ve algo as\u00ed\u2026<\/b><\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = &quot;stock&quot;, catalog = &quot;maindb&quot;, uniqueConstraints = {\n        @UniqueConstraint(columnNames = &quot;STOCK_NAME&quot;),\n        @UniqueConstraint(columnNames = &quot;STOCK_CODE&quot;) })\npublic class Stock implements java.io.Serializable {\n\n    @Id\n    @GeneratedValue(strategy = IDENTITY)\n    @Column(name = &quot;STOCK_ID&quot;, unique = true, nullable = false)\n    public Integer getStockId() {\n        return this.stockId;\n    }\n  ...<\/code><\/pre>\n<p><\/p>\n<p>El modelo est\u00e1 adornado con inteligentes anotaciones, y en alg\u00fan lugar detr\u00e1s de escena, el valiente ORM genera y ejecuta toneladas de c\u00f3digo SQL. Cabe mencionar que los desarrolladores est\u00e1n tratando por todos los medios de aislarse de su base de datos con kil\u00f3metros de abstracciones, lo que indica una cierta <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/1303231\/prichiny-nenavisti-k-yazyku-sql\">&quot;odio SQL&quot;<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Al otro lado de las barricadas, los defensores del puro &quot;handmade&quot;-SQL destacan la posibilidad de exprimir al m\u00e1ximo su SGBD sin capas adicionales ni abstracciones. Como resultado, surgen proyectos &quot;centrados en los datos&quot;, donde la base de datos es manejada por personas especialmente capacitadas (los mismos &quot;database guys&quot;, tambi\u00e9n conocidos como &quot;db admins&quot;, &quot;data managers&quot;, etc.), y a los desarrolladores solo les queda &quot;tirar&quot; de vistas y procedimientos almacenados existentes, sin adentrarse en los detalles.<\/p>\n<p><\/p>\n<p>\u00bfY si tomamos lo mejor de ambos mundos? Como se hace en la maravillosa herramienta con un nombre alentador <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql\">Yesql<\/a><\/noindex>. Citar\u00e9 un par de l\u00edneas de la concepci\u00f3n general en mi libre traducci\u00f3n, y se puede conocer m\u00e1s a fondo. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#rationale\">aqu\u00ed<\/a><\/noindex>.<\/p>\n<p><\/p>\n<blockquote><p>Clojure es un gran lenguaje para crear DSLs, pero SQL ya es en s\u00ed un gran DSL, y no necesitamos otro. Las expresiones S son geniales, pero aqu\u00ed no aportan nada nuevo. Al final, tenemos par\u00e9ntesis por el simple hecho de tener par\u00e9ntesis. \u00bfNo est\u00e1n de acuerdo? Entonces esperen el momento en que la abstracci\u00f3n sobre la base de datos empiece a fallar, y comenzar\u00e1n la lucha con la funci\u00f3n. <em>(raw-sql)<\/em><\/p>\n<p>\u00bfY qu\u00e9 hacer? Dejemos el SQL como SQL normal: un archivo por cada consulta:<\/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 y luego lee este archivo, convirti\u00e9ndolo en una funci\u00f3n normal de Clojure:<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"lisp\">(defqueries &quot;some\/where\/users_by_country.sql&quot;\n   {:connection db-spec})\n\n;;; Se ha creado una funci\u00f3n con el nombre `users-by-country`.\n;;; Usemosla:\n(users-by-country {:country_code &quot;GB&quot;})\n;=&gt; ({:name &quot;Kris&quot; :country_code &quot;GB&quot; ...} ...)<\/code><\/pre>\n<p><\/p>\n<blockquote><p>Siguiendo el principio de &quot;SQL por un lado, Clojure por el otro&quot;, obtienes:<\/p>\n<ul>\n<li>Sin sorpresas sint\u00e1cticas. Tu base de datos (como cualquier otra) no cumple al 100% con el est\u00e1ndar SQL \u2014 pero para Yesql eso no importa. Nunca perder\u00e1s tiempo buscando funciones con una sintaxis equivalente a SQL. Nunca tendr\u00e1s que regresar a la funci\u00f3n <em>(raw-sql &quot;some (&#8216;funky&#8217; :: SYNTAX)&quot;))<\/em>.<\/li>\n<li>El mejor soporte del editor. Tu editor ya tiene un excelente soporte para SQL. Al mantener SQL como SQL, simplemente puedes usarlo.<\/li>\n<li>Compatibilidad del equipo. Tus DBA pueden leer y escribir SQL, que utilizas en tu proyecto de Clojure.<\/li>\n<li>Configuraci\u00f3n de rendimiento m\u00e1s simple. \u00bfNecesitas crear un plan para una consulta problem\u00e1tica? No hay problema, cuando tu consulta es solo SQL normal.<\/li>\n<li>Reutilizaci\u00f3n de consultas. Lleva esos mismos archivos SQL a otros proyectos, porque es solo el viejo y confiable SQL \u2014 simplemente comp\u00e1rtelo.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>Para m\u00ed, la idea es muy genial y a la vez muy simple, lo que ha permitido que el proyecto gane mucho. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#other-languages\">seguidores.<\/a><\/noindex> en una variedad de lenguajes. Y a continuaci\u00f3n intentaremos aplicar una filosof\u00eda similar de separaci\u00f3n del c\u00f3digo SQL de todo lo dem\u00e1s, lejos de ORM.<\/p>\n<p><\/p>\n<h5 id=\"ide--db-menedzhery\">IDE &amp; DB-gestores<\/h5>\n<p><\/p>\n<p>Comencemos con una tarea diaria simple. A menudo tenemos que buscar ciertos objetos en la base de datos, por ejemplo, encontrar una tabla en un esquema y examinar su estructura (qu\u00e9 columnas, claves, \u00edndices, restricciones y dem\u00e1s se utilizan). Y de cualquier IDE gr\u00e1fico o de un DB-manager decente, en primer lugar, esperamos precisamente estas capacidades. Para que sea r\u00e1pido y no tengamos que esperar media hora hasta que se dibuje la ventana con la informaci\u00f3n necesaria (especialmente con una conexi\u00f3n lenta a la base de datos remota), y adem\u00e1s, que la informaci\u00f3n obtenida sea fresca y actual, y no un viejo cach\u00e9. Cuanto m\u00e1s compleja y grande es la base de datos y m\u00e1s numerosas son, m\u00e1s dif\u00edcil se vuelve este proceso.<\/p>\n<p><\/p>\n<p>Pero generalmente abandono el rat\u00f3n y simplemente escribo c\u00f3digo. Supongamos que necesitamos saber qu\u00e9 tablas (y con qu\u00e9 propiedades) est\u00e1n contenidas en el esquema \"HR\". En la mayor\u00eda de los sistemas de bases de datos, se puede lograr el resultado deseado con una sencilla consulta de information_schema:<\/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>De base de datos a base de datos, el contenido de estas tablas de referencia var\u00eda dependiendo de las capacidades de cada sistema de gesti\u00f3n de bases de datos. Y, por ejemplo, para MySQL, de este mismo diccionario se pueden obtener par\u00e1metros espec\u00edficos para esta base de datos:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , storage_engine -- Motor utilizado (\"MyISAM\", \"InnoDB\" etc)\n     , row_format     -- Formato de fila (\"Fixed\", \"Dynamic\" etc)\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Oracle no tiene information_schema, pero tiene <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Oracle_metadata\">Oracle metadata<\/a><\/noindex>, y no surgen grandes problemas:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , pct_free       -- M\u00ednimo espacio libre en el bloque de datos (%)\n     , pct_used       -- M\u00ednimo espacio utilizado en el bloque de datos (%)\n     , last_analyzed  -- Fecha del \u00faltimo an\u00e1lisis estad\u00edstico\n     , ...\n  from all_tables\n where owner = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>ClickHouse no es una excepci\u00f3n:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select name\n     , engine -- Motor utilizado (\"MergeTree\", \"Dictionary\" etc)\n     , ...\n  from system.tables\n where database = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Algo similar se puede hacer en Cassandra (donde hay columnfamilies en lugar de tablas y keyspaces en lugar de esquemas):<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select columnfamily_name\n     , compaction_strategy_class  -- Estrategia de compactaci\u00f3n\n     , gc_grace_seconds           -- Tiempo de vida del basura\n     , ...\n  from system.schema_columnfamilies\n where keyspace_name = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Para la mayor\u00eda de las dem\u00e1s bases de datos, tambi\u00e9n se pueden idear consultas similares (incluso en Mongo hay <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/reference\/system-collections\/#%3Cdatabase%3E.system.namespaces\">una colecci\u00f3n del sistema especial<\/a><\/noindex>, que contiene informaci\u00f3n sobre todas las colecciones en el sistema).<\/p>\n<p><\/p>\n<p>Por supuesto, de esta manera se puede obtener informaci\u00f3n no solo sobre tablas, sino sobre cualquier objeto. Peri\u00f3dicamente, personas amables comparten tal c\u00f3digo para diferentes bases de datos, como en la serie de art\u00edculos de Habr \"Funciones para documentar bases de datos PostgreSQL\" (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/415575\">aib<\/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\">him<\/a><\/noindex>). Por supuesto, mantener toda esta monta\u00f1a de consultas en la cabeza y escribirlas constantemente no es un placer, por lo que en mi IDE\/editor favorito tengo un conjunto de snippets predefinidos para consultas que uso con frecuencia, y solo queda introducir los nombres de los objetos en la plantilla.<\/p>\n<p><\/p>\n<p>Al final, este m\u00e9todo de navegaci\u00f3n y b\u00fasqueda de objetos es mucho m\u00e1s flexible, ahorra mucho tiempo y permite obtener exactamente la informaci\u00f3n en el formato necesario (como se describe, por ejemplo, en la publicaci\u00f3n <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/JetBrains\/blog\/342094\">\"Exportar datos de la base de datos en cualquier formato: lo que pueden hacer las IDE en la plataforma IntelliJ\"<\/a><\/noindex>).<\/p>\n<p><\/p>\n<h5 id=\"operacii-s-obektami\">Operaciones con objetos<\/h5>\n<p><\/p>\n<p>Despu\u00e9s de encontrar y estudiar los objetos necesarios, es hora de hacer algo \u00fatil con ellos. Por supuesto, sin despegar los dedos del teclado.<\/p>\n<p><\/p>\n<p>No es un secreto que la simple eliminaci\u00f3n de una tabla se ver\u00e1 igual casi en todas las bases de datos:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">drop table hr.persons<\/code><\/pre>\n<p><\/p>\n<p>La creaci\u00f3n de una tabla es un tema m\u00e1s interesante. Pr\u00e1cticamente cualquier SGBD (incluidos muchos NoSQL) sabe hacer \"create table\" de alguna manera, y la mayor parte de esta funci\u00f3n no difiere mucho (nombre, lista de columnas, tipos de datos), pero los otros detalles pueden diferir dr\u00e1sticamente y dependen de la arquitectura interna y las capacidades del SGBD espec\u00edfico. Mi ejemplo favorito es que en la documentaci\u00f3n de Oracle solo hay \"BNF desnudos\" para la sintaxis de \"create table\". <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/19\/sqlrf\/sql-language-reference.pdf\">ocupan 31 p\u00e1ginas<\/a><\/noindex>. Otros SGBD tienen capacidades m\u00e1s modestas, pero cada uno tambi\u00e9n tiene muchas caracter\u00edsticas interesantes y \u00fanicas para la creaci\u00f3n de tablas (<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>). Es poco probable que alg\u00fan \"asistente\" gr\u00e1fico de otra IDE (especialmente una universal) pueda cubrir completamente todas estas capacidades, y si lo logra, ser\u00e1 un espect\u00e1culo no apto para nerviosos. Al mismo tiempo, un operador bien escrito y a tiempo <strong><em>create table<\/em><\/strong> permitir\u00e1 aprovechar todas ellas sin dificultades, haciendo que el almacenamiento y el acceso a tus datos sean fiables, \u00f3ptimos y lo m\u00e1s c\u00f3modos posible.<\/p>\n<p><\/p>\n<p>Tambi\u00e9n en muchos SGBD existen tipos de objetos espec\u00edficos que no est\u00e1n presentes en otros SGBD. Adem\u00e1s, podemos realizar operaciones no solo sobre los objetos de la base de datos, sino tambi\u00e9n sobre el mismo SGBD, por ejemplo, \"matar\" un proceso, liberar una cierta \u00e1rea de memoria, habilitar el seguimiento, cambiar a modo \"solo lectura\" y mucho m\u00e1s.<\/p>\n<p><\/p>\n<h5 id=\"a-teper-nemnogo-porisuem\">Ahora vamos a dibujar un poco<\/h5>\n<p><\/p>\n<p>Una de las tareas m\u00e1s comunes es construir un diagrama con los objetos de la base de datos, para ver de forma atractiva los objetos y las relaciones entre ellos. Casi cualquier IDE gr\u00e1fica, algunas utilidades de l\u00ednea de comandos, herramientas gr\u00e1ficas especializadas y modeladores pueden hacerlo. Te dibujar\u00e1n algo \"como pueden\", y puedes influir un poco en este proceso solo mediante algunos par\u00e1metros en el archivo de configuraci\u00f3n o usando las casillas en la interfaz.<\/p>\n<p><\/p>\n<p>Pero este problema se puede resolver de manera mucho m\u00e1s simple, flexible y elegante, y, por supuesto, utilizando c\u00f3digo. Para la construcci\u00f3n de diagramas de cualquier complejidad, tenemos varios lenguajes de marcado especializados (DOT, GraphML, etc.), a los que se les suman m\u00faltiples aplicaciones (GraphViz, PlantUML, Mermaid) que pueden leer tales instrucciones y visualizarlas en diversos formatos. Y ya sabemos c\u00f3mo obtener la informaci\u00f3n sobre los objetos y las relaciones entre ellos.<\/p>\n<p><\/p>\n<p>Proporcionemos un peque\u00f1o ejemplo de c\u00f3mo podr\u00eda verse esto, utilizando PlantUML y <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/316428\/\">una base de datos de demostraci\u00f3n para PostgreSQL<\/a><\/noindex> (a la izquierda la consulta SQL que genera la instrucci\u00f3n necesaria para PlantUML, y a la derecha el resultado):<\/p>\n<p>\n<img decoding=\"async\" alt=\"Experiencia de \u00abDatabase as Code\u00bb\" 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>Y si te esfuerzas un poco, a partir de <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/QuantumGhost\/0955a45383a0b6c0bc24f9654b3cb561\">la plantilla ER para PlantUML<\/a><\/noindex> puedes obtener algo que se asemeje bastante a un verdadero diagrama ER:<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">La consulta SQL es un poco m\u00e1s compleja<\/b><\/p>\n<pre><code class=\"sql\">-- Encabezado\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-- Tablas\nselect format(&#039;Table(%s, &quot;%s n informaci&oacute;n sobre %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-- Relaciones entre tablas\nselect distinct ccu.table_name || &#039; &quot;1&quot; --&amp;gt; &quot;0..N&quot; &#039; || tc.table_name || format(&#039; : &quot;Un %s puede tener muchos %s&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-- Pie\nselect &#039;@enduml&#039;<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"Experiencia de \u00abDatabase as Code\u00bb\" src=\"\/wp-content\/uploads\/2020\/06\/bd45420a4fd1bdfcf20cbe74a0638c7b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Si observas detenidamente, muchos de los herramientas visualizadoras utilizan consultas similares en su funcionamiento. Sin embargo, estas consultas generalmente est\u00e1n profundamente <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgmodeler\/pgmodeler\/blob\/9c615c0b0871df3cd649983ce61e802b0ff0137b\/schemas\/catalog\/table.sch\">\"encriptados\" en el c\u00f3digo de la propia aplicaci\u00f3n y son dif\u00edciles de entender.<\/a><\/noindex>, sin mencionar cualquier tipo de modificaci\u00f3n de las mismas.<\/p>\n<p><\/p>\n<h5 id=\"metriki-i-monitoring\">M\u00e9tricas y monitoreo<\/h5>\n<p><\/p>\n<p>Pasemos a un tema tradicionalmente complicado: el monitoreo del rendimiento de bases de datos. Recuerdo una peque\u00f1a historia real, contada por \"un amigo m\u00edo\". En un proyecto anterior, hab\u00eda un poderoso DBA, y pocos desarrolladores lo conoc\u00edan personalmente, ni siquiera lo hab\u00edan visto alguna vez (a pesar de que, seg\u00fan rumores, trabajaba en alg\u00fan lugar de la oficina cercana). A la hora \"X\", cuando el sistema de producci\u00f3n de un gran minorista comenzaba a \"sentirse mal\" de nuevo, \u00e9l silenciosamente enviaba capturas de pantalla de gr\u00e1ficos del Oracle Enterprise Manager, donde destacaba cuidadosamente los puntos cr\u00edticos con un marcador rojo para \"mayor claridad\" (lo cual, si se me permite decirlo, ayudaba muy poco). Y as\u00ed, con esta \"fotograf\u00eda\", era necesario resolver los problemas. Adem\u00e1s, nadie ten\u00eda acceso al valioso (en ambos sentidos de la palabra) Enterprise Manager, porque el sistema era complejo y costoso, por si acaso los \"desarrolladores romp\u00edan algo por accidente\". As\u00ed que los desarrolladores encontraban el lugar y la causa de los retrasos mediante m\u00e9todos \"emp\u00edricos\" y lanzaban un parche. Si no llegaba otra carta amenazante del DBA en poco tiempo, todos respiraban aliviados y volv\u00edan a sus tareas actuales (hasta la nueva carta).<\/p>\n<p><\/p>\n<p>Pero el proceso de monitoreo puede ser m\u00e1s divertido y amigable, y lo m\u00e1s importante, accesible y transparente para todos. Al menos su parte b\u00e1sica, como complemento a los sistemas de monitoreo principales (que son sin duda \u00fatiles y en muchos casos indispensables). Cualquier SGBD est\u00e1 lista para compartir informaci\u00f3n sobre su estado actual y rendimiento de forma totalmente gratuita. En la misma y \"sangrienta\" Oracle DB, pr\u00e1cticamente cualquier informaci\u00f3n sobre rendimiento se puede obtener de las vistas del sistema, desde procesos y sesiones hasta el estado de la cach\u00e9 de b\u00fafer (por ejemplo, <noindex><a rel=\"nofollow\" href=\"https:\/\/oracle-base.com\/dba\/scripts\">Scripts de DBA<\/a><\/noindex>, secci\u00f3n \"Monitoreo\"). En PostgreSQL tambi\u00e9n hay una gran cantidad de vistas del sistema para <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html\">monitoreo del funcionamiento de bases de datos<\/a><\/noindex>, en particular, aquellas que son indispensables en la vida cotidiana de cualquier DBA, como <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>. En MySQL, hay incluso un esquema separado destinado a esto, <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/performance-schema-table-descriptions.html\">performance_schema<\/a><\/noindex>. Y en Mongo, un <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/\">profiler<\/a><\/noindex> agrega datos sobre el rendimiento en una colecci\u00f3n del sistema <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>As\u00ed, arm\u00e1ndose con alg\u00fan recolector de m\u00e9tricas (Telegraf, Metricbeat, Collectd), que puede ejecutar consultas SQL personalizadas, un almacenamiento para estas m\u00e9tricas (InfluxDB, Elasticsearch, Timescaledb) y un visualizador (Grafana, Kibana), se puede obtener un sistema de monitoreo bastante ligero y flexible, que estar\u00e1 estrechamente integrado con otras m\u00e9tricas generales del sistema (obtenidas, por ejemplo, desde el servidor de aplicaciones, desde el SO, etc.). Como se hace, por ejemplo, en pgwatch2, donde se utiliza la combinaci\u00f3n InfluxDB + Grafana y un conjunto de consultas a vistas del sistema, a las que tambi\u00e9n se pueden <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/cybertec-postgresql\/pgwatch2#adding-metrics\">agregar consultas personalizadas<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"itogo\">Total<\/h2>\n<p><\/p>\n<p>Y esta es solo una lista aproximada de lo que se puede hacer con nuestra base de datos mediante c\u00f3digo SQL convencional. Estoy seguro de que se pueden encontrar muchas m\u00e1s aplicaciones, escr\u00edbanos en los comentarios. Y sobre c\u00f3mo (y, lo m\u00e1s importante, por qu\u00e9) automatizar todo esto e integrarlo en su pipeline de CI\/CD, hablaremos la pr\u00f3xima vez.<\/p>\n<p>Fuente: <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 5.0.2 - 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?\" \/>\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\/es\/blog\/administrirovanie\/database-as-sode-experience\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\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?\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/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\u00abDatabase as Code\u00bb Experience | ProHoster","description":"SQL, \u00bfqu\u00e9 puede ser m\u00e1s sencillo?","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/database-as-sode-experience","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","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?","og:url":"https:\/\/prohoster.info\/es\/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","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/83649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=83649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/83649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/83650"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=83649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=83649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=83649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}