Esta comparación de SQL y NoSQL es el siguiente paso después de convertir tu base de datos SQL Server a Couchbase. En el puesto anteriorCopié AdventureWorks de SQL Server a Couchbase.

En este post, voy a mostrar una aplicación ASP.NET Core que usa SQL Server, y cómo esa misma aplicación usaría Couchbase. Si quieres seguir el tutorial, puedes consultar la sección Proyecto SqlServerToCouchbase en GitHub.

A diferencia del post anterior, no estoy haciendo ningún intento de conversión "automática" de una aplicación. En su lugar, piensa en esto más como una comparación de SQL y NoSQL a nivel de aplicación.

Aplicaciones ASP.NET SQL Server

He creado una aplicación ASP.NET Core REST API muy simple. He utilizado Entity Framework, pero si estás usando Dapper, ADO.NET, NHibernate, etc, todavía debe ser capaz de seguir a lo largo.

Cada punto final devuelve JSON. También he añadido Swashbuckle al proyecto, para que puedas realizar peticiones directamente desde tu navegador a través de OpenAPI.

Aplicación ASP.NET Couchbase Server

La versión Couchbase de la aplicación devuelve los mismos datos, porque está utilizando los mismos datos SQL Server AdventureWorks.

En la aplicación, estoy utilizando el SDK .NET de Couchbase y Transacciones Couchbase bibliotecas. (Puede utilizar Linq2Base como un tipo de sustitución de Entity Framework).

Por lo demás, la aplicación es la misma, proporcionando una comparación (y contraste) entre SQL y NoSQL. Los endpoints devuelven JSON, y Swashbuckle está instalado.

Hay un controlador en cada muestra. Vamos a pasar por cada punto final en el controlador y realizar una comparación SQL y NoSQL.

Comparación entre SQL y NoSQL: Obtener por ID

Empecemos por el GetPersonByIdAsync punto final. Dado un ID de persona, este punto final devuelve los datos de Persona para el ID dado.

Servidor SQL

Aquí está el ejemplo de SQL Server utilizando Entity Framework:

También escribí otra versión de este método, llamada GetPersonByIdRawAsync que utiliza una consulta SQL "en bruto". Esta consulta es muy similar a la que Entity Framework (arriba) genera en última instancia, y es similar a un enfoque Dapper.

Tenga en cuenta que, de cualquier forma, se está ejecutando una consulta SQL.

Con N1QL, podríamos consultar los datos en Couchbase de una manera muy similar. Aquí está el GetPersonByIdRawAsync en el proyecto Couchbase:

(Hay un paso extra al pasar de "bucket" a "cluster". Esto podría ser omitido, pero yo uso cubo en otras partes del controlador, así que lo dejé en).

Sin embargo, el uso de una consulta N1QL implica una sobrecarga adicional (indexación, análisis de consultas, etc). Con Couchbase, si ya conocemos el ID de Persona, podemos saltarnos una consulta N1QL y hacer una búsqueda directa clave/valor (K/V).

Obtener por ID con K/V

La clave ya se conoce; se da como argumento. En lugar de utilizar SQL, vamos a hacer una búsqueda clave/valor. Hice esto en un método endpoint llamado GetPersonByIdAsync:

A diferencia de SQL Server, Couchbase soporta una variedad de APIs para interactuar con los datos. En este caso, la búsqueda clave/valor extraerá el documento Persona directamente de la memoria. No hay necesidad de parsear una consulta SQL o usar cualquier indexación. Las búsquedas de clave/valor en Couchbase a menudo se miden en microsegundos.

Mi consejo: utiliza la búsqueda clave/valor siempre que puedas.

Obtener una entidad expandida por ID

Los datos pueden ser complejos y abarcar múltiples tablas (o múltiples documentos en el caso de Couchbase). Dependiendo de las herramientas que utilices, es posible que tengas alguna funcionalidad que pueda cargar entidades relacionadas.

Por ejemplo, con Entity Framework, puede utilizar una directiva Incluya para extraer entidades relacionadas, como se muestra en este GetPersonByIdExpandedAsync ejemplo:

Entre bastidores, Entity Framework puede generar un JOIN y/o múltiples consultas SELECT para que esto suceda.

Aquí es donde cualquier O/RM (no sólo Entity Framework) puede ser peligroso. Asegúrese de utilizar una herramienta como SQL Profiler para ver qué consultas se están ejecutando realmente.

Nota
Los O/RM pueden ayudar, pero en un De SQL a NoSQL en comparación, es importante recordar que la incompatibilidad de impedancias es un problema mucho menor en el mundo NoSQL.

