Conceptos básicos de diseño de bases de datos: comparación de PostgreSQL, Cassandra y MongoDB

Hola amigos Antes de partir para la segunda parte de las vacaciones de mayo, compartimos con ustedes el material que tradujimos en la víspera del lanzamiento de una nueva transmisión al ritmo de "DBMS relacional" .



Los desarrolladores de aplicaciones pasan mucho tiempo comparando múltiples bases de datos operativas para elegir la que mejor funcione para su carga de trabajo prevista. Las necesidades pueden incluir modelado de datos simplificado, garantías transaccionales, rendimiento de lectura / escritura, escala horizontal y tolerancia a fallas. Por tradición, la elección comienza con una categoría de base de datos, SQL o NoSQL, ya que cada categoría proporciona un conjunto claro de compensaciones. El alto rendimiento en términos de baja latencia y alto rendimiento generalmente se considera un requisito de compensación y, por lo tanto, es necesario para cualquier base de datos en la muestra.

El propósito de este artículo es ayudar a los desarrolladores de aplicaciones a tomar la decisión correcta entre SQL y NoSQL en el contexto del modelado de datos de aplicaciones. Analizaremos una base de datos SQL, a saber, PostgreSQL y dos bases de datos NoSQL, Cassandra y MongoDB, para hablar sobre los conceptos básicos del diseño de la base de datos, como crear tablas, rellenarlas, leer datos de la tabla y eliminarlas. En el próximo artículo, definitivamente veremos los índices, las transacciones, las UNIONES, las directivas TTL y el diseño de bases de datos basadas en JSON.

¿Cuál es la diferencia entre SQL y NoSQL?

Las bases de datos SQL aumentan la flexibilidad de la aplicación con garantías transaccionales ACID, así como su capacidad de consultar datos utilizando JOIN de manera inesperada además de los modelos de bases de datos relacionales normalizados existentes.

Dada su arquitectura monolítica / de nodo único y el uso de un modelo de replicación maestro-esclavo para la redundancia, las bases de datos SQL tradicionales no tienen dos características importantes: escalabilidad lineal del registro (es decir, división automática en varios nodos) y pérdida de datos automática / cero. Esto significa que la cantidad de datos recibidos no puede exceder el rendimiento máximo de escritura de un nodo. Además, se debe tener en cuenta cierta pérdida temporal de datos durante la tolerancia a fallas (en una arquitectura sin compartir recursos). Aquí debe tener en cuenta que las confirmaciones recientes aún no se han reflejado en la copia esclava. Las actualizaciones sin tiempo de inactividad también son difíciles de lograr en las bases de datos SQL.

Las bases de datos NoSQL generalmente se distribuyen por naturaleza, es decir en ellos, los datos se dividen en secciones y se distribuyen en varios nodos. Requieren desnormalización. Esto significa que los datos ingresados ​​también deben copiarse varias veces para responder a las solicitudes específicas que envíe. El objetivo general es obtener un alto rendimiento al reducir la cantidad de fragmentos disponibles durante la lectura. Sigue la afirmación de que NoSQL requiere que modele sus consultas, mientras que SQL requiere que modele sus datos.

NoSQL se enfoca en lograr un alto rendimiento en un clúster distribuido, y esta es la razón principal para muchas compensaciones de diseño de bases de datos que incluyen ACID de pérdida de transacciones, UNIONES e índices secundarios globales consistentes.

Se cree que aunque las bases de datos NoSQL proporcionan escalabilidad de escritura lineal y alta tolerancia a fallas, la pérdida de garantías transaccionales las hace inadecuadas para datos críticos para la misión.

La siguiente tabla muestra cómo el modelado de datos en NoSQL difiere de SQL.



SQL y NoSQL: ¿Por qué se necesitan ambos?

Las aplicaciones del mundo real con una gran cantidad de usuarios, como Amazon.com, Netflix, Uber y Airbnb, llevan a cabo tareas complejas y de clasificación múltiple. Por ejemplo, una aplicación de comercio electrónico como Amazon.com necesita almacenar datos livianos y altamente críticos, como información sobre usuarios, productos, pedidos, facturas, junto con datos pesados ​​pero menos confidenciales, como revisiones de productos, mensajes de soporte , actividad del usuario, opiniones de los usuarios y recomendaciones. Naturalmente, estas aplicaciones se basan en al menos una base de datos SQL junto con al menos una base de datos NoSQL. En los sistemas interregionales y globales, la base de datos NoSQL funciona como un caché geo-distribuido para los datos almacenados en una fuente confiable, una base de datos SQL, trabajando en cualquier región.

