{"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\/pt\/sql-nosql-comparison-aspnet-application\/","title":{"rendered":"Compara\u00e7\u00e3o entre SQL e NoSQL: Aplicativo ASP.NET"},"content":{"rendered":"<div class=\"paragraph\">\n<p>Essa compara\u00e7\u00e3o entre SQL e NoSQL \u00e9 a pr\u00f3xima etapa ap\u00f3s a convers\u00e3o do seu banco de dados do SQL Server para o Couchbase. Em <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/sql-to-nosql-automated-migration\/\">a postagem anterior<\/a>Em um dos meus testes, copiei o AdventureWorks do SQL Server para o Couchbase.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Nesta postagem, mostrarei um aplicativo ASP.NET Core que usa o SQL Server e como esse mesmo aplicativo usaria o Couchbase. Se quiser acompanhar, voc\u00ea pode conferir o <a href=\"https:\/\/github.com\/mgroves\/SqlServerToCouchbase\">Projeto SqlServerToCouchbase<\/a> no GitHub.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Ao contr\u00e1rio da postagem anterior, n\u00e3o estou tentando fazer uma convers\u00e3o \"autom\u00e1tica\" de um aplicativo. Em vez disso, pense nisso mais como uma compara\u00e7\u00e3o entre SQL e NoSQL no n\u00edvel do aplicativo.<\/p>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_asp_net_sql_server_applications\">Aplicativos ASP.NET SQL Server<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Criei um aplicativo muito simples no estilo da API REST do ASP.NET Core. Usei o Entity Framework, mas se voc\u00ea estiver usando Dapper, ADO.NET, NHibernate etc., ainda poder\u00e1 acompanhar o processo.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Cada endpoint retorna JSON. Tamb\u00e9m adicionei o Swashbuckle ao projeto, para que voc\u00ea possa emitir solicita\u00e7\u00f5es diretamente do navegador via OpenAPI.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_asp_net_couchbase_server_application\">Aplicativo do servidor ASP.NET Couchbase<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>A vers\u00e3o Couchbase do aplicativo retorna os mesmos dados, porque est\u00e1 usando os mesmos dados do SQL Server AdventureWorks.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>No aplicativo, estou usando o <a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/hello-world\/start-using-sdk.html\">SDK do Couchbase .NET<\/a> e <a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/distributed-acid-transactions-from-the-sdk.html\">Transa\u00e7\u00f5es do Couchbase<\/a> bibliotecas. (Voc\u00ea poderia usar <a href=\"https:\/\/github.com\/couchbaselabs\/Linq2Couchbase\">Linq2Couchbase<\/a> como um tipo de substitui\u00e7\u00e3o do Entity Framework).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Caso contr\u00e1rio, o aplicativo \u00e9 o mesmo, fornecendo uma compara\u00e7\u00e3o (e contraste) entre SQL e NoSQL. Os pontos de extremidade est\u00e3o retornando JSON, e o Swashbuckle est\u00e1 instalado.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>H\u00e1 um controlador em cada amostra. Vamos examinar cada endpoint no controlador e realizar uma compara\u00e7\u00e3o SQL e NoSQL.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_sql_and_nosql_comparison_get_by_id\">Compara\u00e7\u00e3o entre SQL e NoSQL: Obter por ID<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Vamos come\u00e7ar com o <code>GetPersonByIdAsync<\/code> endpoint. Dado um ID de pessoa, esse ponto de extremidade retorna os dados da pessoa para o ID fornecido.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_sql_server\">SQL Server<\/h3>\n<div class=\"paragraph\">\n<p>Aqui est\u00e1 o exemplo do SQL Server usando o 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>Tamb\u00e9m escrevi outra vers\u00e3o desse m\u00e9todo, chamada <code>GetPersonByIdRawAsync<\/code> que usa uma consulta SQL \"bruta\". Essa consulta \u00e9 muito parecida com a que o Entity Framework (acima) gera, e \u00e9 semelhante a uma abordagem 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>Observe que, de qualquer forma, uma consulta SQL est\u00e1 sendo executada.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Com o N1QL, podemos consultar os dados no Couchbase de forma muito semelhante. Aqui est\u00e1 o <code>GetPersonByIdRawAsync<\/code> no projeto 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>(H\u00e1 uma etapa extra que vai de \"bucket\" para \"cluster\". Ela poderia ser ignorada, mas como uso bucket em outras partes do controlador, deixei-a l\u00e1).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>No entanto, o uso de uma consulta N1QL envolve alguma sobrecarga extra (indexa\u00e7\u00e3o, an\u00e1lise de consulta etc.). Com o Couchbase, se j\u00e1 soubermos o ID da pessoa, podemos ignorar uma consulta N1QL e fazer uma pesquisa direta de chave\/valor (K\/V).<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_get_by_id_with_k_v\">Obter por ID com K\/V<\/h3>\n<div class=\"paragraph\">\n<p>A chave j\u00e1 \u00e9 conhecida; ela \u00e9 fornecida como um argumento. Em vez de usar SQL, vamos fazer uma pesquisa de chave\/valor. Fiz isso em um m\u00e9todo de endpoint chamado <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>Ao contr\u00e1rio do SQL Server, o Couchbase oferece suporte a uma variedade de APIs para interagir com os dados. Nesse caso, a pesquisa de chave\/valor estar\u00e1 extraindo o documento Person diretamente da mem\u00f3ria. N\u00e3o h\u00e1 necessidade de analisar uma consulta SQL ou usar qualquer indexa\u00e7\u00e3o. As pesquisas de chave\/valor no Couchbase geralmente s\u00e3o medidas em microssegundos.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Minha recomenda\u00e7\u00e3o: use a pesquisa de chave\/valor sempre que poss\u00edvel.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_get_an_expanded_entity_by_id\">Obter uma entidade expandida por ID<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Os dados podem ser complexos e abranger v\u00e1rias tabelas (ou v\u00e1rios documentos, no caso do Couchbase). Dependendo das ferramentas que estiver usando, voc\u00ea pode ter alguma funcionalidade que possa carregar entidades relacionadas.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Por exemplo, com o Entity Framework, voc\u00ea pode usar um <code>Incluir<\/code> para atrair entidades relacionadas, como mostrado neste <code>GetPersonByIdExpandedAsync<\/code> exemplo:<\/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>Nos bastidores, o Entity Framework pode gerar uma consulta JOIN e\/ou v\u00e1rias consultas SELECT para que isso aconte\u00e7a.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u00c9 nesse ponto que qualquer O\/RM (n\u00e3o apenas o Entity Framework) pode ser perigoso. Certifique-se de usar uma ferramenta como o SQL Profiler para ver quais consultas est\u00e3o realmente sendo executadas.<\/p>\n<\/div>\n<div class=\"admonitionblock note\">\n<table>\n<tbody>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Observa\u00e7\u00e3o<\/div>\n<\/td>\n<td class=\"content\">Os O\/RMs podem ajudar, mas em um <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/sql-to-nosql-automated-migration\/\">SQL para NoSQL<\/a> Em compara\u00e7\u00e3o, \u00e9 importante lembrar que a incompatibilidade de imped\u00e2ncia \u00e9 um problema muito menor no mundo NoSQL.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<div class=\"paragraph\">\n<p>Para o exemplo do Couchbase, n\u00e3o estou usando o Entity Framework, mas, em vez disso, posso usar o <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/nest.html\">Sintaxe NEST<\/a> que faz parte das extens\u00f5es N1QL do padr\u00e3o SQL. Veja como a vers\u00e3o do Couchbase do <code>GetPersonByIdExpandedAsync<\/code> apar\u00eancia:<\/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 \u00e9 um tipo de JOIN que coloca os dados JOINed em um objeto JSON aninhado. Em vez de usar um O\/RM para mapear os dados, esses dados podem ser serializados diretamente em objetos C#.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_paging_query\">Consulta de pagina\u00e7\u00e3o<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Vamos dar uma olhada em um exemplo em que N\u00c3O temos uma \u00fanica chave para procurar um dado. Vejamos um m\u00e9todo que retorna uma \"p\u00e1gina\" de resultados (talvez para preencher uma grade ou lista da interface do usu\u00e1rio).<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_paging_in_sql_server\">Pagina\u00e7\u00e3o no SQL Server<\/h3>\n<div class=\"paragraph\">\n<p>Aqui est\u00e1 a vers\u00e3o do 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>Com o Entity Framework, <code>Ordem<\/code>, <code>Pular<\/code>e <code>Pegue<\/code> s\u00e3o normalmente usados para pagina\u00e7\u00e3o. Se abrirmos o SQL Server Profiler, o SQL gerado ter\u00e1 a seguinte apar\u00eancia:<\/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> \u00e9 a sintaxe que est\u00e1 sendo usada para pagina\u00e7\u00e3o aqui.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_paging_in_couchbase\">Pagina\u00e7\u00e3o no Couchbase<\/h3>\n<div class=\"paragraph\">\n<p>A sintaxe de pagina\u00e7\u00e3o sempre varia entre as implementa\u00e7\u00f5es de SQL. O Couchbase se inclina mais para a sintaxe do Oracle\/MySQL nesse aspecto. Aqui est\u00e1 a vers\u00e3o do 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>Nesse caso, <code>LIMITE ... DESLOCAMENTO ...<\/code> est\u00e1 sendo usado.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Tamb\u00e9m quero destacar o <code>WHERE p.LastName IS NOT MISSING<\/code>. Como o Couchbase \u00e9 um banco de dados NoSQL, o mecanismo de consulta n\u00e3o pode presumir que <code>Sobrenome<\/code> estar\u00e1 em todos os documentos, mesmo com <code>ORDER BY p.LastName<\/code>. Ao adicionar este <code>ONDE<\/code> a consulta agora sabe qual \u00edndice usar. Sem isso, a consulta levar\u00e1 muito mais tempo para ser executada.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_update_with_an_acid_transaction\">Atualizar com uma transa\u00e7\u00e3o ACID<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Com o modelo de estilo relacional que estamos usando no SQL Server e no Couchbase para este exemplo, as transa\u00e7\u00f5es ACID ser\u00e3o importantes para ambos os aplicativos.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Nesses exemplos, h\u00e1 um <code>PersonUpdateApi<\/code> que permitir\u00e1 que o usu\u00e1rio atualize <strong>ambos<\/strong> o nome de uma pessoa e seu endere\u00e7o de e-mail. Como esses dados est\u00e3o em duas tabelas\/linhas separadas (SQL Server) ou dois documentos separados (Couchbase), queremos que essa seja uma opera\u00e7\u00e3o at\u00f4mica do tipo tudo ou nada.<\/p>\n<\/div>\n<div class=\"admonitionblock note\">\n<table>\n<tbody>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Observa\u00e7\u00e3o<\/div>\n<\/td>\n<td class=\"content\">Um ID \u00e9 especificado para ambos (para simplificar a API), pois \u00e9 poss\u00edvel (mas raro nesse conjunto de dados) que uma pessoa tenha v\u00e1rios endere\u00e7os de e-mail.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_acid_with_entity_framework\">ACID com o Entity Framework<\/h3>\n<div class=\"paragraph\">\n<p>Aqui est\u00e1 um exemplo de uma transa\u00e7\u00e3o ACID usando o Entity Framework para atualizar uma linha de dados na tabela Person e uma linha de dados na tabela 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>Observe as quatro partes principais de uma transa\u00e7\u00e3o:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>Iniciar transa\u00e7\u00e3o (<code>_context.Database.BeginTransactionAsync();<\/code>)<\/li>\n<li><code>tentar<\/code>\/<code>captura<\/code><\/li>\n<li>Transa\u00e7\u00e3o de confirma\u00e7\u00e3o (<code>await transaction.CommitAsync();<\/code>)<\/li>\n<li>Transa\u00e7\u00e3o de revers\u00e3o no <code>captura<\/code> (<code>transaction.RollbackAsync();<\/code>)<\/li>\n<\/ol>\n<\/div>\n<div class=\"paragraph\">\n<p>Esse \u00e9 um recurso importante em que a compara\u00e7\u00e3o entre SQL e NoSQL mudou nos \u00faltimos anos. Com o Couchbase, as transa\u00e7\u00f5es ACID agora s\u00e3o poss\u00edveis.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_acid_with_a_couchbase_transaction\">ACID com uma transa\u00e7\u00e3o do Couchbase<\/h3>\n<div class=\"paragraph\">\n<p>Com o Couchbase, a API \u00e9 um pouco diferente, mas as mesmas etapas est\u00e3o todas l\u00e1:<\/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>As etapas principais s\u00e3o as mesmas:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>Iniciar transa\u00e7\u00e3o (<code>transaction.RunAsync( ... )<\/code>)<\/li>\n<li><code>tentar<\/code>\/<code>captura<\/code><\/li>\n<li>Transa\u00e7\u00e3o de compromisso (impl\u00edcita, mas <code>contexto.CommitAsync()<\/code> poderia ser usado)<\/li>\n<li>Transa\u00e7\u00e3o de revers\u00e3o (novamente, impl\u00edcita, mas <code>contexto.RollbackAsync()<\/code> poderia ser usado).<\/li>\n<\/ol>\n<\/div>\n<div class=\"paragraph\">\n<p>Em ambos os casos, temos uma transa\u00e7\u00e3o ACID. <strong>Diferente de<\/strong> SQL Server, no entanto, podemos <strong>mais tarde<\/strong> otimizar e consolidar os dados no Couchbase para reduzir a quantidade de transa\u00e7\u00f5es ACID de que precisamos e aumentar o desempenho.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_stored_procedures_a_sql_and_nosql_comparison\">Procedimentos armazenados: uma compara\u00e7\u00e3o entre SQL e NoSQL<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Os procedimentos armazenados s\u00e3o um t\u00f3pico \u00e0s vezes controverso. De modo geral, eles podem conter muita funcionalidade e l\u00f3gica.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_stored_procedure_in_sql_server\">Procedimento armazenado no SQL Server<\/h3>\n<div class=\"paragraph\">\n<p>Criei um procedimento armazenado chamado \"ListSubcomponents\" (voc\u00ea pode ver o arquivo <a href=\"https:\/\/github.com\/mgroves\/SqlServerToCouchbase\">Detalhes completos no GitHub<\/a>). Com o Entity Framework, voc\u00ea pode usar <code>FromSqlRaw<\/code> para execut\u00e1-lo e mapear os resultados para objetos C#. Criei um objeto C# de pseudo-entidade chamado <code>ListSubcomponents<\/code> que \u00e9 usado apenas para esse 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>O procedimento armazenado tem dois par\u00e2metros.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_couchbase_user_defined_function\">Fun\u00e7\u00e3o definida pelo usu\u00e1rio do Couchbase<\/h3>\n<div class=\"paragraph\">\n<p>O Couchbase n\u00e3o tem nada chamado de \"procedimento armazenado\" (ainda), mas tem algo chamado de fun\u00e7\u00e3o definida pelo usu\u00e1rio (UDF) que tamb\u00e9m pode conter l\u00f3gica complexa quando necess\u00e1rio.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Criei um UDF chamado <code>ListSubcomponents<\/code> (que voc\u00ea tamb\u00e9m pode <a href=\"https:\/\/github.com\/mgroves\/SqlServerToCouchbase\">visualiza\u00e7\u00e3o no GitHub<\/a>) que corresponde \u00e0 funcionalidade do sproc do SQL Server.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Veja a seguir como executar esse UDF no 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>Invoc\u00e1-lo no Couchbase com dois par\u00e2metros \u00e9 muito semelhante a usar o FromSqlRaw com o Entity Framework.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_performance_sql_to_nosql_comparison\">Desempenho - Compara\u00e7\u00e3o entre SQL e NoSQL<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Agora que converti o aplicativo para usar o Couchbase, a nova vers\u00e3o \u00e9 executada pelo menos t\u00e3o rapidamente quanto a vers\u00e3o antiga do SQL Server?<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u00c9 uma pergunta complicada de responder porque:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>N\u00e3o fiz NENHUMA otimiza\u00e7\u00e3o no modelo de dados. Ainda estou usando a convers\u00e3o literal de dados de <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/sql-to-nosql-automated-migration\/\">a postagem anterior<\/a>.<\/li>\n<li>O acesso aos dados pode variar muito de caso de uso para caso de uso.<\/li>\n<li>Os ambientes podem variar muito de pessoa para pessoa e de empresa para empresa.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>No entanto, eu queria fazer alguns testes de carga \"por tr\u00e1s do envelope\" como uma verifica\u00e7\u00e3o de sanidade.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Executei os dois aplicativos em minha m\u00e1quina local e usei <a href=\"https:\/\/ngrok.com\">ngrok<\/a> para exp\u00f4-los \u00e0 Internet. Em seguida, usei <a href=\"https:\/\/loader.io\/\">carregador.io<\/a> (uma excelente ferramenta para testes de carga com concorr\u00eancia). Em seguida, executei alguns testes r\u00e1pidos de desempenho somente com o endpoint de \"pagina\u00e7\u00e3o\". Esse \u00e9 o endpoint com o qual estou mais preocupado em termos de desempenho, e tamb\u00e9m acho que \u00e9 a compara\u00e7\u00e3o SQL e NoSQL mais \"igualit\u00e1ria\" entre os endpoints.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_load_testing_sql_and_nosql_comparison\">Compara\u00e7\u00e3o entre SQL e NoSQL para teste de carga<\/h3>\n<div class=\"paragraph\">\n<p>Aqui est\u00e3o os resultados do aplicativo do 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>E aqui est\u00e3o os resultados do aplicativo 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\">Interpreta\u00e7\u00e3o dos resultados do teste de carga de compara\u00e7\u00e3o entre SQL e NoSQL<\/h3>\n<div class=\"paragraph\">\n<p>N\u00e3o se trata de um benchmark ou de um ponto de dados que diga que \"o Couchbase \u00e9 mais r\u00e1pido que o SQL Server\".<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>O objetivo \u00e9 apenas uma verifica\u00e7\u00e3o de sanidade.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Se eu n\u00e3o estiver obtendo um desempenho pelo menos t\u00e3o bom sob carga quanto antes, talvez eu esteja fazendo algo errado. Esse \u00e9 um benef\u00edcio crucial para o <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/proof-of-concept-move-relational\/\">prova de conceito<\/a> processo. Embora o Couchbase, especialmente o Couchbase 7, seja muito compat\u00edvel com o sistema relacional, ainda existem diferen\u00e7as e nuances entre <strong>todos<\/strong> e esse processo o ajudar\u00e1 a identificar as diferen\u00e7as que mais importam para voc\u00ea e seu projeto.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Se estiver procurando benchmarks mais robustos, aqui est\u00e3o alguns recursos que voc\u00ea pode consultar:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/benchmarks\/\">Relat\u00f3rios de benchmark da Altoros<\/a> (terceiros)<\/li>\n<li><a href=\"https:\/\/resources.couchbase.com\/c\/altoros-report-eval-nosql-dbaas-ycsb?x=p2kCzD#zoom=100\" target=\"_blank\" rel=\"noopener\">Benchmarks de nuvem<\/a><\/li>\n<li>Servidor Couchbase <a href=\"https:\/\/showfast.sc.couchbase.com\/#\/timeline\/Linux\/kv\/max_ops\/all\">\"Benchmarks \"ShowFast<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_conclusion\">Conclus\u00e3o<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>A compara\u00e7\u00e3o e a convers\u00e3o de SQL e NoSQL do c\u00f3digo do aplicativo, combinadas com alguns testes de carga muito b\u00e1sicos, mostram que eu posso:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Hospedar um modelo de dados relacional como est\u00e1, sem altera\u00e7\u00f5es de modelagem<\/li>\n<li>Converter os pontos de extremidade do ASP.NET para usar o SDK do Couchbase<\/li>\n<li>Espere um desempenho pelo menos t\u00e3o bom no in\u00edcio, com muito espa\u00e7o para escalar e melhorar, com baixo risco.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Seu caso de uso pode variar, mas lembre-se tamb\u00e9m de que, durante essa convers\u00e3o, o Couchbase nos forneceu:<\/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\">escalabilidade horizontal<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/why-couchbase.html#ha\">Alta disponibilidade<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/why-couchbase.html#mem-first-archi\">Armazenamento em cache incorporado<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/why-couchbase.html#core-db-engine\">Flexibilidade do esquema<\/a> (que \u00e9 provavelmente o motivo pelo qual voc\u00ea est\u00e1 procurando usar o Couchbase em primeiro lugar).<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_appendix\">Ap\u00eandice<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Aqui est\u00e1 um guia sucinto da compara\u00e7\u00e3o entre SQL e NoSQL que fiz no aplicativo.<\/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\">Opera\u00e7\u00e3o do SQL Server<\/th>\n<th class=\"tableblock halign-left valign-top\">Opera\u00e7\u00e3o do Couchbase<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Ler\/gravar uma linha\/entidade<\/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\">Pesquisa de chave\/valor<\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Ler\/gravar v\u00e1rias linhas\/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\">SELECIONAR uma entidade com entidades relacionadas<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Consulta N1QL com <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\">BeginTransaction<\/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\">Transa\u00e7\u00e3o.Create<\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Procedimento armazenado<\/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> tamb\u00e9m pode ser \u00fatil aqui)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>Lembretes:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>Mude para a API de chave\/valor quando puder<\/li>\n<li>Use a indexa\u00e7\u00e3o, a visualiza\u00e7\u00e3o do plano de indexa\u00e7\u00e3o e o consultor de \u00edndices ao escrever N1QL<\/li>\n<li>Use uma transa\u00e7\u00e3o ACID (somente) quando precisar<\/li>\n<li>Pense nas metas de desempenho e estabele\u00e7a uma maneira de test\u00e1-las<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_next_steps\">Pr\u00f3ximas etapas<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Confira <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/downloads\/\">Couchbase Server 7, atualmente em vers\u00e3o beta<\/a>hoje. \u00c9 um download gratuito. Tente carregar seus dados relacionais nele, convertendo alguns pontos de extremidade, e veja se o processo funciona para voc\u00ea.<\/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\/pt\/sql-nosql-comparison-aspnet-application\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\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\/pt\/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\":\"pt-BR\",\"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\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\",\"@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\/pt\/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 compara\u00e7\u00e3o entre SQL e NoSQL mostra o c\u00f3digo do aplicativo e as consultas do SQL Server e do Couchbase, incluindo pagina\u00e7\u00e3o, SQL e teste 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\/pt\/sql-nosql-comparison-aspnet-application\/","og_locale":"pt_BR","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\/pt\/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":"pt-BR","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 compara\u00e7\u00e3o entre SQL e NoSQL mostra o c\u00f3digo do aplicativo e as consultas do SQL Server e do Couchbase, incluindo pagina\u00e7\u00e3o, SQL e teste de carga.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/sql-nosql-comparison-aspnet-application\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@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":"Blog do Couchbase","description":"Couchbase, o banco de dados 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":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@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":"pt-BR","@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 \u00e9 um cara que adora programar. N\u00e3o importa se \u00e9 C#, jQuery ou PHP: ele enviar\u00e1 solicita\u00e7\u00f5es de pull para qualquer coisa. Ele tem programado profissionalmente desde que escreveu um aplicativo de ponto de venda QuickBASIC para a pizzaria de seus pais nos anos 90. Atualmente, ele trabalha como gerente s\u00eanior de marketing de produtos da Couchbase. Seu tempo livre \u00e9 passado com a fam\u00edlia, assistindo aos Reds e participando da comunidade de desenvolvedores. Ele \u00e9 autor de AOP in .NET, Pro Microservices in .NET, autor da Pluralsight e Microsoft MVP.","sameAs":["https:\/\/crosscuttingconcerns.com","https:\/\/x.com\/mgroves"],"url":"https:\/\/www.couchbase.com\/blog\/pt\/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":"Matthew D. Groves \u00e9 um cara que adora programar.  N\u00e3o importa se \u00e9 C#, jQuery ou PHP: ele enviar\u00e1 solicita\u00e7\u00f5es de pull para qualquer coisa.  Ele tem programado profissionalmente desde que escreveu um aplicativo de ponto de venda QuickBASIC para a pizzaria de seus pais nos anos 90.  Atualmente, ele trabalha como gerente s\u00eanior de marketing de produtos da Couchbase. Seu tempo livre \u00e9 passado com a fam\u00edlia, assistindo aos Reds e participando da comunidade de desenvolvedores.  Ele \u00e9 autor de AOP in .NET, Pro Microservices in .NET, autor da Pluralsight e Microsoft MVP."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/11147","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/71"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=11147"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/11147\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=11147"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=11147"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=11147"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=11147"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}