Para el ejemplo de Couchbase, no estoy utilizando Entity Framework, pero en su lugar puedo utilizar el módulo Sintaxis NEST que forma parte de las extensiones N1QL del estándar SQL. Así es como la versión Couchbase de GetPersonByIdExpandedAsync parece:

NEST es un tipo de JOIN que coloca los datos JOINed en un objeto JSON anidado. En lugar de utilizar un O/RM para mapear los datos, estos datos pueden serializarse directamente en objetos C#.

Consulta de paginación

Veamos un ejemplo en el que NO tenemos una única clave para buscar un dato. Veamos un método que devuelve una "página" de resultados (quizás para rellenar una cuadrícula o lista de la interfaz de usuario).

Paginación en SQL Server

Esta es la versión de SQL Server de GetPersonsPageAsync:

Con Entity Framework, OrderBy, Saltary Toma se utilizan normalmente para la paginación. Si abrimos SQL Server Profiler, el SQL que esto genera se parece a esto:

OFFSET ... ROWS FETCH NEXT ... es la sintaxis que se utiliza aquí para la paginación.

Paging en Couchbase

La sintaxis de paginación siempre varía entre implementaciones SQL. Couchbase se inclina más hacia la sintaxis Oracle/MySQL en este aspecto. Aquí está la versión de Couchbase de GetPersonsPageAsync:

En este caso, LÍMITE ... OFFSET ... se está utilizando.

También quiero señalar la WHERE p.Apellidos NO FALTA. Dado que Couchbase es una base de datos NoSQL, el motor de consulta no puede asumir que Apellido estará en todos los documentos, incluso con ORDER BY p.LastName. Al añadir este DONDE la consulta sabe qué índice debe utilizar. Sin esto, la consulta tardará mucho más en ejecutarse.

Actualización con una transacción ACID

Con el modelo de estilo relacional que estamos utilizando tanto en SQL Server como en Couchbase para este ejemplo, las transacciones ACID serán importantes para ambas aplicaciones.

En estos ejemplos, hay un PersonUpdateApi que permitirá al usuario actualizar ambos el nombre de una persona y su dirección de correo electrónico. Dado que estos datos están en dos tablas/filas separadas (SQL Server) o dos documentos separados (Couchbase), queremos que sea una operación atómica de todo o nada.

Nota
Se especifica un ID para ambas (para simplificar la API), ya que es posible (aunque poco frecuente en este conjunto de datos) que una persona tenga varias direcciones de correo electrónico.

ACID con Entity Framework

A continuación se muestra un ejemplo de una transacción ACID que utiliza Entity Framework para actualizar tanto una fila de datos de la tabla Persona como una fila de datos de la tabla EmailAddress.

Tenga en cuenta las cuatro partes principales de una transacción:

  1. Iniciar transacción (_context.Database.BeginTransactionAsync();)
  2. pruebe/captura
  3. Transacción de compromiso (await transacción.CommitAsync();)
  4. Transacción de Rollback en el captura (transacción.RollbackAsync();)

Esta es una característica importante en la que la comparación entre SQL y NoSQL ha cambiado en los últimos años. Con Couchbase, las transacciones ACID son ahora posibles.

ACID con una transacción Couchbase

Con Couchbase, la API es ligeramente diferente, pero se siguen los mismos pasos:

Los mismos pasos principales son:

  1. Iniciar transacción (transaction.RunAsync( ... ))
  2. pruebe/captura
  3. Transacción de compromiso (implícita, pero context.CommitAsync() podría utilizarse)
  4. Transacción de reversión (de nuevo, implícita, pero context.RollbackAsync() ).

En ambos casos, tenemos una transacción ACID. A diferencia de SQL Server, sin embargo, podemos más tarde optimizar y consolidar los datos en Couchbase para reducir la cantidad de transacciones ACID que necesitamos y aumentar el rendimiento.

Procedimientos almacenados: comparación entre SQL y NoSQL

Los procedimientos almacenados son un tema a veces controvertido. En general, pueden contener mucha funcionalidad y lógica.

Procedimiento almacenado en SQL Server

He creado un procedimiento almacenado llamado "ListSubcomponents" (puede ver el archivo todos los detalles en GitHub). Con Entity Framework, puede utilizar FromSqlRaw para ejecutarlo y asignar los resultados a objetos C#. He creado un objeto C# pseudo-entidad llamado ListaSubcomponentes que se utiliza sólo para este sproc:

El procedimiento almacenado tiene dos parámetros.

Couchbase Función definida por el usuario

Couchbase no tiene nada llamado "procedimiento almacenado" (todavía), pero tiene algo llamado función definida por el usuario (UDF) que también puede contener lógica compleja cuando sea necesario.