¿Cómo combina YugaByte DB SQL y NoSQL?

Construido sobre un motor de almacenamiento mixto orientado a registros, fragmentación automática, replicación de consenso distribuida fragmentada y transacciones distribuidas ACID (inspiradas en Google Spanner), YugaByte DB es la primera base de datos de código abierto del mundo que es simultáneamente compatible con NoSQL (Cassandra & Redis ) y SQL (PostgreSQL). Como se muestra en la tabla a continuación, YSQL, la API YugaByte DB compatible con Cassandra, agrega los conceptos de transacciones ACID simples y de múltiples claves e índices secundarios globales a las API NoSQL, abriendo así la era de las bases de datos NoSQL transaccionales. Además, YSQL, una API YugaByte DB compatible con PostgreSQL, agrega la noción de escala de escritura lineal y tolerancia automática a fallas a la API SQL, presentando bases de datos SQL distribuidas al mundo. Dado que la base de datos YugaByte DB es esencialmente transaccional, la API NoSQL ahora se puede usar en el contexto de datos de misión crítica.



Como se indicó anteriormente en el artículo "Introducción de YSQL: una API SQL distribuida compatible con PostgreSQL para YugaByte DB" , la elección entre SQL o NoSQL en YugaByte DB depende completamente de las características de la carga de trabajo principal:

  • Si la carga de trabajo principal es operaciones de múltiples claves con JOIN, al elegir YSQL, comprenda que sus claves se pueden distribuir en varios nodos, lo que conducirá a un mayor retraso y / o menor rendimiento que en NoSQL.
  • De lo contrario, seleccione cualquiera de las dos API NoSQL, teniendo en cuenta que obtendrá un mejor rendimiento como resultado de las consultas que se atienden desde un nodo a la vez. YugaByte DB puede servir como una única base de datos operativa para aplicaciones complejas reales en las que necesita administrar múltiples cargas de trabajo al mismo tiempo.

El laboratorio de modelado de datos en la siguiente sección se basa en las bases de datos YugaByte DB compatibles con PostgreSQL y Cassandra API, a diferencia de las bases de datos de origen. Este enfoque enfatiza la facilidad de interacción con dos API diferentes (en dos puertos diferentes) del mismo grupo de bases de datos, en lugar de usar grupos completamente independientes de dos bases de datos diferentes.

En las siguientes secciones, nos reuniremos con el laboratorio de modelado de datos para ilustrar las diferencias y algunas características comunes de las bases de datos en cuestión.

Laboratorio de modelado de datos

Instalación de base de datos

Dado el énfasis en el diseño de un modelo de datos (en lugar de arquitecturas de implementación complejas), instalaremos las bases de datos en contenedores Docker en la computadora local, y luego interactuaremos con ellos utilizando sus correspondientes shells de línea de comandos.

Compatible con PostgreSQL y Cassandra, base de datos YugaByte DB

mkdir ~/yugabyte && cd ~/yugabyte wget https://downloads.yugabyte.com/yb-docker-ctl && chmod +x yb-docker-ctl docker pull yugabytedb/yugabyte ./yb-docker-ctl create --enable_postgres 

Mongodb

 docker run --name my-mongo -d mongo:latest 

Línea de comando de acceso

Vamos a conectarnos a las bases de datos utilizando el shell de la línea de comandos para las API correspondientes.

PostgreSQL

psql es un shell de línea de comando para interactuar con PostgreSQL. Para facilitar su uso, YugaByte DB viene con psql directamente en la carpeta bin.

 docker exec -it yb-postgres-n1 /home/yugabyte/postgres/bin/psql -p 5433 -U postgres 

Cassandra

cqlsh es un shell de línea de comandos para interactuar con Cassandra y sus bases de datos compatibles a través de CQL (lenguaje de consulta Cassandra). Para facilitar su uso, YugaByte DB viene con cqlsh en el bin .

Tenga en cuenta que CQL se inspiró en SQL y tiene conceptos similares a tablas, filas, columnas e índices. Sin embargo, como lenguaje NoSQL, agrega un cierto conjunto de restricciones, la mayoría de las cuales también cubriremos en otros artículos.

 docker exec -it yb-tserver-n1 /home/yugabyte/bin/cqlsh 

Mongodb

mongo es un shell de línea de comando para interactuar con MongoDB. Se puede encontrar en el directorio bin de la instalación de MongoDB.

 docker exec -it my-mongo bash cd bin mongo 

Creación de tabla

