{"id":11147,"date":"2021-05-27T08:01:06","date_gmt":"2021-05-27T15:01:06","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=11147"},"modified":"2025-06-13T19:40:16","modified_gmt":"2025-06-14T02:40:16","slug":"sql-nosql-comparison-aspnet-application","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/sql-nosql-comparison-aspnet-application\/","title":{"rendered":"Comparaci\u00f3n entre SQL y NoSQL: Aplicaci\u00f3n ASP.NET"},"content":{"rendered":"<div class=\"paragraph\">\n<p>Esta comparaci\u00f3n de SQL y NoSQL es el siguiente paso despu\u00e9s de convertir tu base de datos SQL Server a Couchbase. En <a href=\"https:\/\/www.couchbase.com\/blog\/es\/sql-to-nosql-automated-migration\/\">el puesto anterior<\/a>Copi\u00e9 AdventureWorks de SQL Server a Couchbase.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En este post, voy a mostrar una aplicaci\u00f3n ASP.NET Core que usa SQL Server, y c\u00f3mo esa misma aplicaci\u00f3n usar\u00eda Couchbase. Si quieres seguir el tutorial, puedes consultar la secci\u00f3n <a href=\"https:\/\/github.com\/mgroves\/SqlServerToCouchbase\">Proyecto SqlServerToCouchbase<\/a> en GitHub.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>A diferencia del post anterior, no estoy haciendo ning\u00fan intento de conversi\u00f3n \"autom\u00e1tica\" de una aplicaci\u00f3n. En su lugar, piensa en esto m\u00e1s como una comparaci\u00f3n de SQL y NoSQL a nivel de aplicaci\u00f3n.<\/p>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_asp_net_sql_server_applications\">Aplicaciones ASP.NET SQL Server<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>He creado una aplicaci\u00f3n ASP.NET Core REST API muy simple. He utilizado Entity Framework, pero si est\u00e1s usando Dapper, ADO.NET, NHibernate, etc, todav\u00eda debe ser capaz de seguir a lo largo.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Cada punto final devuelve JSON. Tambi\u00e9n he a\u00f1adido Swashbuckle al proyecto, para que puedas realizar peticiones directamente desde tu navegador a trav\u00e9s de OpenAPI.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_asp_net_couchbase_server_application\">Aplicaci\u00f3n ASP.NET Couchbase Server<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>La versi\u00f3n Couchbase de la aplicaci\u00f3n devuelve los mismos datos, porque est\u00e1 utilizando los mismos datos SQL Server AdventureWorks.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En la aplicaci\u00f3n, estoy utilizando el <a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/hello-world\/start-using-sdk.html\">SDK .NET de Couchbase<\/a> y <a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/distributed-acid-transactions-from-the-sdk.html\">Transacciones Couchbase<\/a> bibliotecas. (Puede utilizar <a href=\"https:\/\/github.com\/couchbaselabs\/Linq2Couchbase\">Linq2Base<\/a> como un tipo de sustituci\u00f3n de Entity Framework).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Por lo dem\u00e1s, la aplicaci\u00f3n es la misma, proporcionando una comparaci\u00f3n (y contraste) entre SQL y NoSQL. Los endpoints devuelven JSON, y Swashbuckle est\u00e1 instalado.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Hay un controlador en cada muestra. Vamos a pasar por cada punto final en el controlador y realizar una comparaci\u00f3n SQL y NoSQL.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_sql_and_nosql_comparison_get_by_id\">Comparaci\u00f3n entre SQL y NoSQL: Obtener por ID<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Empecemos por el <code>GetPersonByIdAsync<\/code> punto final. Dado un ID de persona, este punto final devuelve los datos de Persona para el ID dado.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_sql_server\">Servidor SQL<\/h3>\n<div class=\"paragraph\">\n<p>Aqu\u00ed est\u00e1 el ejemplo de SQL Server utilizando Entity Framework:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpGet(\"\/person\/{personId}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonByIdAsync(int personId)\r\n{\r\n    var person = await _context.Persons\r\n        .SingleOrDefaultAsync(p =&gt; p.BusinessEntityID == personId);\r\n\r\n    return Ok(person);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Tambi\u00e9n escrib\u00ed otra versi\u00f3n de este m\u00e9todo, llamada <code>GetPersonByIdRawAsync<\/code> que utiliza una consulta SQL \"en bruto\". Esta consulta es muy similar a la que Entity Framework (arriba) genera en \u00faltima instancia, y es similar a un enfoque Dapper.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpGet(\"\/personRaw\/{personId}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonByIdRawAsync(int personId)\r\n{\r\n    var person = await _context.Persons\r\n        .FromSqlRaw(@\"SELECT * FROM Person.Person WHERE BusinessEntityID = {0}\", personId)\r\n        .SingleOrDefaultAsync();\r\n\r\n    return Ok(person);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Tenga en cuenta que, de cualquier forma, se est\u00e1 ejecutando una consulta SQL.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Con N1QL, podr\u00edamos consultar los datos en Couchbase de una manera muy similar. Aqu\u00ed est\u00e1 el <code>GetPersonByIdRawAsync<\/code> en el proyecto Couchbase:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpGet(\"\/personRaw\/{personId}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonByIdRawAsync(int personId)\r\n{\r\n    var bucket = await _bucketProvider.GetBucketAsync();\r\n    var cluster = bucket.Cluster;\r\n    var personResult = await cluster.QueryAsync&lt;Person&gt;(@\"\r\n        SELECT p.* FROM AdventureWorks2016.Person.Person p WHERE p.BusinessEntityID = $personId\",\r\n        new QueryOptions().Parameter(\"personId\", personId));\r\n    return Ok(await personResult.Rows.SingleOrDefaultAsync());\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>(Hay un paso extra al pasar de \"bucket\" a \"cluster\". Esto podr\u00eda ser omitido, pero yo uso cubo en otras partes del controlador, as\u00ed que lo dej\u00e9 en).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Sin embargo, el uso de una consulta N1QL implica una sobrecarga adicional (indexaci\u00f3n, an\u00e1lisis de consultas, etc). Con Couchbase, si ya conocemos el ID de Persona, podemos saltarnos una consulta N1QL y hacer una b\u00fasqueda directa clave\/valor (K\/V).<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_get_by_id_with_k_v\">Obtener por ID con K\/V<\/h3>\n<div class=\"paragraph\">\n<p>La clave ya se conoce; se da como argumento. En lugar de utilizar SQL, vamos a hacer una b\u00fasqueda clave\/valor. Hice esto en un m\u00e9todo endpoint llamado <code>GetPersonByIdAsync<\/code>:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpGet(\"\/person\/{personId}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonByIdAsync(int personId)\r\n{\r\n    var bucket = await _bucketProvider.GetBucketAsync();\r\n    var scope = await bucket.ScopeAsync(\"Person\");\r\n    var coll = await scope.CollectionAsync(\"Person\");\r\n    var personDoc = await coll.GetAsync(personId.ToString());\r\n    return Ok(personDoc.ContentAs&lt;Person&gt;());\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>A diferencia de SQL Server, Couchbase soporta una variedad de APIs para interactuar con los datos. En este caso, la b\u00fasqueda clave\/valor extraer\u00e1 el documento Persona directamente de la memoria. No hay necesidad de parsear una consulta SQL o usar cualquier indexaci\u00f3n. Las b\u00fasquedas de clave\/valor en Couchbase a menudo se miden en microsegundos.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Mi consejo: utiliza la b\u00fasqueda clave\/valor siempre que puedas.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_get_an_expanded_entity_by_id\">Obtener una entidad expandida por ID<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Los datos pueden ser complejos y abarcar m\u00faltiples tablas (o m\u00faltiples documentos en el caso de Couchbase). Dependiendo de las herramientas que utilices, es posible que tengas alguna funcionalidad que pueda cargar entidades relacionadas.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Por ejemplo, con Entity Framework, puede utilizar una directiva <code>Incluya<\/code> para extraer entidades relacionadas, como se muestra en este <code>GetPersonByIdExpandedAsync<\/code> ejemplo:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpGet(\"\/personExpanded\/{personId}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonByIdExpandedAsync(int personId)\r\n{\r\n    var person = await _context.Persons\r\n        .Include(p =&gt; p.EmailAddresses)\r\n        .SingleOrDefaultAsync(p =&gt; p.BusinessEntityID == personId);\r\n\r\n    return Ok(person);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Entre bastidores, Entity Framework puede generar un JOIN y\/o m\u00faltiples consultas SELECT para que esto suceda.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Aqu\u00ed es donde cualquier O\/RM (no s\u00f3lo Entity Framework) puede ser peligroso. Aseg\u00farese de utilizar una herramienta como SQL Profiler para ver qu\u00e9 consultas se est\u00e1n ejecutando realmente.<\/p>\n<\/div>\n<div class=\"admonitionblock note\">\n<table>\n<tbody>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Nota<\/div>\n<\/td>\n<td class=\"content\">Los O\/RM pueden ayudar, pero en un <a href=\"https:\/\/www.couchbase.com\/blog\/es\/sql-to-nosql-automated-migration\/\">De SQL a NoSQL<\/a> en comparaci\u00f3n, es importante recordar que la incompatibilidad de impedancias es un problema mucho menor en el mundo NoSQL.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<div class=\"paragraph\">\n<p>Para el ejemplo de Couchbase, no estoy utilizando Entity Framework, pero en su lugar puedo utilizar el m\u00f3dulo <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/nest.html\">Sintaxis NEST<\/a> que forma parte de las extensiones N1QL del est\u00e1ndar SQL. As\u00ed es como la versi\u00f3n Couchbase de <code>GetPersonByIdExpandedAsync<\/code> parece:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpGet(\"\/personExpanded\/{personId}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonByIdExpandedAsync(int personId)\r\n{\r\n    var bucket = await _bucketProvider.GetBucketAsync();\r\n    var cluster = bucket.Cluster;\r\n    var personResult = await cluster.QueryAsync&lt;Person&gt;(@\"\r\n        SELECT p.*, EmailAddresses\r\n        FROM AdventureWorks2016.Person.Person p\r\n        NEST AdventureWorks2016.Person.EmailAddress EmailAddresses ON EmailAddresses.BusinessEntityID = p.BusinessEntityID\r\n        WHERE p.BusinessEntityID = $personId\",\r\n        new QueryOptions().Parameter(\"personId\", personId));\r\n    return Ok(await personResult.Rows.SingleOrDefaultAsync());\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>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#.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_paging_query\">Consulta de paginaci\u00f3n<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Veamos un ejemplo en el que NO tenemos una \u00fanica clave para buscar un dato. Veamos un m\u00e9todo que devuelve una \"p\u00e1gina\" de resultados (quiz\u00e1s para rellenar una cuadr\u00edcula o lista de la interfaz de usuario).<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_paging_in_sql_server\">Paginaci\u00f3n en SQL Server<\/h3>\n<div class=\"paragraph\">\n<p>Esta es la versi\u00f3n de SQL Server de <code>GetPersonsPageAsync<\/code>:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpGet(\"\/persons\/page\/{pageNum}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonsPageAsync(int pageNum)\r\n{\r\n    var pageSize = 10;\r\n    var personPage = await _context.Persons\r\n        .OrderBy(p =&gt; p.LastName)\r\n        .Skip(pageNum * pageSize)\r\n        .Take(pageSize)\r\n        .Select(p =&gt; new { p.BusinessEntityID, p.FirstName, p.LastName })\r\n        .ToListAsync();\r\n    return Ok(personPage);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Con Entity Framework, <code>OrderBy<\/code>, <code>Saltar<\/code>y <code>Toma<\/code> se utilizan normalmente para la paginaci\u00f3n. Si abrimos SQL Server Profiler, el SQL que esto genera se parece a esto:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-SQL\" data-lang=\"SQL\">exec sp_executesql N'SELECT [p].[BusinessEntityID], [p].[FirstName], [p].[LastName]\r\nFROM [Person].[Person] AS [p]\r\nORDER BY [p].[LastName]\r\nOFFSET @__p_0 ROWS FETCH NEXT @__p_0 ROWS ONLY',N'@__p_0 int',@__p_0=10<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><code>OFFSET ... ROWS FETCH NEXT ...<\/code> es la sintaxis que se utiliza aqu\u00ed para la paginaci\u00f3n.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_paging_in_couchbase\">Paging en Couchbase<\/h3>\n<div class=\"paragraph\">\n<p>La sintaxis de paginaci\u00f3n siempre var\u00eda entre implementaciones SQL. Couchbase se inclina m\u00e1s hacia la sintaxis Oracle\/MySQL en este aspecto. Aqu\u00ed est\u00e1 la versi\u00f3n de Couchbase de <code>GetPersonsPageAsync<\/code>:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-SQL\" data-lang=\"SQL\">[HttpGet(\"\/persons\/page\/{pageNum}\")]\r\npublic async Task&lt;IActionResult&gt; GetPersonsPageAsync(int pageNum)\r\n{\r\n    var pageSize = 10;\r\n    var bucket = await _bucketProvider.GetBucketAsync();\r\n    var bucketName = bucket.Name;\r\n    var cluster = bucket.Cluster;\r\n\r\n    var personPage = await cluster.QueryAsync&lt;Person&gt;($@\"\r\n        SELECT p.LastName, p.BusinessEntityID, p.FirstName\r\n        FROM `{bucketName}`.Person.Person p\r\n        WHERE p.LastName IS NOT MISSING\r\n        ORDER BY p.LastName\r\n        LIMIT {pageSize} OFFSET {(pageNum * pageSize)}\r\n    \");\r\n\r\n    return Ok(await personPage.Rows.ToListAsync());\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>En este caso, <code>L\u00cdMITE ... OFFSET ...<\/code> se est\u00e1 utilizando.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Tambi\u00e9n quiero se\u00f1alar la <code>WHERE p.Apellidos NO FALTA<\/code>. Dado que Couchbase es una base de datos NoSQL, el motor de consulta no puede asumir que <code>Apellido<\/code> estar\u00e1 en todos los documentos, incluso con <code>ORDER BY p.LastName<\/code>. Al a\u00f1adir este <code>DONDE<\/code> la consulta sabe qu\u00e9 \u00edndice debe utilizar. Sin esto, la consulta tardar\u00e1 mucho m\u00e1s en ejecutarse.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_update_with_an_acid_transaction\">Actualizaci\u00f3n con una transacci\u00f3n ACID<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Con el modelo de estilo relacional que estamos utilizando tanto en SQL Server como en Couchbase para este ejemplo, las transacciones ACID ser\u00e1n importantes para ambas aplicaciones.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En estos ejemplos, hay un <code>PersonUpdateApi<\/code> que permitir\u00e1 al usuario actualizar <strong>ambos<\/strong> el nombre de una persona y su direcci\u00f3n de correo electr\u00f3nico. Dado que estos datos est\u00e1n en dos tablas\/filas separadas (SQL Server) o dos documentos separados (Couchbase), queremos que sea una operaci\u00f3n at\u00f3mica de todo o nada.<\/p>\n<\/div>\n<div class=\"admonitionblock note\">\n<table>\n<tbody>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Nota<\/div>\n<\/td>\n<td class=\"content\">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\u00f3nico.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_acid_with_entity_framework\">ACID con Entity Framework<\/h3>\n<div class=\"paragraph\">\n<p>A continuaci\u00f3n se muestra un ejemplo de una transacci\u00f3n 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.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpPut(\"\/person\")]\r\npublic async Task&lt;IActionResult&gt; UpdatePurchaseOrderAsync(PersonUpdateApi personUpdateApi)\r\n{\r\n    var transaction = await _context.Database.BeginTransactionAsync();\r\n\r\n    try\r\n    {\r\n        \/\/ find the person\r\n        var person = await _context.Persons\r\n            .Include(p =&gt; p.EmailAddresses)\r\n            .SingleOrDefaultAsync(p =&gt; p.BusinessEntityID == personUpdateApi.PersonId);\r\n\r\n        \/\/ update name\r\n        person.FirstName = personUpdateApi.FirstName;\r\n        person.LastName = personUpdateApi.LastName;\r\n\r\n        \/\/ get the particular email address and update it\r\n        \/\/ if the supplied ID is invalid, this will throw an exception\r\n        var email = person.EmailAddresses.Single(e =&gt;\r\n            e.EmailAddressID == personUpdateApi.EmailAddressId);\r\n        email.EmailAddress = personUpdateApi.EmailAddress;\r\n\r\n        await _context.SaveChangesAsync();\r\n\r\n        \/\/ commit transaction\r\n        await transaction.CommitAsync();\r\n\r\n        return Ok($\"Person {personUpdateApi.PersonId} name and email updated.\");\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        await transaction.RollbackAsync();\r\n        return BadRequest(\"Something went wrong, transaction rolled back\");\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Tenga en cuenta las cuatro partes principales de una transacci\u00f3n:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>Iniciar transacci\u00f3n (<code>_context.Database.BeginTransactionAsync();<\/code>)<\/li>\n<li><code>pruebe<\/code>\/<code>captura<\/code><\/li>\n<li>Transacci\u00f3n de compromiso (<code>await transacci\u00f3n.CommitAsync();<\/code>)<\/li>\n<li>Transacci\u00f3n de Rollback en el <code>captura<\/code> (<code>transacci\u00f3n.RollbackAsync();<\/code>)<\/li>\n<\/ol>\n<\/div>\n<div class=\"paragraph\">\n<p>Esta es una caracter\u00edstica importante en la que la comparaci\u00f3n entre SQL y NoSQL ha cambiado en los \u00faltimos a\u00f1os. Con Couchbase, las transacciones ACID son ahora posibles.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_acid_with_a_couchbase_transaction\">ACID con una transacci\u00f3n Couchbase<\/h3>\n<div class=\"paragraph\">\n<p>Con Couchbase, la API es ligeramente diferente, pero se siguen los mismos pasos:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">[HttpPut(\"\/person\")]\r\npublic async Task&lt;IActionResult&gt; UpdatePurchaseOrderAsync(PersonUpdateApi personUpdateApi)\r\n{\r\n    \/\/ setup bucket, cluster, and collections\r\n    var bucket = await _bucketProvider.GetBucketAsync();\r\n    var scope = await bucket.ScopeAsync(\"Person\");\r\n    var personColl = await scope.CollectionAsync(\"Person\");\r\n    var emailColl = await scope.CollectionAsync(\"EmailAddress\");\r\n\r\n    \/\/ create transaction\r\n    var cluster = bucket.Cluster;\r\n    var transaction = Transactions.Create(cluster,\r\n        TransactionConfigBuilder.Create()\r\n            .DurabilityLevel(DurabilityLevel.None)\r\n            .Build());\r\n\r\n    try\r\n    {\r\n        await transaction.RunAsync(async (context) =&gt;\r\n        {\r\n            \/\/ update person and email documents\r\n            \/\/ based on values passed in API object\r\n            var personKey = personUpdateApi.PersonId.ToString();\r\n            var emailKey = personKey + \"::\" + personUpdateApi.EmailAddressId.ToString();\r\n            var person = await context.GetAsync(personColl, personKey);\r\n            var email = await context.GetAsync(emailColl, emailKey);\r\n\r\n            var personDoc = person.ContentAs&lt;dynamic&gt;();\r\n            var emailDoc = email.ContentAs&lt;dynamic&gt;();\r\n\r\n            personDoc.FirstName = personUpdateApi.FirstName;\r\n            personDoc.LastName = personUpdateApi.LastName;\r\n            emailDoc.EmailAddress = personUpdateApi.EmailAddress;\r\n\r\n            await context.ReplaceAsync(person, personDoc);\r\n            await context.ReplaceAsync(email, emailDoc);\r\n        });\r\n        return Ok($\"Person {personUpdateApi.PersonId} name and email updated.\");\r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        return BadRequest(\"Something went wrong, transaction rolled back.\");\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Los mismos pasos principales son:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>Iniciar transacci\u00f3n (<code>transaction.RunAsync( ... )<\/code>)<\/li>\n<li><code>pruebe<\/code>\/<code>captura<\/code><\/li>\n<li>Transacci\u00f3n de compromiso (impl\u00edcita, pero <code>context.CommitAsync()<\/code> podr\u00eda utilizarse)<\/li>\n<li>Transacci\u00f3n de reversi\u00f3n (de nuevo, impl\u00edcita, pero <code>context.RollbackAsync()<\/code> ).<\/li>\n<\/ol>\n<\/div>\n<div class=\"paragraph\">\n<p>En ambos casos, tenemos una transacci\u00f3n ACID. <strong>A diferencia de<\/strong> SQL Server, sin embargo, podemos <strong>m\u00e1s tarde<\/strong> optimizar y consolidar los datos en Couchbase para reducir la cantidad de transacciones ACID que necesitamos y aumentar el rendimiento.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_stored_procedures_a_sql_and_nosql_comparison\">Procedimientos almacenados: comparaci\u00f3n entre SQL y NoSQL<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Los procedimientos almacenados son un tema a veces controvertido. En general, pueden contener mucha funcionalidad y l\u00f3gica.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_stored_procedure_in_sql_server\">Procedimiento almacenado en SQL Server<\/h3>\n<div class=\"paragraph\">\n<p>He creado un procedimiento almacenado llamado \"ListSubcomponents\" (puede ver el archivo <a href=\"https:\/\/github.com\/mgroves\/SqlServerToCouchbase\">todos los detalles en GitHub<\/a>). Con Entity Framework, puede utilizar <code>FromSqlRaw<\/code> para ejecutarlo y asignar los resultados a objetos C#. He creado un objeto C# pseudo-entidad llamado <code>ListaSubcomponentes<\/code> que se utiliza s\u00f3lo para este sproc:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">\/\/ sproc example - see ExampleStoredProcedure.sql\r\n[HttpGet(\"\/getListSubcomponents\/{listPriceMin}\/{listPriceMax}\")]\r\npublic async Task&lt;IActionResult&gt; GetListSubcomponents(decimal listPriceMin, decimal listPriceMax)\r\n{\r\n    var listPriceMinParam = new SqlParameter(\"@ListPriceMin\", SqlDbType.Decimal) {Value = listPriceMin };\r\n    var listPriceMaxParam = new SqlParameter(\"@ListPriceMax\", SqlDbType.Decimal) {Value = listPriceMax };\r\n\r\n    var result = await _context.ListSubcomponents\r\n        .FromSqlRaw(\"EXECUTE dbo.ListSubcomponents @ListPriceMin, @ListPriceMax\", listPriceMinParam, listPriceMaxParam)\r\n        .ToListAsync();\r\n\r\n    return Ok(result);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>El procedimiento almacenado tiene dos par\u00e1metros.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_couchbase_user_defined_function\">Couchbase Funci\u00f3n definida por el usuario<\/h3>\n<div class=\"paragraph\">\n<p>Couchbase no tiene nada llamado \"procedimiento almacenado\" (todav\u00eda), pero tiene algo llamado funci\u00f3n definida por el usuario (UDF) que tambi\u00e9n puede contener l\u00f3gica compleja cuando sea necesario.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>He creado una UDF llamada <code>ListaSubcomponentes<\/code> (que tambi\u00e9n puede <a href=\"https:\/\/github.com\/mgroves\/SqlServerToCouchbase\">ver en GitHub<\/a>) que coincide con la funcionalidad del sproc de SQL Server.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>A continuaci\u00f3n se explica c\u00f3mo ejecutar esa UDF desde ASP.NET:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\" data-lang=\"C#\">\/\/ sproc example - see ExampleStoredProcedure.sql\r\n[HttpGet(\"\/getListSubcomponents\/{listPriceMin}\/{listPriceMax}\")]\r\npublic async Task&lt;IActionResult&gt; GetListSubcomponents(decimal listPriceMin, decimal listPriceMax)\r\n{\r\n    var bucket = await _bucketProvider.GetBucketAsync();\r\n    var cluster = bucket.Cluster;\r\n\r\n    var options = new QueryOptions();\r\n    options.Parameter(\"$listPriceMin\", listPriceMin);\r\n    options.Parameter(\"$listPriceMax\", listPriceMax);\r\n\r\n    var result = await cluster.QueryAsync&lt;ListSubcomponent&gt;(\r\n        \"SELECT l.* FROM ListSubcomponents($listPriceMin, $listPriceMax) l\", options);\r\n\r\n    return Ok(await result.Rows.ToListAsync());\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Invocarlo en Couchbase con dos par\u00e1metros es muy similar a usar FromSqlRaw con Entity Framework.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_performance_sql_to_nosql_comparison\">Rendimiento - Comparaci\u00f3n de SQL con NoSQL<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Ahora que he convertido la aplicaci\u00f3n para utilizar Couchbase, \u00bfla nueva versi\u00f3n funciona al menos tan r\u00e1pido como la antigua versi\u00f3n de SQL Server?<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Es una pregunta complicada de responder porque:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>No he hecho NINGUNA optimizaci\u00f3n en el modelo de datos. Todav\u00eda estoy usando la conversi\u00f3n literal de datos de <a href=\"https:\/\/www.couchbase.com\/blog\/es\/sql-to-nosql-automated-migration\/\">el puesto anterior<\/a>.<\/li>\n<li>El acceso a los datos puede variar mucho de un caso de uso a otro.<\/li>\n<li>Los entornos pueden variar mucho de una persona a otra y de una empresa a otra.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Sin embargo, quer\u00eda hacer algunas pruebas de carga para comprobar que todo est\u00e1 bien.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Ejecut\u00e9 ambas aplicaciones en mi m\u00e1quina local y utilic\u00e9 <a href=\"https:\/\/ngrok.com\">ngrok<\/a> para exponerlos a Internet. A continuaci\u00f3n, utilic\u00e9 <a href=\"https:\/\/loader.io\/\">loader.io<\/a> (una excelente herramienta para pruebas de carga con concurrencia). A continuaci\u00f3n, corr\u00ed algunas pruebas r\u00e1pidas de rendimiento contra s\u00f3lo el punto final 'paginaci\u00f3n'. Este es el punto final que m\u00e1s me preocupa para el rendimiento, y tambi\u00e9n creo que es el m\u00e1s \"manzanas con manzanas\" SQL y NoSQL comparaci\u00f3n entre los puntos finales.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_load_testing_sql_and_nosql_comparison\">Comparaci\u00f3n de pruebas de carga SQL y NoSQL<\/h3>\n<div class=\"paragraph\">\n<p>Estos son los resultados de la aplicaci\u00f3n SQL Server:<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><span class=\"image\"><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/05\/13301-sql-server-loader-performance.png\" alt=\"SQL and NoSQL comparison - SQL Server load testing\" \/><\/span><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Y aqu\u00ed est\u00e1n los resultados de la aplicaci\u00f3n Couchbase Server:<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><span class=\"image\"><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/05\/13302-couchbase-server-loader-performance.png\" alt=\"SQL and NoSQL comparison - Couchbase Server load testing\" \/><\/span><\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_interpreting_the_results_of_the_sql_and_nosql_comparison_load_test\">Interpretaci\u00f3n de los resultados de la prueba de carga comparativa SQL y NoSQL<\/h3>\n<div class=\"paragraph\">\n<p>Esto no pretende ser un punto de referencia o un dato que diga \"Couchbase es m\u00e1s r\u00e1pido que SQL Server\".<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>S\u00f3lo pretende ser una comprobaci\u00f3n de cordura.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Si no obtengo al menos el mismo rendimiento bajo carga que antes, quiz\u00e1 est\u00e9 haciendo algo mal. Este es un beneficio crucial para el <a href=\"https:\/\/www.couchbase.com\/blog\/es\/proof-of-concept-move-relational\/\">prueba de concepto<\/a> proceso. Aunque Couchbase, especialmente Couchbase 7, es muy amigable con las relaciones, todav\u00eda hay diferencias y matices entre <strong>cada<\/strong> y este proceso le ayudar\u00e1 a identificar las diferencias m\u00e1s importantes para usted y su proyecto.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Si buscas puntos de referencia m\u00e1s s\u00f3lidos, aqu\u00ed tienes algunos recursos que puedes consultar:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/es\/benchmarks\/\">Informes comparativos de Altoros<\/a> (3\u00aa parte)<\/li>\n<li><a href=\"https:\/\/resources.couchbase.com\/c\/altoros-report-eval-nosql-dbaas-ycsb?x=p2kCzD#zoom=100\" target=\"_blank\" rel=\"noopener\">Puntos de referencia en la nube<\/a><\/li>\n<li>Servidor Couchbase <a href=\"https:\/\/showfast.sc.couchbase.com\/#\/timeline\/Linux\/kv\/max_ops\/all\">\"Puntos de referencia \"ShowFast<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_conclusion\">Conclusi\u00f3n<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>La comparaci\u00f3n de SQL y NoSQL y la conversi\u00f3n del c\u00f3digo de la aplicaci\u00f3n, combinadas con algunas pruebas de carga muy b\u00e1sicas, me demuestran que s\u00ed:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Alojar un modelo de datos relacional tal cual, sin cambios de modelado<\/li>\n<li>Convertir punto(s) final(es) ASP.NET para utilizar el SDK de Couchbase<\/li>\n<li>Se espera un rendimiento al menos igual de bueno al principio, con mucho margen para escalar y mejorar, con un riesgo bajo.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Tu caso de uso puede variar, pero recuerda tambi\u00e9n que durante esta conversi\u00f3n, Couchbase nos dio:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>F\u00e1cil <a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/why-couchbase.html#scale-out-archi\">escalabilidad horizontal<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/why-couchbase.html#ha\">Alta disponibilidad<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/why-couchbase.html#mem-first-archi\">Almacenamiento en cach\u00e9 integrado<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/why-couchbase.html#core-db-engine\">Flexibilidad del esquema<\/a> (que es probablemente la raz\u00f3n por la que est\u00e1s buscando utilizar Couchbase en primer lugar).<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_appendix\">Anexo<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>He aqu\u00ed una gu\u00eda sucinta de la comparaci\u00f3n entre SQL y NoSQL que realic\u00e9 en la aplicaci\u00f3n.<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<colgroup>\n<col style=\"width: 50%\" \/>\n<col style=\"width: 50%\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">Funcionamiento de SQL Server<\/th>\n<th class=\"tableblock halign-left valign-top\">Operaci\u00f3n Couchbase<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Lectura\/escritura de una fila\/entidad<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/kv-operations.html\">B\u00fasqueda de claves\/valores<\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Lectura\/escritura de varias filas\/p\u00e1ginas<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/n1ql-queries-with-sdk.html\">Consulta N1QL<\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">SELECCIONE una entidad con entidades relacionadas<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Consulta N1QL con <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/nest.html\">NEST<\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">IniciarTransacci\u00f3n<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/distributed-acid-transactions-from-the-sdk.html\">Transacci\u00f3n.Crear<\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Procedimiento almacenado<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/userfun.html\">UDF<\/a> (<a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/eventing\/eventing-overview.html\">Eventos<\/a> tambi\u00e9n puede ser \u00fatil en este caso)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>Recordatorios:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>Cambie a la API de clave\/valor cuando pueda<\/li>\n<li>Utilizar la indexaci\u00f3n, la visualizaci\u00f3n del plan de indexaci\u00f3n y el asesor de \u00edndices al escribir N1QL<\/li>\n<li>Utilice una transacci\u00f3n ACID (\u00fanicamente) cuando necesite<\/li>\n<li>Piense en los objetivos de rendimiento y establezca una forma de ponerlos a prueba.<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_next_steps\">Pr\u00f3ximos pasos<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Echa un vistazo <a href=\"https:\/\/www.couchbase.com\/blog\/es\/downloads\/\">Couchbase Server 7, actualmente en fase beta<\/a>hoy. Es una descarga gratuita. Pruebe a cargar sus datos relacionales en \u00e9l, convirtiendo algunos puntos finales, y vea si el proceso le funciona.<\/p>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>This SQL and NoSQL comparison is the next step after converting your SQL Server database to Couchbase. In the previous post, I copied AdventureWorks from SQL Server to Couchbase. In this post, I\u2019m going to show an ASP.NET Core application [&hellip;]<\/p>","protected":false},"author":71,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1811,10126,1816,1812,2396],"tags":[9499,1556],"ppma_author":[8937],"class_list":["post-11147","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-asp-dotnet","category-couchbase-server","category-n1ql-query","category-transactions","tag-acid-transactions","tag-sql-server"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.2 (Yoast SEO v26.2) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>SQL and NoSQL comparison: ASP.NET application - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"This SQL and NoSQL comparison shows the application code and queries for both SQL Server and Couchbase, including paging, SQL, load testing.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/sql-nosql-comparison-aspnet-application\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL and NoSQL comparison: ASP.NET application\" \/>\n<meta property=\"og:description\" content=\"This SQL and NoSQL comparison shows the application code and queries for both SQL Server and Couchbase, including paging, SQL, load testing.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/sql-nosql-comparison-aspnet-application\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-05-27T15:01:06+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T02:40:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/05\/13301-sql-server-loader-performance.png\" \/>\n<meta name=\"author\" content=\"Matthew Groves\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mgroves\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matthew Groves\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/\"},\"author\":{\"name\":\"Matthew Groves\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58\"},\"headline\":\"SQL and NoSQL comparison: ASP.NET application\",\"datePublished\":\"2021-05-27T15:01:06+00:00\",\"dateModified\":\"2025-06-14T02:40:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/\"},\"wordCount\":1899,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"ACID transactions\",\"SQL Server\"],\"articleSection\":[\".NET\",\"ASP.NET\",\"Couchbase Server\",\"SQL++ \/ N1QL Query\",\"Transactions\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/\",\"name\":\"SQL and NoSQL comparison: ASP.NET application - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2021-05-27T15:01:06+00:00\",\"dateModified\":\"2025-06-14T02:40:16+00:00\",\"description\":\"This SQL and NoSQL comparison shows the application code and queries for both SQL Server and Couchbase, including paging, SQL, load testing.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SQL and NoSQL comparison: ASP.NET application\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58\",\"name\":\"Matthew Groves\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/ba51e6aacc53995c323a634e4502ef54\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g\",\"caption\":\"Matthew Groves\"},\"description\":\"Matthew D. Groves is a guy who loves to code. It doesn't matter if it's C#, jQuery, or PHP: he'll submit pull requests for anything. He has been coding professionally ever since he wrote a QuickBASIC point-of-sale app for his parent's pizza shop back in the 90s. He currently works as a Senior Product Marketing Manager for Couchbase. His free time is spent with his family, watching the Reds, and getting involved in the developer community. He is the author of AOP in .NET, Pro Microservices in .NET, a Pluralsight author, and a Microsoft MVP.\",\"sameAs\":[\"https:\/\/crosscuttingconcerns.com\",\"https:\/\/x.com\/mgroves\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/matthew-groves\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SQL and NoSQL comparison: ASP.NET application - The Couchbase Blog","description":"Esta comparaci\u00f3n de SQL y NoSQL muestra el c\u00f3digo de la aplicaci\u00f3n y las consultas tanto para SQL Server como para Couchbase, incluyendo paginaci\u00f3n, SQL, pruebas de carga.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/sql-nosql-comparison-aspnet-application\/","og_locale":"es_MX","og_type":"article","og_title":"SQL and NoSQL comparison: ASP.NET application","og_description":"This SQL and NoSQL comparison shows the application code and queries for both SQL Server and Couchbase, including paging, SQL, load testing.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/sql-nosql-comparison-aspnet-application\/","og_site_name":"The Couchbase Blog","article_published_time":"2021-05-27T15:01:06+00:00","article_modified_time":"2025-06-14T02:40:16+00:00","og_image":[{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/05\/13301-sql-server-loader-performance.png","type":"","width":"","height":""}],"author":"Matthew Groves","twitter_card":"summary_large_image","twitter_creator":"@mgroves","twitter_misc":{"Written by":"Matthew Groves","Est. reading time":"12 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/"},"author":{"name":"Matthew Groves","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58"},"headline":"SQL and NoSQL comparison: ASP.NET application","datePublished":"2021-05-27T15:01:06+00:00","dateModified":"2025-06-14T02:40:16+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/"},"wordCount":1899,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["ACID transactions","SQL Server"],"articleSection":[".NET","ASP.NET","Couchbase Server","SQL++ \/ N1QL Query","Transactions"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/","url":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/","name":"SQL and NoSQL comparison: ASP.NET application - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2021-05-27T15:01:06+00:00","dateModified":"2025-06-14T02:40:16+00:00","description":"Esta comparaci\u00f3n de SQL y NoSQL muestra el c\u00f3digo de la aplicaci\u00f3n y las consultas tanto para SQL Server como para Couchbase, incluyendo paginaci\u00f3n, SQL, pruebas de carga.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"SQL and NoSQL comparison: ASP.NET application"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58","name":"Matthew Groves","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/ba51e6aacc53995c323a634e4502ef54","url":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","caption":"Matthew Groves"},"description":"A Matthew D. Groves le encanta programar. No importa si se trata de C#, jQuery o PHP: enviar\u00e1 pull requests para cualquier cosa. Lleva codificando profesionalmente desde que escribi\u00f3 una aplicaci\u00f3n de punto de venta en QuickBASIC para la pizzer\u00eda de sus padres, all\u00e1 por los a\u00f1os 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.","sameAs":["https:\/\/crosscuttingconcerns.com","https:\/\/x.com\/mgroves"],"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/matthew-groves\/"}]}},"authors":[{"term_id":8937,"user_id":71,"is_guest":0,"slug":"matthew-groves","display_name":"Matthew Groves","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","author_category":"","last_name":"Groves","first_name":"Matthew","job_title":"","user_url":"https:\/\/crosscuttingconcerns.com","description":"A Matthew D. Groves le encanta programar.  No importa si se trata de C#, jQuery o PHP: enviar\u00e1 pull requests para cualquier cosa.  Lleva codificando profesionalmente desde que escribi\u00f3 una aplicaci\u00f3n de punto de venta en QuickBASIC para la pizzer\u00eda de sus padres, all\u00e1 por los a\u00f1os 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."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/11147","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/71"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=11147"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/11147\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=11147"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=11147"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=11147"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=11147"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}