He creado una UDF llamada ListaSubcomponentes (que también puede ver en GitHub) que coincide con la funcionalidad del sproc de SQL Server.

A continuación se explica cómo ejecutar esa UDF desde ASP.NET:

Invocarlo en Couchbase con dos parámetros es muy similar a usar FromSqlRaw con Entity Framework.

Rendimiento - Comparación de SQL con NoSQL

Ahora que he convertido la aplicación para utilizar Couchbase, ¿la nueva versión funciona al menos tan rápido como la antigua versión de SQL Server?

Es una pregunta complicada de responder porque:

  • No he hecho NINGUNA optimización en el modelo de datos. Todavía estoy usando la conversión literal de datos de el puesto anterior.
  • El acceso a los datos puede variar mucho de un caso de uso a otro.
  • Los entornos pueden variar mucho de una persona a otra y de una empresa a otra.

Sin embargo, quería hacer algunas pruebas de carga para comprobar que todo está bien.

Ejecuté ambas aplicaciones en mi máquina local y utilicé ngrok para exponerlos a Internet. A continuación, utilicé loader.io (una excelente herramienta para pruebas de carga con concurrencia). A continuación, corrí algunas pruebas rápidas de rendimiento contra sólo el punto final 'paginación'. Este es el punto final que más me preocupa para el rendimiento, y también creo que es el más "manzanas con manzanas" SQL y NoSQL comparación entre los puntos finales.

Comparación de pruebas de carga SQL y NoSQL

Estos son los resultados de la aplicación SQL Server:

SQL and NoSQL comparison - SQL Server load testing

Y aquí están los resultados de la aplicación Couchbase Server:

SQL and NoSQL comparison - Couchbase Server load testing

Interpretación de los resultados de la prueba de carga comparativa SQL y NoSQL

Esto no pretende ser un punto de referencia o un dato que diga "Couchbase es más rápido que SQL Server".

Sólo pretende ser una comprobación de cordura.

Si no obtengo al menos el mismo rendimiento bajo carga que antes, quizá esté haciendo algo mal. Este es un beneficio crucial para el prueba de concepto proceso. Aunque Couchbase, especialmente Couchbase 7, es muy amigable con las relaciones, todavía hay diferencias y matices entre cada y este proceso le ayudará a identificar las diferencias más importantes para usted y su proyecto.

Si buscas puntos de referencia más sólidos, aquí tienes algunos recursos que puedes consultar:

Conclusión

La comparación de SQL y NoSQL y la conversión del código de la aplicación, combinadas con algunas pruebas de carga muy básicas, me demuestran que sí:

  • Alojar un modelo de datos relacional tal cual, sin cambios de modelado
  • Convertir punto(s) final(es) ASP.NET para utilizar el SDK de Couchbase
  • Se espera un rendimiento al menos igual de bueno al principio, con mucho margen para escalar y mejorar, con un riesgo bajo.

Tu caso de uso puede variar, pero recuerda también que durante esta conversión, Couchbase nos dio:

Anexo

He aquí una guía sucinta de la comparación entre SQL y NoSQL que realicé en la aplicación.

Funcionamiento de SQL Server Operación Couchbase

Lectura/escritura de una fila/entidad

Búsqueda de claves/valores

Lectura/escritura de varias filas/páginas

Consulta N1QL

SELECCIONE una entidad con entidades relacionadas

Consulta N1QL con NEST

IniciarTransacción

Transacción.Crear

Procedimiento almacenado

UDF (Eventos también puede ser útil en este caso)

Recordatorios:

  1. Cambie a la API de clave/valor cuando pueda
  2. Utilizar la indexación, la visualización del plan de indexación y el asesor de índices al escribir N1QL
  3. Utilice una transacción ACID (únicamente) cuando necesite
  4. Piense en los objetivos de rendimiento y establezca una forma de ponerlos a prueba.

Próximos pasos

Echa un vistazo Couchbase Server 7, actualmente en fase betahoy. Es una descarga gratuita. Pruebe a cargar sus datos relacionales en él, convirtiendo algunos puntos finales, y vea si el proceso le funciona.

Autor

Publicado por Matthew Groves

A Matthew D. Groves le encanta programar. No importa si se trata de C#, jQuery o PHP: enviará pull requests para cualquier cosa. Lleva codificando profesionalmente desde que escribió una aplicación de punto de venta en QuickBASIC para la pizzería de sus padres, allá por los años noventa. Actualmente trabaja como Director de Marketing de Producto para Couchbase. Su tiempo libre lo pasa con su familia, viendo a los Reds y participando en la comunidad de desarrolladores. Es autor de AOP in .NET, Pro Microservices in .NET, autor de Pluralsight y MVP de Microsoft.

Dejar una respuesta