Ahora podemos interactuar con la base de datos para realizar varias operaciones utilizando la línea de comando. Comencemos creando una tabla que almacene información sobre canciones escritas por diferentes artistas. Estas canciones pueden ser parte de un álbum. También atributos opcionales para la canción: año de lanzamiento, precio, género y calificación. Necesitamos considerar atributos adicionales que pueden ser necesarios en el futuro a través del campo "etiquetas". Puede almacenar datos semiestructurados como pares clave-valor.

PostgreSQL

 CREATE TABLE Music ( Artist VARCHAR(20) NOT NULL, SongTitle VARCHAR(30) NOT NULL, AlbumTitle VARCHAR(25), Year INT, Price FLOAT, Genre VARCHAR(10), CriticRating FLOAT, Tags TEXT, PRIMARY KEY(Artist, SongTitle) ); 

Cassandra

Crear una tabla en Cassandra es muy similar a PostgreSQL. Una de las principales diferencias es la falta de restricciones de integridad (por ejemplo, NO NULL), pero esto es responsabilidad de la aplicación, no de la base de datos NoSQL . La clave principal consta de una clave de sección (columna Artista en el ejemplo a continuación) y un conjunto de columnas de agrupación (columna SongTitle en el ejemplo a continuación). La clave de partición determina en qué partición / fragmento colocar la fila, y las columnas de agrupamiento indican cómo deben organizarse los datos dentro del fragmento actual.

 CREATE KEYSPACE myapp; USE myapp; CREATE TABLE Music ( Artist TEXT, SongTitle TEXT, AlbumTitle TEXT, Year INT, Price FLOAT, Genre TEXT, CriticRating FLOAT, Tags TEXT, PRIMARY KEY(Artist, SongTitle) ); 

Mongodb

MongoDB organiza los datos en bases de datos (Base de datos) (similar a Keyspace en Cassandra), donde hay colecciones (Colecciones) (similares a tablas), que contienen documentos (Documentos) (similares a filas en una tabla). MongoDB básicamente no requiere la definición del esquema original. El comando "usar base de datos" que se muestra a continuación crea una instancia de la base de datos en la primera llamada y cambia el contexto de la base de datos recién creada. Incluso las colecciones no necesitan ser creadas explícitamente, se crean automáticamente, simplemente cuando agrega el primer documento a una nueva colección. Tenga en cuenta que MongoDB usa la base de datos de prueba de forma predeterminada, por lo tanto, cualquier operación de nivel de recopilación sin especificar una base de datos específica se realizará de forma predeterminada.

 use myNewDatabase; 

Recuperando información de la tabla PostgreSQL

 \d Music Table "public.music" Column | Type | Collation | Nullable | Default --------------+-----------------------+-----------+----------+-------- artist | character varying(20) | | not null | songtitle | character varying(30) | | not null | albumtitle | character varying(25) | | | year | integer | | | price | double precision | | | genre | character varying(10) | | | criticrating | double precision | | | tags | text | | | Indexes: "music_pkey" PRIMARY KEY, btree (artist, songtitle) 

Cassandra

 DESCRIBE TABLE MUSIC; CREATE TABLE myapp.music ( artist text, songtitle text, albumtitle text, year int, price float, genre text, tags text, PRIMARY KEY (artist, songtitle) ) WITH CLUSTERING ORDER BY (songtitle ASC) AND default_time_to_live = 0 AND transactions = {'enabled': 'false'}; 

Mongodb

 use myNewDatabase; show collections; 

Publicar datos en una tabla PostgreSQL

 INSERT INTO Music (Artist, SongTitle, AlbumTitle, Year, Price, Genre, CriticRating, Tags) VALUES( 'No One You Know', 'Call Me Today', 'Somewhat Famous', 2015, 2.14, 'Country', 7.8, '{"Composers": ["Smith", "Jones", "Davis"],"LengthInSeconds": 214}' ); INSERT INTO Music (Artist, SongTitle, AlbumTitle, Price, Genre, CriticRating) VALUES( 'No One You Know', 'My Dog Spot', 'Hey Now', 1.98, 'Country', 8.4 ); INSERT INTO Music (Artist, SongTitle, AlbumTitle, Price, Genre) VALUES( 'The Acme Band', 'Look Out, World', 'The Buck Starts Here', 0.99, 'Rock' ); INSERT INTO Music (Artist, SongTitle, AlbumTitle, Price, Genre, Tags) VALUES( 'The Acme Band', 'Still In Love', 'The Buck Starts Here', 2.47, 'Rock', '{"radioStationsPlaying": ["KHCR", "KBQX", "WTNR", "WJJH"], "tourDates": { "Seattle": "20150625", "Cleveland": "20150630"}, "rotation": Heavy}' ); 

