<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tucaz.blog.now() &#187; cache</title>
	<atom:link href="http://blog.tucaz.net/tag/cache/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.tucaz.net</link>
	<description>Software architecture, agile and all that stuff that you can find everywhere</description>
	<lastBuildDate>Tue, 11 Jan 2011 21:00:29 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Performance: NHibernate versus ADO.NET</title>
		<link>http://blog.tucaz.net/2010/08/31/performance-nhibernate-versus-ado-net/</link>
		<comments>http://blog.tucaz.net/2010/08/31/performance-nhibernate-versus-ado-net/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 01:18:21 +0000</pubDate>
		<dc:creator>tucaz</dc:creator>
				<category><![CDATA[Banco de Dados]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[NHibernate]]></category>
		<category><![CDATA[adhoc]]></category>
		<category><![CDATA[ADO.NET]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[stored procedures]]></category>

		<guid isPermaLink="false">http://blog.tucaz.net/?p=466</guid>
		<description><![CDATA[Disclaimer
Os testes neste post apresentados não representam uma amostra exata ou fidedigna que represente uma condição real de acesso a dados de uma aplicação a fim de comparar a performance das duas tecnologias. A idéia é apenas mostrar alguns dados e exemplos com o objetivo de dismistificar a idéia de que ORM é uma ferramenta [...]]]></description>
			<content:encoded><![CDATA[<h1><em><span style="color: #ff0000">Disclaimer</span></em></h1>
<p><em><span style="color: #ff0000">Os testes neste post apresentados não representam uma amostra exata ou fidedigna que represente uma condição real de acesso a dados de uma aplicação a fim de comparar a performance das duas tecnologias. A idéia é apenas mostrar alguns dados e exemplos com o objetivo de dismistificar a idéia de que ORM é uma ferramenta lenta e estes testes são apenas um exercício.</span></em></p>
<p><em><span style="color: #ff0000">Sou usuário de NHibernate e defendo o uso de ORM’s portanto as conclusões apresentadas com certeza não são as mais imparciais possíveis.</span></em></p>
<p>Motivado <a title="DDD - Objetos de consulta usando ORM - o que vcs acham? @ DotNetArchitects" href="http://groups.google.com/group/dotnetarchitects/browse_thread/thread/dc01630511ec34ec">por esta thread no DNA hoje</a> decidi fazer alguns testes de perfomance pra comparar acesso a dados utilizando ADO.NET nativo (queries AdHoc e Stored Procedures) versus NHibernate.</p>
<p>Sempre rolam diversas discussões a respeito do assunto e a conclusão que geralmente se chega é de que qualquer ORM vai ser mais lento do que uma chamada nativa. É uma conclusão óbvia já que utilizar um ORM é adicionar uma camada de abstração a mais dentro da nossa aplicação. No entanto, até então eu nunca havia efetuado nenhuma medição pra ver qual a diferença de performance.</p>
<p>Todos os testes foram executados na minha máquina com código compilado em modo Release com banco de dados Sql Server 2008 também local.</p>
<p>Vamos aos testes.</p>
<h1>Cenário de testes</h1>
<p>Criei uma tabela (Product) e populei com cerca de 500 registros vindos do AdventureWorks (banco de dados exemplo do SqlServer).</p>
<p><a href="http://blog.tucaz.net/wp-content/uploads/2010/08/image.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Modelo de Dados" border="0" alt="Modelo de Dados" src="http://blog.tucaz.net/wp-content/uploads/2010/08/image_thumb.png" width="237" height="175" /></a></p>
<p>Contra essa tabela executei duas categorias de testes:</p>
<ol>
<li>Carregar todos os registros da tabela em um List&lt;&gt; </li>
<li>Carregar apenas um registro </li>
</ol>
<p>Pra ficar mais interessante fiz algumas variações dos testes:</p>
<ul>
<li>Query AdHoc/Inline </li>
<li>Query AdHoc/Inline com hidratação<strong>[1]</strong> via reflection </li>
<li>Query utilizando uma procedure </li>
<li>NHibernate com LINQ </li>
<li>NHibernate com HQL </li>
<li>NHibernate com Criteria </li>
<li>Nhibernate com Projections </li>
</ul>
<p>Como rodando uma única vez não foi possível obter dados suficientes, executei cada teste dentro de um loop com 1000 (numberOfIterations = 1000) iterações que resultou no código abaixo:</p>
<p>Método principal:</p>
<pre class="csharp" name="code">static void Main(string[] args)
{
    for (int i = 1; i &lt;= 3; i++)
    {
        Console.WriteLine(&quot;Test &quot; + i.ToString());
        Console.WriteLine(&quot;======================&quot;);

        SqlAdHocAllProducts();
        SqlAdHocAllProductsWithReflection();
        SProcAllProducts();
        NHibernateAllProductsWithLinq();
        NHibernateAllProductsWithHql();
        NHibernateAllProductsWithCriteria();
        NHibernateAllProductsWithProjections();

        SqlAdHocOneProduct();
        SqlAdHocOneProductWithReflection();
        SProcOneProduct();
        NHibernateOneProduct();

        Console.WriteLine();
    }

    Console.ReadLine();
}</pre>
<p>
  <br />Um dos métodos usando Sql AdHoc e outro usando NHibernate:</p>
<p></p>
<pre class="csharp" name="code">private static void SqlAdHocAllProducts()
{
    List&lt;Product&gt; allProducts = null;

    var connectionString = &quot;Data Source=(local);Integrated Security=SSPI;Database=TDC2010;&quot;;
    var select = @&quot;SELECT P.Id, P.Description, P.Name, P.Price FROM dbo.Product P&quot;;

    var connection = new SqlConnection(connectionString);
    connection.Open();

    Stopwatch watch = new Stopwatch();
    watch.Start();

    for (int i = 0; i &lt; numberOfIterations; i++)
    {
        allProducts = new List&lt;Product&gt;();
        var command = new SqlCommand(select, connection);
        var reader = command.ExecuteReader();

        while (reader.Read())
        {
            allProducts.Add(new Product()
                {

                    Id = Convert.ToInt32(reader[&quot;Id&quot;]),
                    Name = Convert.ToString(reader[&quot;Name&quot;]),
                    Description = Convert.ToString(reader[&quot;Description&quot;]),
                    Price = Convert.ToDecimal(reader[&quot;price&quot;])
                });
        }

        reader.Close();
    }

    watch.Stop();

    connection.Close();
    connection.Dispose();

    Console.WriteLine(
        &quot;Loading &quot; + allProducts.Count + &quot; Products with Sql AdHoc took &quot; + watch.ElapsedMilliseconds + &quot; ms&quot;);
}</pre>
<p>
  </p>
<pre class="csharp" name="code">private static void NHibernateAllProductsWithLinq()
{
    List&lt;Product&gt; allProducts = null;

    var session = CreateForSqlServer().OpenSession();

    Stopwatch watch = new Stopwatch();
    watch.Start();

    for (int i = 0; i &lt; numberOfIterations; i++)
    {
        allProducts = session.Linq&lt;Product&gt;().ToList();
    }

    watch.Stop();

    session.Close();

    Console.WriteLine(
        &quot;Loading &quot; + allProducts.Count + &quot; Products with NHibernate took &quot; + watch.ElapsedMilliseconds + &quot; ms&quot;);
}</pre>
<p><strong>Vou omitir o restante dos métodos para evitar duplicações já que eles são apenas variações dos dois exemplos acima.</strong></p>
<h1>Resultado Geral</h1>
<p><a href="http://blog.tucaz.net/wp-content/uploads/2010/08/image1.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Resultados dos Testes" border="0" alt="Resultados dos Testes" src="http://blog.tucaz.net/wp-content/uploads/2010/08/image_thumb1.png" width="681" height="648" /></a></p>
<h1>Análise dos Resultados</h1>
<h3>Stored Procedures versus Queries AdHoc/Inline [500 registros]</h3>
<p>A diferença entre o uso de stored procedures e queries AdHoc é praticamente inexistente. A diferença média medida foi de <strong>menos de 1%</strong>.</p>
<p>Isso acontece, pois não existe complexidade suficiente neste tipo de query para que a armazenagem do plano de execução no banco de dados faça diferença.</p>
<p>Portanto, na grande maioria dos cenários Stored Procedures não são necessárias.</p>
<h3>NHibernate versus NHibernate [500 registros]</h3>
<p>Na média, todas as variações de consulta utilizando NHibernate também tiveram <strong>mais ou menos o mesmo resultado (~1500ms)</strong> com exceção do uso de <strong>Projections</strong>, que levou o dobro<strong> (~3000ms)</strong> do tempo.</p>
<p>Não conheço o NHibernate suficiente pra afirmar com 100% de certeza o motivo, mas acredito que seja pelo fato de esse tipo de query retornar Arrays bidimensionais que são criados e redimensionados em runtime até que todos os itens possam ser acomodados.</p>
<h3>NHibernate versus ADO.NET [500 registros]</h3>
<p>Este e o comparativo mais importante. Carregando (e hidratando) 500 registros o ADO.NET é cerca de <strong>30% mais</strong> rapido do que o NHibernate. A causa dessa discrepância é uma só e se chama reflection.</p>
<p>Apesar de todas as otimizações o NHibernate utiliza-se de reflection para efetuar a hidratação<strong>[1] </strong>de todos os objetos e é dai que vem a queda de performance que fica clara quando executamos queries AdHoc usando hidratação via reflection conforme o código abaixo.</p>
<pre class="csharp" name="code">private static void SqlAdHocAllProductsWithReflection()
{
    List&lt;Product&gt; allProducts = null;

    var connectionString = &quot;Data Source=(local);Integrated Security=SSPI;Database=TDC2010;&quot;;
    var select = @&quot;SELECT P.Id, P.Description, P.Name, P.Price FROM dbo.Product P&quot;;

    var connection = new SqlConnection(connectionString);
    connection.Open();

    Stopwatch watch = new Stopwatch();
    watch.Start();

    for (int i = 0; i &lt; numberOfIterations; i++)
    {
        allProducts = new List&lt;Product&gt;();
        var command = new SqlCommand(select, connection);
        var reader = command.ExecuteReader();

        while (reader.Read())
        {
            var newProduct = Activator.CreateInstance&lt;Product&gt;();
            SetProperty(newProduct, &quot;Id&quot;, Convert.ToInt32(reader[&quot;Id&quot;]));
            SetProperty(newProduct, &quot;Description&quot;, Convert.ToString(reader[&quot;Description&quot;]));
            SetProperty(newProduct, &quot;Name&quot;, Convert.ToString(reader[&quot;Name&quot;]));
            SetProperty(newProduct, &quot;Price&quot;, Convert.ToDecimal(reader[&quot;Price&quot;]));
            allProducts.Add(newProduct);
        }

        reader.Close();
    }

    watch.Stop();

    connection.Close();
    connection.Dispose();

    Console.WriteLine(
&quot;Loading &quot; + allProducts.Count + &quot; Products with Sql AdHoc and Reflection took &quot; + watch.ElapsedMilliseconds + &quot; ms&quot;);
}

private static void SetProperty(object instance, string property, object val)
{
    Type t = instance.GetType();
    var prop = t.GetProperty(property, BindingFlags.Instance | BindingFlags.Public);
    prop.SetValue(instance, val, null);
}</pre>
<p>Este código quando executado demora cerca de <strong>6000ms, ou 4 vezes mais</strong>, do que o código executado pelo NHibernate.</p>
<p>Mas por que a diferença não é de 30%? Porque o NHibernate possui otimizações quanto ao modo de hidratar um objeto via reflection. No meu código acima podemos ver, por exemplo, que toda vez que chamo o método SetProperty o Type da propriedade a ser refletida ainda não está criado. Provavelmente o NHibernate deve manter cache deste tipo de informação (e de outras) a fim de otimizar o processo de hidratação das entidades.</p>
<h3>Stored Procedures versus Queries AdHoc/Inline [1 registro]</h3>
<p>Mesmo resultado do cenário onde 500 registros são carregados. Não há diferença.</p>
<h3>NHibernate versus ADO.NET [1 registro]</h3>
<p>Aqui a diferença é gigantesca sendo de <strong>quase 4000% a favor do NHibernate. </strong>Isso acontece, pois o NHibernate implementa cache nível 1 nativamente então dentro de uma mesma ISession o objeto é carregado apenas uma vez enquanto com ADO.NET é necessário ir ao banco e carregar o objeto diversas vezes.</p>
<h1>Conclusões</h1>
<p>Olhando para os números apenas, em casos onde diversos registros precisam ser carregados, ADO.NET nativo oferece uma performance superior e parece ser a escolha óbvia. No entanto:</p>
<ul>
<li>Os testes com NHibernate foram executados utilizandos exemplos simples e sem qualquer tipo de otimização. </li>
<li>NHibernate oferece nativamente cache de resultados de queries e cache nível 2 que se utilizados iriam exibir um resultado bem próximo ao cenário “<em>NHibernate versus ADO.NET [1 registro]” </em>onde o NHibernate é 4 vezes mais rápido. </li>
<li>ADO.NET oferece um custo de desenvolvimento e manutenção altissimo e este custo torna-se ainda maior se utilizado com Stored Procedures que transformam o cenário em algo totalmente caótico de gerenciar devido a dificuldade de manter a rastreabilidade desses diabinhos malignos. </li>
</ul>
<p>No caso de sistemas <a title="OLTP @ Wikipedia" href="http://pt.wikipedia.org/wiki/OLTP">OLTP</a> onde as transações carregam unidades individuais e/ou pequenas coleções de entidades por sessão, NHibernate não só é mais rápido como também oferece muito mais flexibilidade pra lidar com praticamente todos os cenários existentes. <a title="25 reasons not to write your own ORM @ Ayende&#39;s Blog" href="http://ayende.com/Blog/archive/2006/05/12/25ReasonsNotToWriteYourOwnObjectRelationalMapper.aspx">Este post do Ayende</a> mostra 25 funcionalidades importantes (cache, gerenciamento de concorrência, etc) que você vai precisar quando estiver lidando com dados e que custariam muito caro (tempo e complexidade) caso você queira escreve-las “na mão”.</p>
<p>Em cenários de aplicações de internet onde o número de leituras é infinitamente superior ao número de escritas no banco de dados deve se utilizar cache no front end (IIS), portanto o tempo que se leva pra montar uma página é irrelevante. Mesmo que você carregasse os dados de um servidor remoto via conexão discada não faria diferença uma vez que os dados estivessem em cache.</p>
<p>Por último, se você se encontrar em uma situação utilizando NHibernate onde o acesso a dados é o gargalo da sua aplicação seu problema não é o NHibernate (a não ser que você tenha usado-o de maneira totalmente absurda, mas a probabilidade de você fazer o mesmo com ADO.NET é grande também). Nestes cenários o problema não é o acesso a dados em si, mas o resto da arquitetura que não escala de maneira adequada seja por meio de cache, processamento assincrono, filas, etc.</p>
<p>Sendo assim, acredito que podemos concluir que não faz sentido algum no meio do ano de 2010 utilizar queries AdHoc ou Stored Procedures em aplicações <a title="Line of Business @ Wikipedia" href="http://en.wikipedia.org/wiki/Line_of_business">LoB</a>. <img src='http://blog.tucaz.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>O código completo utilizado está no GitHub e pode ser <a title="NHPerf Source Code @ GitHub" href="http://github.com/tucaz/Samples/tree/master/NHPerf/">acessado online</a> ou baixado em <a title="Download of NHPerf Source Code @ GitHub" href="http://github.com/downloads/tucaz/Samples/NHPerf.zip">formato zip</a>.</p>
<p><strong>[1] – Hidratação é o processo de preenchimento (filling) das propriedades de uma entidade</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tucaz.net/2010/08/31/performance-nhibernate-versus-ado-net/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Verbos HTTP: GET e POST. Você sabe mesmo a diferença?</title>
		<link>http://blog.tucaz.net/2009/11/22/verbos-http-get-e-post-voce-sabe-mesmo-a-diferenca/</link>
		<comments>http://blog.tucaz.net/2009/11/22/verbos-http-get-e-post-voce-sabe-mesmo-a-diferenca/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 00:23:51 +0000</pubDate>
		<dc:creator>tucaz</dc:creator>
				<category><![CDATA[WCF]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[escalabilidade]]></category>
		<category><![CDATA[get]]></category>
		<category><![CDATA[post]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restful]]></category>
		<category><![CDATA[verbos http]]></category>
		<category><![CDATA[webrequest]]></category>

		<guid isPermaLink="false">http://blog.tucaz.net/?p=386</guid>
		<description><![CDATA[Sabe a diferença entre POST e GET em um ambiente REST? Não? Então leia este post e assista o vídeo linkado para entender!]]></description>
			<content:encoded><![CDATA[<p>Até pouco tempo atrás quando eu fazia entrevistas a fim de contratar desenvolvedores, não importando o nível, eu fazia a mesma pergunta: &#8220;Você sabe a diferença entre GET e POST em uma request HTTP?&#8221;. Por incrível que pareça poucas pessoas sabiam responder. Na maioria das vezes alguém que se considerava um desenvolvedor web não tinha a menor idéia  sobre o que eu estava falando. Acho que era culpa do RH que fazia uma pré-seleção muito ruim, mas anyway&#8230;</p>
<p>Hoje essa informação já chegou a maioria dos desenvolvedores web (já era hora, não?) então a pergunta no contexto original perdeu um pouco a validade. Todo mundo sabe que enviar formulários via GET manda as informações pela querystring e que POST manda encapsulado dentro da request e bla bla bla. No entanto, com a nova &#8220;moda&#8221;, que acho bem bacana aliás, de REST(ful) a pergunta ganhou um contexto novo e tornou a ser válida: você sabe qual a diferença dos verbos em uma request HTTP? Não só de GET e POST, mas de todo o resto?</p>
<p>Decidi fazer esse post rápido enquanto retomava meus estudos a respeito de WCF e assistia a um vídeo do MIX do ano passado que está no final deste post.</p>
<p>POST não escala, GET sim. Porquê? Por causa da semântica! POST, PUT, DELETE e outros verbos são por definição non-safe e com efeitos colaterais, ou seja, é esperado que uma request usando esses verbos modifique algum recurso. Dessa forma é impossível fazer cache desse tipo de chamada. E como todos nós sabemos, sem cache = sem escalabilidade, isn&#8217;t that right?</p>
<p>Vamos tomar como exemplo uma chamada a URI imaginária: <em>http://meusite.com.br/usuario/novo</em> passando via POST todas as informações necessárias para se criar um usuário. Se tudo correr bem, vamos receber como resposta um HTTP Status Code 201 indicando que o recurso foi criado e a URL para acessa-lo. Provavelmente algo como <em>http://meusite.com.br/usuário/765</em>.</p>
<p>Agora a pergunta: é seguro para os intermediários dessa request tais como proxies, clientes, etc efetuarem o cache disso? Não! Imagine um usuário do sistema que utiliza esse recurso tentando cadastrar um novo usuário com os mesmos dados. Ao invés de receber uma resposta de conflito ele receberia um status 201 dizendo que o recurso foi criado. De fato o recurso foi criado, mas será que deveriamos mostrar isso pra ele quando na verdade a criação desse recurso já havia acontecido e a ação que ele executou neste momento não trouxe sucesso? Acho que não.</p>
<p>Já o GET, por definição é cacheavel, pois não possui efeitos colaterais. Ele apenas devolve o recurso desejado sem modificar nada. Claro que isso só acontece quando bem usado, pois tem muita gente que utiliza esse verbo de maneira errada e baseado em parâmetros executa ações que deveriam ser associadas a outros verbos HTTP. Como não modifica nenhuma informação é possível efetuar o cache desse recurso com segurança.</p>
<p>Pra quem quiser ver mais a respeito de <a title="Caching REST with WCF in MIX 09" href="http://videos.visitmix.com/MIX09/T64M" target="_self">REST, GET, POST e cache, basta acessar o vídeo no site do MIX 09</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tucaz.net/2009/11/22/verbos-http-get-e-post-voce-sabe-mesmo-a-diferenca/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