Cassandra

En general, la expresión INSERT en Cassandra es muy similar a la de PostgreSQL. Sin embargo, hay una gran diferencia en la semántica. En Cassandra, INSERT realidad una operación UPSERT donde los últimos valores se agregan a la cadena en caso de que la cadena ya exista.
La entrada de datos es similar a la inserción de PostgreSQL anterior

Mongodb

Aunque MongoDB es una base de datos NoSQL, como Cassandra, su operación de inserción no tiene nada que ver con el comportamiento semántico en Cassandra. En MongoDB, insert () no tiene capacidades UPSERT , lo que lo hace parecer PostgreSQL. Agregar datos predeterminados sin _idspecified agregará un nuevo documento a la colección.

db.music.insert( {
artist: "No One You Know",
songTitle: "Call Me Today",
albumTitle: "Somewhat Famous",
year: 2015,
price: 2.14,
genre: "Country",
tags: {
Composers: ["Smith", "Jones", "Davis"],
LengthInSeconds: 214
}
}
);
db.music.insert( {
artist: "No One You Know",
songTitle: "My Dog Spot",
albumTitle: "Hey Now",
price: 1.98,
genre: "Country",
criticRating: 8.4
}
);
db.music.insert( {
artist: "The Acme Band",
songTitle: "Look Out, World",
albumTitle:"The Buck Starts Here",
price: 0.99,
genre: "Rock"
}
);
db.music.insert( {
artist: "The Acme Band",
songTitle: "Still In Love",
albumTitle:"The Buck Starts Here",
price: 2.47,
genre: "Rock",
tags: {
radioStationsPlaying:["KHCR", "KBQX", "WTNR", "WJJH"],
tourDates: {
Seattle: "20150625",
Cleveland: "20150630"
},
rotation: "Heavy"
}
}
);


Consulta de tabla

Quizás la diferencia más significativa entre SQL y NoSQL en términos de diseño de consultas es el uso de las instrucciones FROM y WHERE . SQL le permite seleccionar varias tablas después de una FROM , y una WHERE puede ser de cualquier complejidad (incluidas las operaciones JOIN entre tablas). Sin embargo, NoSQL tiende a imponer una restricción estricta en FROM y funciona con una sola tabla especificada, y en WHERE , la clave primaria siempre debe especificarse. Esto se debe al deseo de mejorar el rendimiento de NoSQL, del que hablamos anteriormente. Este deseo conduce a todas las reducciones posibles en cualquier interacción entre tablas y claves. Puede dar lugar a una gran demora en la comunicación internodal al responder a una solicitud y, por lo tanto, es mejor evitarlo en principio. Por ejemplo, Cassandra requiere que las consultas se limiten a ciertos operadores (solo se permiten =, IN, <, >, =>, <= ) en las teclas de partición, excepto cuando se solicita un índice secundario (aquí solo se permite el operador =).

PostgreSQL

A continuación se ofrecen tres ejemplos de consultas que una base de datos SQL puede ejecutar fácilmente.

  • Imprime todas las canciones del artista;
  • Imprima todas las canciones del artista que coincidan con la primera parte del nombre;
  • Enumere todas las canciones del artista que tengan una palabra específica en el título y que tengan un precio inferior a 1.00.

 SELECT * FROM Music WHERE Artist='No One You Know'; SELECT * FROM Music WHERE Artist='No One You Know' AND SongTitle LIKE 'Call%'; SELECT * FROM Music WHERE Artist='No One You Know' AND SongTitle LIKE '%Today%' AND Price > 1.00; 

Cassandra

De las consultas PostgreSQL anteriores, solo la primera funcionará en Cassandra sin cambios, ya que la instrucción LIKE no se puede aplicar a columnas de agrupación como SongTitle . En este caso, solo se permiten operadores = e IN .

 SELECT * FROM Music WHERE Artist='No One You Know'; SELECT * FROM Music WHERE Artist='No One You Know' AND SongTitle IN ('Call Me Today', 'My Dog Spot') AND Price > 1.00; 

Mongodb

Como se muestra en ejemplos anteriores, el método principal para crear consultas en MongoDB es db.collection.find () . Este método contiene explícitamente el nombre de la colección ( music en el ejemplo a continuación), por lo que está prohibida la solicitud de varias colecciones.

 db.music.find( { artist: "No One You Know" } ); db.music.find( { artist: "No One You Know", songTitle: /Call/ } ); 

Leer todas las filas de la tabla

Leer todas las líneas es solo un caso especial de la plantilla de consulta que examinamos anteriormente.

PostgreSQL

 SELECT * FROM Music; 


Cassandra

Similar al ejemplo en PostgreSQL anterior.


Mongodb

 db.music.find( {} ); 

Edición de datos en una tabla

PostgreSQL

PostgreSQL proporciona una UPDATE para modificar datos. No tiene capacidades UPSERT , por lo que la ejecución de esta instrucción fallará si la fila ya no está en la base de datos.

 UPDATE Music SET Genre = 'Disco' WHERE Artist = 'The Acme Band' AND SongTitle = 'Still In Love'; 

Cassandra

Cassandra tiene una UPDATE similar a PostgreSQL. UPDATE tiene la misma semántica UPSERT INSERT .

Similar al ejemplo en PostgreSQL anterior.

Mongodb
La operación update () en MongoDB puede actualizar completamente un documento existente o actualizar solo ciertos campos. Por defecto, actualiza solo un documento con la semántica UPSERT . La actualización de múltiples documentos y comportamientos similares a UPSERT se puede aplicar estableciendo indicadores adicionales para la operación. Por ejemplo, en el ejemplo a continuación, su canción actualiza el género de un artista en particular.

 db.music.update( {"artist": "The Acme Band"}, { $set: { "genre": "Disco" } }, {"multi": true, "upsert": true} ); 

Eliminar datos de una tabla

PostgreSQL

 DELETE FROM Music WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World'; 

Cassandra

Similar al ejemplo en PostgreSQL anterior.

Mongodb

MongoDB tiene dos tipos de operaciones para eliminar documentos: deleteOne () / deleteMany () y remove () . Ambos tipos eliminan documentos, pero devuelven resultados diferentes.

 db.music.deleteMany( { artist: "The Acme Band" } ); 

Eliminar tabla

PostgreSQL

 DROP TABLE Music; 

Cassandra

Similar al ejemplo en PostgreSQL anterior.

Mongodb

 db.music.drop(); 

Conclusión

El debate sobre la elección entre SQL y NoSQL ha sido furioso durante más de 10 años. Hay dos aspectos principales de este debate: la arquitectura del motor de la base de datos (SQL monolítico, transaccional versus NoSQL distribuido, no transaccional) y el enfoque del diseño de la base de datos (modelar datos en SQL versus modelar sus consultas en NoSQL).

Con una base de datos transaccional distribuida como YugaByte DB, el debate sobre la arquitectura de la base de datos se puede disipar fácilmente. A medida que los volúmenes de datos se hacen más grandes de lo que se puede escribir en un solo nodo, se hace necesaria una arquitectura completamente distribuida que admita escalabilidad lineal de grabaciones con fragmentación / reequilibrio automático.

Además de ser dicho en un artículo de Google Cloud , las arquitecturas transaccionales estrictamente consistentes ahora se usan más ampliamente para proporcionar una mejor flexibilidad de desarrollo que las arquitecturas no transaccionales y, en última instancia, consistentes.

Volviendo a la discusión del diseño de la base de datos, es justo decir que ambos enfoques de diseño (SQL y NoSQL) son necesarios para cualquier aplicación real compleja. El enfoque de "modelado de datos" del enfoque SQL permite a los desarrolladores cumplir más fácilmente los requisitos comerciales cambiantes, mientras que el "datos de modelado" del enfoque NoSQL permite a los mismos desarrolladores manejar grandes cantidades de datos con baja latencia y alto rendimiento. Es por esta razón que YugaByte DB proporciona API SQL y NoSQL en un núcleo común, en lugar de promover uno de los enfoques. Además, al garantizar la compatibilidad con los lenguajes de bases de datos populares, incluidos PostgreSQL y Cassandra, YugaByte DB garantiza que los desarrolladores no tengan que aprender otro idioma para trabajar con un motor de base de datos distribuido y estrictamente coherente.

En este artículo, descubrimos cómo los fundamentos del diseño de la base de datos difieren en PostgreSQL, Cassandra y MongoDB. En los siguientes artículos, profundizaremos en conceptos de diseño avanzados, como índices, transacciones, uniones, directivas TTL y documentos JSON.

Le deseamos una maravillosa estadía el resto del fin de semana y lo invitamos a un seminario web gratuito , que se realizará el 14 de mayo.

Source: https://habr.com/ru/post/451042/


All Articles