<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Surviving the Night</title><link>http://geeks.ms/blogs/palvarez/default.aspx</link><description>El blog de Pablo Doval sobre .NET, SQL, WinDbg... </description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Roar: Inserciones Masivas en MongoDB vs SQL Server (IV)</title><link>http://geeks.ms/blogs/palvarez/archive/2011/11/22/roar-inserciones-masivas-en-mongodb-vs-sql-server-iv.aspx</link><pubDate>Tue, 22 Nov 2011 15:24:24 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201823</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=201823</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2011/11/22/roar-inserciones-masivas-en-mongodb-vs-sql-server-iv.aspx#comments</comments><description>&lt;p&gt;Me alegra comprobar que, al parecer, el &lt;a href="http://geeks.ms/blogs/palvarez/archive/2011/11/17/hot-inserciones-masivas-en-mongodb-vs-sql-server.aspx"&gt;pequeño reto&lt;/a&gt; que nos traemos &lt;a href="http://geeks.ms/blogs/unai"&gt;Unai&lt;/a&gt; y yo está provocando cierto interés; más allá de haber conseguido que el de &lt;em&gt;Monforte&lt;/em&gt; y yo nos hayamos tenido que rascar el bolsillo e invitarnos el uno al otro a varias cenas, algo de debate si que se ha generado en twitter, llegando a contar incluso con alguna prueba similar en otra plataforma!&lt;em&gt;(*)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Para quien no haya leído la &lt;a href="http://geeks.ms/blogs/palvarez/archive/2011/11/17/hot-inserciones-masivas-en-mongodb-vs-sql-server.aspx"&gt;entrada anterior&lt;/a&gt;, o la &lt;a href="http://geeks.ms/blogs/unai/archive/2011/11/18/hot-inserciones-masivas-en-mongodb-vs-sql-server-ii.aspx"&gt;respuesta de Unai&lt;/a&gt;, os recuerdo brevemente las reglas de nuestra improvisada apuesta:&lt;/p&gt;  &lt;p&gt;El ganador será aquel de nosotros dos que sea capaz de insertar 500.000 filas (documentos, en su &lt;em&gt;dialecto&lt;/em&gt;) compuestas por un GUID y una cadena de 20 caracteres (no unicode). Recordaros que la solución &lt;strong&gt;bcp&lt;/strong&gt; ha sido declarada ilegal, para que Unai siga manteniendo alguna opción de victoria ;)&lt;/p&gt;  &lt;p&gt;Lo cierto es que no tenía pensado publicar nada mas avanzada la semana. Sin embargo, me ha surgido un imprevisto viaje a la pérfida Albión este fin de semana para participar en una &lt;em&gt;taskforce&lt;/em&gt; de rendimiento (yeah!), y he tenido bastantes ratos libres entre viajes y transbordos. No se me ocurrían muchas maneras mejores de ocupar este tiempo que compartiendo mi siguiente solución al reto, así que ahí vamos!&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;strong&gt;Descargo de Responsabilidad:&lt;/strong&gt; Al igual que hice en la entrada anterior, voy a tratar de volver a cubrirme las espaldas frente a conversaciones que deriven en fanatismos. Siempre que escribo acerca de una tecnología ajena al ecosistema de Microsoft acabo con problemas de fanatismos y guerras de religión. Por ello, dejadme que deje muy claro que este post solo pretende contar la historia de un pique interesante con un compañero, así como tratar de aprovechar la ocasión para comentaros un par de técnicas no triviales para realizar cargas rápidas de datos en SQL Server. Vaya por delante que MongoDB me resulta un producto más que interesante y con escenarios para los que es más idóneo que una base de datos relacional.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;NOTA: Si alguien esta leyendo mi blog de modo secuencial y nota la ausencia de una entrada llamada ‘Inserciones Masivas en MongoDB vs SQL Server (II)’, esto es porque esta entrada &lt;a href="http://geeks.ms/blogs/unai/archive/2011/11/18/hot-inserciones-masivas-en-mongodb-vs-sql-server-ii.aspx"&gt;la ha realizado Unai&lt;/a&gt; en su blog, y podéis acceder a ella aquí. De hecho, os recomiendo encarecidamente que la leáis incluso en el caso de que no estéis particularmente interesados en MongoDB o bases de datos NoSQL.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;(*): El amigo &lt;a href="http://geeks.ms/blogs/jtorrecilla/"&gt;Javier Torrecilla&lt;/a&gt; hizo la prueba en Oracle, aunque me niego a dar los resultados! ;) Por otra parte, aun esperamos la versión en WP7 de &lt;a href="http://geeks.ms/blogs/jyeray/default.aspx"&gt;Yeray&lt;/a&gt;!!! En el factor rendimiento no creo que nos gane ni a SQL Server ni a MongoDB, pero lo que es en cool factor nos va a dar una paliza.&lt;/em&gt;&lt;/p&gt;  &lt;h3&gt;¿Por dónde íbamos?&lt;/h3&gt;  &lt;p&gt;Si recordáis la entrada anterior, mis esfuerzos de inserción ya no eran capaces de aprovechar mejor los procesadores, a pesar de que no se encontraban aún al máximo; mi cuello de botella se había desplazado a otros lugares, y se materializaba en el lado de SQL Server &lt;a href="http://geeks.ms/blogs/palvarez/archive/2010/07/27/da-consultas-adhoc.aspx"&gt;mediante esperas&lt;/a&gt; por dos tipos de eventos concretos (&lt;em&gt;WRITELOG&lt;/em&gt; y &lt;em&gt;PAGELATCH_EX&lt;/em&gt;) como muestra la siguiente captura:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb58_5F00_7F42651E.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="image_thumb58" border="0" alt="image_thumb58" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb58_5F00_thumb_5F00_5D768C8D.png" width="454" height="64" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;El tener casi un 50% de las esperas globales en &lt;strong&gt;WRITELOG&lt;/strong&gt; evidencia el uso masivo del log de transacciones por las inserciones. Recordemos que, al contrario que con la escritura de los datos, esta operación es síncrona. A priori poco más podemos hacer de este lado, a no ser que recurriéramos a un escenario de BULK INSERT mínimamente logado, pero lamentablemente esta opción viola las reglas del concurso. &lt;em&gt;Doh… estúpidas reglas!&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;¡Vamos a ver si la otra espera nos da alguna pista! La espera es por el tipo &lt;strong&gt;PAGELATCH_EX&lt;/strong&gt;, que se trata de una vieja amiga mía. De todos modos, en caso de que os encontréis con alguna espera que no conozcáis, las tenéis casi todas listadas en la entrada relacionada a &lt;strong&gt;sys.dm_os_wait_stats&lt;/strong&gt; de los&lt;em&gt; Books Online&lt;/em&gt;… o en vuestro buscador favorito! ;) La respuesta de la documentación para esta espera es la siguiente:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;PAGELATCH_EX : Occurs when a task is waiting on a latch for a buffer that is not in an I/O request. The latch request is in Exclusive mode.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font style="background-color:#ffffff;"&gt;Lo que sucede es que al hacer tantas inserciones de modo concurrente, la ultima pagina del heap sufre de contención, lo que limita seriamente nuestra capacidad para hacer inserciones. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;¿Que podemos hacer para reducir la contención de esperas PAGELATCH_EX? Aquí viene el momento genial, pero absolutamente contraintuitivo, de esta entrada del blog: &lt;/p&gt;  &lt;p&gt;&lt;em&gt;&amp;lt;drum roll&amp;gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Vamos a particionar la tabla sobre la que vamos a hacer las inserciones.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&amp;lt;/drum roll&amp;gt;&lt;/em&gt;&lt;/p&gt;  &lt;h3&gt;¡¿Particionar la tabla para las inserts?! Se te pira…&lt;/h3&gt;  &lt;p&gt;Eso es lo que pensé la primera vez que escuché esta técnica; todos estamos más que habituados al particionado de tablas pensando en las mejoras administrativas que nos proporcionan y, como no, de rendimiento a la hora de realizar búsquedas debido a la eliminación de particiones, la menor altura de los índices, etc…. ¿Pero, mejoras en inserciones? &lt;/p&gt;  &lt;p&gt;Os podéis imaginar como me quede cuando leí por primera vez acerca de la idea de particionar una tabla para optimizar la carga de datos en un artículo de &lt;a href="http://blog.kejser.org/"&gt;Thomas Kejser&lt;/a&gt;; sin embargo, tiene sentido. Ahora os estoy escuchando a algunos pensar… &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;¿¡pero que hardware tiene tu portátil?! Si vas a hacer tantas particiones como procesadores (cuatro), ¿no deberías seguir las buenas recomendaciones y poner cada archivo en un disco independiente?&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;¡Buena pregunta! (y tanto… ¡como que me la he hecho yo a mi mismo! ;)) Pero daros cuenta de un detalle: la contención NO está en el disco, sino en las estructuras internas de SQL Server de la tabla. Lo que pretendo con esto no es optimizar el acceso a disco, sino la sobrecarga que tiene SQL Server cuando tiene varios hilos tratando de insertar en la misma tabla. Al particionarla, estas esperas se reducen, y ese es nuestro objetivo (PAGELATCH_EX).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_348B7784.png"&gt;&lt;img style="background-image:none;border-right-width:0px;margin:0px 0px 0px 10px;padding-left:0px;padding-right:0px;display:inline;float:right;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="image" border="0" alt="image" align="right" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_4CAEE1DF.png" width="104" height="107" /&gt;&lt;/a&gt;De cara a realizar este particionado, vamos a realizar un pequeño cambio a mi tabla que, evidentemente, consensué con Unai previamente. De hecho, a priori, este cambio me pone en una situación mas comprometida, ya que implica agregar un campo nuevo (de tipo TINYINT y al que llamaré Hash aunque realmente no es tal…), así como un índice clustered sobre el ID y este nuevo campo.&lt;/p&gt;  &lt;p&gt;La siguiente pregunta es: ¿cuantas particiones crear sobre la tabla? En este punto no he sido muy profesional, para ser sinceros: solo he hecho una prueba por el momento, con 8 particiones. Escogí este valor un poco por intuición; mi maquina tiene 4 núcleos reales, y consideré que 8 particiones deberían ser un numero apropiado para poder jugar un poco con la ociosidad de las tareas y minimizar el &lt;em&gt;signal_wait_time&lt;/em&gt;. De todos modos, si encuentro algo más de tiempo, trataré de hacer al menos un par de escenarios mas con diferente número de particiones. &lt;/p&gt;  &lt;p&gt;Como ya comentamos antes, todas estas particiones apuntaran al mismo &lt;em&gt;filegroup&lt;/em&gt; y fichero, por lo que en realidad no se trata de paralelizar las escrituras en ficheros o unidades diferentes; una vez mas recuerdo que solo pretendemos reducir la contención en las estructuras internas de SQL Server. &lt;/p&gt;  &lt;p&gt;Así pues, nuestro particionado quedaría tal y como muestra el siguiente diagrama:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_0076D831.png"&gt;&lt;img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_29323D7A.png" width="500" height="325" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;A continuación os muestro el script de creación de mi nueva tabla, así como la función y esquema de particionado que he empleado, y el nuevo índice clustered:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; PARTITION &lt;span class="kwrd"&gt;FUNCTION&lt;/span&gt; pf_hash (TINYINT) 
&lt;span class="kwrd"&gt;AS&lt;/span&gt; RANGE &lt;span class="kwrd"&gt;LEFT&lt;/span&gt; &lt;span class="kwrd"&gt;FOR&lt;/span&gt; &lt;span class="kwrd"&gt;VALUES&lt;/span&gt; 
(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07)

&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; PARTITION SCHEME ps_hash
&lt;span class="kwrd"&gt;AS&lt;/span&gt; PARTITION pf_hash &lt;span class="kwrd"&gt;TO&lt;/span&gt; ([&lt;span class="kwrd"&gt;ALL&lt;/span&gt;])
&lt;span class="kwrd"&gt;GO&lt;/span&gt;

&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; dbo.Test
(
    ID uniqueidentifier &lt;span class="kwrd"&gt;NOT&lt;/span&gt; NULLDEFAULT NEWID(),
    Payload &lt;span class="kwrd"&gt;varchar&lt;/span&gt;(20) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    Hash tinyint &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;
) &lt;span class="kwrd"&gt;ON&lt;/span&gt; ps_hash(Hash)

&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;UNIQUE&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; &lt;span class="kwrd"&gt;INDEX&lt;/span&gt; CIX_Hash 
&lt;span class="kwrd"&gt;ON&lt;/span&gt; dbo.Test (ID &lt;span class="kwrd"&gt;ASC&lt;/span&gt;, Hash &lt;span class="kwrd"&gt;ASC&lt;/span&gt;) &lt;span class="kwrd"&gt;ON&lt;/span&gt; ps_hash(Hash)&lt;/pre&gt;


&lt;p&gt;Además del particionado, voy a adelantarme a un potencial problema de contención de bloqueos en la tabla asegurándome que mi índice no permita bloqueos de pagina ni fila, y estableciendo la política de escalado de bloqueos de la tabla a Auto:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;INDEX&lt;/span&gt; CIX_Hash &lt;span class="kwrd"&gt;ON&lt;/span&gt; dbo.Test
&lt;span class="kwrd"&gt;SET&lt;/span&gt; (ALLOW_PAGE_LOCKS = &lt;span class="kwrd"&gt;OFF&lt;/span&gt;, ALLOW_ROW_LOCKS = &lt;span class="kwrd"&gt;OFF&lt;/span&gt;)

&lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; dbo.Test &lt;span class="kwrd"&gt;SET&lt;/span&gt; (LOCK_ESCALATION = AUTO)&lt;/pre&gt;

&lt;p&gt;El código de la prueba es similar a la versión anterior, pero agregando el código hash a cada una de los Tasks, de modo que cada Task enviará sus inserts a una partición diferente:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DoWork(&lt;span class="kwrd"&gt;int&lt;/span&gt; hash)
        {

            &lt;span class="kwrd"&gt;int&lt;/span&gt; countIterations = 0;
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (countIterations &amp;lt; 63)
            {
                &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection conn = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection(connStr))
                {
                    conn.Open();

                    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlCommand cmd = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlCommand())
                    {
                        cmd.Connection = conn;

                        &lt;span class="kwrd"&gt;int&lt;/span&gt; countValues = 0;
                        var builder = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();

                        builder.Append(&lt;span class="str"&gt;&amp;quot;INSERT INTO Test(Id,Payload, Hash) VALUES &amp;quot;&lt;/span&gt;);

                        &lt;span class="kwrd"&gt;while&lt;/span&gt; (countValues &amp;lt; 1000)
                        {
                            builder.Append(&lt;span class="str"&gt;&amp;quot;(NEWID(), REPLICATE(&amp;#39;X&amp;#39;,20), &amp;quot;&lt;/span&gt;);
                            builder.Append(hash.ToString());


                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (countValues != 999)
                                builder.Append(&lt;span class="str"&gt;&amp;quot;),&amp;quot;&lt;/span&gt;);
                            &lt;span class="kwrd"&gt;else&lt;/span&gt;
                                builder.Append(&lt;span class="str"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;);

                            countValues++;
                        }

                        cmd.CommandText = builder.ToString();
                        cmd.ExecuteNonQuery();
                        countIterations++;
                    }
                }
            }
        }&lt;/pre&gt;


&lt;h3&gt;Y todo esto.. ¿para que?&lt;/h3&gt;

&lt;p&gt;Solo hay una respuesta a esta pregunta: para derrotar, y humillar si cabe, a Unai y su MongoDB :P Vamos a ver si lo hemos conseguido!&lt;/p&gt;

&lt;p&gt;Bueno, en este caso no me entretendré demasiado con los resultados; simplemente os diré que después de los cambios consigo la inserción de los 500.000 registros en &lt;strong&gt;1,8 segundos estables&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Esta solución esta ligeramente por detrás de los &lt;em&gt;1,6 segundos del MongoDB de Unai&lt;/em&gt;, pero aun así me siento muy satisfecho porque es muy estable en tiempos y, bueno… si miro atrás al primer día del reto, no creía que pudiera bajar de los 20 segundos!&lt;/p&gt;

&lt;p&gt;Aun así, ya estoy trabajando en la siguiente idea… No se si será mas rápida, pero os garantizo que es bastante espectacular! ;)&lt;/p&gt;

&lt;h3&gt;Conclusiones:&lt;/h3&gt;

&lt;p&gt;A pesar de que aún falta lo más importante, el cara a cara final sobre el mismo metal, parece que ya podemos ir obteniendo algunas conclusiones buenas: &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Para empezar, y contra todo pronóstico (al menos por mi parte), parece que en esté escenario concreto SQL Server puede plantar cara a MongoDB. Aún tengo un as en la manga, pero incluso en el caso de que finalmente SQL Server salga derrotado en este pequeño juego, ya me resulta increíble estar en el mismo orden de magnitud de tiempos, así que no digamos estar en una situación tan reñida y con posiciones de victoria. &lt;/li&gt;

  &lt;li&gt;Aun no llegamos al limite de nuestras CPUs en este escenario; estoy convencido de que algo más podremos hacer… y aquí entra en juego mi as en la manga. &lt;/li&gt;

  &lt;li&gt;En este caso hemos tratado de mejorar las esperas que no se corresponden con las entradas en el log de transacciones; ¿podríamos mejorar este otro frente, que supone el otro 50% del tiempo en nuestro escenario original? Esta parte es mas difícil, por no decir imposible si no podemos realizar el proceso con operaciones mínimamente logadas (BULK), así que no creo que podamos ganar nada por ahí sin hacer trampas a Unai. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Igual que hice en la ocasión anterior, os voy a dejar una pista de lo que será mi siguiente intento para mejorar el rendimiento en las inserciones; solo os diré que voy a tratar de reducir las esperas por SOS_SCHEDULER_YIELD :)&lt;/p&gt;

&lt;p&gt;Cuando publiquemos los resultados definitivos, publicaremos también el código de ambas implementaciones; me encantaría que alguien mas se animara a realizar las pruebas y extraer conclusiones! &lt;/p&gt;

&lt;p&gt;Por último, quizá sea interesante reflexionar si realmente es necesario tanto esfuerzo para ganar, en este caso, simplemente dos segundos. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Keep Rockin’!&lt;/em&gt;&lt;/p&gt;

&lt;h5&gt;Rock Tip:&lt;/h5&gt;

&lt;p&gt;&lt;em&gt;“Ready to Roar, ready to rock, ready to give it all I’ve got”&lt;/em&gt; reza el estribillo de ‘&lt;a href="http://www.youtube.com/watch?v=qnMXoyUqzkw"&gt;Roar&lt;/a&gt;’, uno de os temas más espectaculares del increíble ‘&lt;a href="http://en.wikipedia.org/wiki/Coup_De_Grace_(Treat_album)"&gt;Coup de Grace&lt;/a&gt;’, el último disco de la ya venerable banda de Hard Rock melódico sueca &lt;a href="http://en.wikipedia.org/wiki/Treat_(band)"&gt;Treat&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Y eso es precisamente lo que me dije a mi mismo cuando Unai y su MongoDB empezaron a apretarme las tuercas! &lt;em&gt;Ready to give it all I’ve got!&lt;/em&gt; De hecho, este disco me estuvo acompañando durante gran parte de las pruebas que iba realizando; debería poner al final un grupo de los artistas, discos y temas involucrados en todo el reto ;)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201823" width="1" height="1"&gt;</description></item><item><title>Hot: Inserciones Masivas en MongoDB vs SQL Server</title><link>http://geeks.ms/blogs/palvarez/archive/2011/11/17/hot-inserciones-masivas-en-mongodb-vs-sql-server.aspx</link><pubDate>Thu, 17 Nov 2011 02:09:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201723</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=201723</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2011/11/17/hot-inserciones-masivas-en-mongodb-vs-sql-server.aspx#comments</comments><description>&lt;p&gt;Esta semana estoy en San Sebastián, impartiendo una pequeña formación sobre optimización de SQL Server. A priori, la semana se presentaba tranquila y con gran carga turística al tratarse de la primera ocasión que visito esta ciudad, y mi predilección general por estas tierras del norte. &lt;/p&gt;  &lt;p&gt;Lamentablemente, todos mis planes se torcieron tan pronto como descubrí que &lt;strong&gt;&lt;a href="http://geeks.ms/blogs/unai/"&gt;Unai&lt;/a&gt;&lt;/strong&gt; estaba en la misma ciudad que yo. Como no podía ser de otro modo, ente &lt;em&gt;pintxo&lt;/em&gt; y &lt;em&gt;pintxo&lt;/em&gt; nuestros temas técnicos favoritos empezaron a surgir en nuestras conversaciones. Y, como cualquiera que conozca a nuestro &lt;em&gt;Unai &lt;/em&gt;podrá intuir, no pasó demasiado tiempo antes de que MongoDB secuestrara todos nuestros hilos conversacionales y se convirtiera en nuestro particular &lt;em&gt;trending topic&lt;/em&gt;, por delante de otras apasionantes cuestiones como la entropía de la demografía en el postmoderno barroco, o el peculiar criterio que tengo a la hora de escoger &lt;a href="http://img.guitarchina.com/imgeshop/ibanez/rg3550dy01.jpg"&gt;mis guitarras&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;He de confesar que no recuerdo muy bien la cadena de acontecimientos que nos condujo a la historia que os voy a contar; quizá fuera mi falta de conocimiento respecto a este producto tan de moda (MongoDB), o el número de &lt;em&gt;zuritos&lt;/em&gt; que nos habíamos tomado… No lo acabo de tener muy claro, pero el hecho es que, de algún modo, me metí de lleno en un juego/apuesta que acabaría con el escaso tiempo libre que me quedaba a lo largo de la semana.&lt;/p&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;La Apuesta&lt;/h3&gt;  &lt;p&gt;Las reglas eran muy sencillas: el ganador sería aquel de nosotros dos que fuera capaz de insertar una carga de trabajo acordada previamente en menos tiempo. Él con su MongoDB de marras, y yo con mi viejo, fiable, pero no siempre bien ponderado SQL Server 2008 R2, ¡como no!&lt;/p&gt;  &lt;p&gt;Tras duras negociaciones de paz, &lt;em&gt;Unai&lt;/em&gt; y yo llegamos a un acuerdo para evitar emplear armas de destrucción masiva; por este motivo finalmente decidimos no evaluar la que es, de lejos, la manera más rápida de insertar datos en SQL Server: las &lt;em&gt;Bulk Inserts&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;La carga de trabajo que nos pusimos de objetivo fue 500.000 registros, cada uno conteniendo un GUID y 20 caracteres textuales (no unicode).&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;strong&gt;Descargo de Responsabilidad:&lt;/strong&gt; Siempre que escribo acerca de una tecnología ajena al ecosistema de Microsoft acabo con problemas de fanatismos y guerras de religión. Por ello, dejadme que deje muy claro que este post solo pretende contar la historia de un pique interesante con un compañero, así como tratar de aprovechar la ocasión para comentaros un par de técnicas no triviales para realizar cargas rápidas de datos en SQL Server. Vaya por delante que MongoDB me resulta un producto más que interesante y con escenarios para los que es más idóneo que una base de datos relacional.&lt;/em&gt;&lt;/p&gt;  &lt;h3&gt;Construcción del Entorno de Prueba&lt;/h3&gt;  &lt;p&gt;En entorno de prueba inicial consistió simplemente en una base de datos que contiene la tabla sobre la que vamos a insertar nuestros 500.000 registros. La única preparación inicial que he realizado de cara a mejorar un poco el rendimiento ha sido dimensionar de modo apropiado los ficheros (para evitar autocrecimientos por uso del log de transacciones en las inserciones) y establecer el modelo de recuperación a SIMPLE.&lt;/p&gt;  &lt;p&gt;A continuación os dejo el script inicial, aunque como veréis más adelante hemos realizado algún que otro cambio:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; DemoInserts &lt;span class="kwrd"&gt;ON&lt;/span&gt; &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; 
( 
    NAME = &lt;span class="str"&gt;&amp;#39;DemoInserts&amp;#39;&lt;/span&gt;, 
    FILENAME = &lt;span class="str"&gt;&amp;#39;c:\Databases\DemoInserts.MDF&amp;#39;&lt;/span&gt;, 
    &lt;span class="kwrd"&gt;SIZE&lt;/span&gt; = 200, 
    FILEGROWTH = 10% 
) 
LOG &lt;span class="kwrd"&gt;ON&lt;/span&gt; 
( 
    NAME = N&lt;span class="str"&gt;&amp;#39;DemoInserts_Log&amp;#39;&lt;/span&gt;, 
    FILENAME = N&lt;span class="str"&gt;&amp;#39;c:\Databases\DemoInserts_Log.LDF&amp;#39;&lt;/span&gt;, 
    &lt;span class="kwrd"&gt;SIZE&lt;/span&gt; = 200, 
    FILEGROWTH = 10% 
) 
&lt;span class="kwrd"&gt;GO&lt;/span&gt; 
&lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; DemoInserts &lt;span class="kwrd"&gt;SET&lt;/span&gt; RECOVERY SIMPLE 
&lt;span class="kwrd"&gt;GO&lt;/span&gt; 
&lt;span class="kwrd"&gt;USE&lt;/span&gt; DemoInserts 
&lt;span class="kwrd"&gt;GO&lt;/span&gt; 
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [Test] 
( 
    ID UNIQUEIDENTIFIER &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;DEFAULT&lt;/span&gt; NEWID(), 
    Payload &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(20) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;, 
)&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;¡Vamos a Insertar Filas!&lt;/h3&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;p&gt;La primera solución consistirá en un simple bucle de 500.000 ejecuciones, en el que para cada iteración insertamos una fila. Su única ‘optimización’ fue el empleo de la opción NCOUNT ON para evitar saturar el output buffer con los típicos mensajes de (1 row affected),&amp;#160; tal como se puede ver en el siguiente fragmento de código:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SET&lt;/span&gt; NOCOUNT &lt;span class="kwrd"&gt;ON&lt;/span&gt;

&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @cont &lt;span class="kwrd"&gt;INT&lt;/span&gt; 
&lt;span class="kwrd"&gt;SET&lt;/span&gt; @cont = 0

&lt;span class="kwrd"&gt;WHILE&lt;/span&gt; (@cont &amp;lt; 500000) 
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; 
   INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; Test(ID, Payload) &lt;span class="kwrd"&gt;VALUES&lt;/span&gt; (&lt;span class="kwrd"&gt;DEFAULT&lt;/span&gt;, REPLICATE(&lt;span class="str"&gt;&amp;#39;X&amp;#39;&lt;/span&gt;, 20)) 
   &lt;span class="kwrd"&gt;SET&lt;/span&gt; @cont = @cont + 1 
&lt;span class="kwrd"&gt;END&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;El tiempo de ejecución de la inserción en mi equipo fue de &lt;strong&gt;3 minutos y 8 segundos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; Todos los tiempos tomados en este artículo se han calculado realizando el promedio de tres ejecuciones sucesivas.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Evidentemente, desde antes de realizar esta prueba yo era consciente de que este mecanismo no iba a arrojar buenos resultados, pero me serviría para tener una línea base respecto a la que poder evaluar las mejoras posteriores y para hacerme una idea respecto a lo que podría esperar de SQL Server. &lt;/p&gt;

&lt;p&gt;Llegados a este punto le comenté a Unai que me daría con un canto en los dientes si era capaz de bajar mi tiempo de inserción por debajo de los 20 segundos. Mi amigo y competidor me corrigió, asegurándome que sería él mismo quien se encargaría de darme con el susodicho canto en toda mi dentadura si conseguía tal hazaña. Creo que en ese momento empecé a tomarme nuestra pequeña competición en serio ;)&lt;/p&gt;

&lt;h3&gt;Manos a la Obra… ¿Dónde esta mi cuello de botella?&lt;/h3&gt;

&lt;p&gt;Siempre hay un cuello de botella; ¡siempre! Aunque el rendimiento sea excelente, siempre hay un factor limitante, y solo uno. En este caso, un vistazo rápido al &lt;em&gt;Task Manager &lt;/em&gt;me permitió ver que la CPU no eran en este caso el problema:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_465CBF54.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_387A538C.png" width="444" height="323" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto me dio una buena idea para el siguiente intento: realizar una pequeña aplicación en C# que se encargara de lanzar INSERTS modo masivo en paralelo, usando múltiples hilos, para tratar de aprovechar al máximo las cuatro CPUs de las que dispone mi equipo de pruebas.&lt;/p&gt;

&lt;p&gt;A continuación os pongo el código exacto que he empleado para esta prueba, aunque casi me da vergüenza ;) No me juzguéis por él, es solo un ejemplo &lt;em&gt;‘quick and dirty’&lt;/em&gt;!:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading.Tasks;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data.SqlClient;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; ConsoleApplication5
{
    &lt;span class="kwrd"&gt;class&lt;/span&gt; Program
    {

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)
        {
            Stopwatch watch = Stopwatch.StartNew();

            var mainTask = &lt;span class="kwrd"&gt;new&lt;/span&gt; TaskFactory().StartNew(() =&amp;gt;
            {
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(125000), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(125000), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(125000), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(125000), TaskCreationOptions.AttachedToParent).Start();
            });

            mainTask.ContinueWith((t) =&amp;gt;
            {
                watch.Stop();
                Console.WriteLine(watch.Elapsed);
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            Console.ReadLine();
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DoWork(&lt;span class="kwrd"&gt;int&lt;/span&gt; rows)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; connStr = &lt;span class="str"&gt;&amp;quot;Data Source=.;Initial Catalog=DemoInserts&lt;br /&gt;&lt;/span&gt;&lt;span class="str"&gt;;Integrated Security=true;Application Name=TestInserts&amp;quot;&lt;/span&gt;;

            &lt;span class="kwrd"&gt;int&lt;/span&gt; countIterations = 0;
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (countIterations &amp;lt; rows)
            {
                &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection conn = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection(connStr))
                {
                    conn.Open();

                    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlCommand cmd = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlCommand())
                    {
                        cmd.Connection = conn;
                        cmd.CommandText = &lt;span class="str"&gt;&amp;quot;INSERT INTO Test(Id,Payload) VALUES (NEWID(), REPLICATE(&amp;#39;X&amp;#39;,20))&amp;quot;&lt;/span&gt;;
                        cmd.ExecuteNonQuery();
                        countIterations++;
                    }
                }
            }
        }
    }
}&lt;/pre&gt;


&lt;p&gt;Como podéis ver, el código simplemente instancia 4 tareas (una por cara núcleo disponible en mi máquina). Estas tareas reciben el número de filas a insertar, y proceden a realizar estas inserciones como comandos SQL dentro de un bucle. &lt;/p&gt;

&lt;p&gt;La inserción de las dichosas 500.000 filas por este mecanismo se produjo en &lt;strong&gt;1 minuto y 7 segundos&lt;/strong&gt;; si bien el valor no está nada mal en términos de mejora, sabía que aún me quedaba mucho para tener un tiempo competitivo. Una nueva visita al &lt;em&gt;Task Manager&lt;/em&gt; me hizo darme cuenta rápidamente de que, si bien había aumentado mucho mi consumo de CPU, aparentemente aún disponía de mucho margen adicional:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_4BF78D60.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_3E44D158.png" width="444" height="323" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A la vista de esto, decidí probar a aumentar el número de hilos empleados para lanzar las sentencias INSERT, y monitorizar tras cada prueba tanto la duración de la misma como la utilización de los procesadores durante el transcurso de las inserciones. De este modo pude lograr grandes usos del procesador, pero es importante tener presente una cuestión:&lt;em&gt; el incremento de la actividad de CPU no implica necesariamente un mejor rendimiento en las inserciones. &lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para demostrar este punto, os adjunto una pequeña gráfica que muestra los tiempos obtenidos en función del número de hilos empleados:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_3915A1BA.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_0977832E.png" width="404" height="245" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Atiende que graficazaaa… ¿verdad que una de estas ayuda a darle un look más profesional a cualquier artículo? ;))&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Como se puede apreciar, el &lt;em&gt;sweet spot&lt;/em&gt; de este proceso de inserción en mi equipo se encuentra en los 8 hilos, con un tiempo de ejecución de &lt;strong&gt;43 segundos&lt;/strong&gt;. A continuación os muestro la gráfica de uso de CPU de esta ejecución, para que podáis contrastarla con la primera de todas y apreciéis el notable incremento en la utilización que hemos logrado:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_2F58783A.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_18A60426.png" width="443" height="320" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;&amp;#160;&lt;/h3&gt;

&lt;h3&gt;¿Por donde seguimos ahora?&lt;/h3&gt;

&lt;p&gt;Bien, llegados a este punto ya tenía mas o menos claro el punto más idóneo de paralelismo desde el lado de la aplicación C# de inserciones, pero no conocía lo que estaba sucediendo por parte de SQL Server. Por esto, decidí estudiar las esperas del servidor; borre las estadísticas de esperas, lancé el proceso y a su finalización, use el celebérrimo script de &lt;a href="http://sqlserverperformance.wordpress.com/"&gt;Glenn Berry&lt;/a&gt;, personalizado por &lt;a href="http://www.sqlskills.com/BLOGS/PAUL/"&gt;Paul Randal&lt;/a&gt; para la &lt;a href="http://www.sqlskills.com/BLOGS/PAUL/post/Wait-statistics-or-please-tell-me-where-it-hurts.aspx"&gt;agregación de información de esperas por recursos en SQL Server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;El resultado de la prueba, si bien era de esperar, resulta revelador:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_2C233DFA.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_06B94A8C.png" width="454" height="56" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como se puede ver, un 99.22% del tiempo total de la prueba se destino a realizar entradas en el log de transacciones; esto se debe al hecho de que las inserciones, salvo casos muy puntuales en escenarios de BULK INSERT, son operaciones completamente logeadas. Dicho a lo bestia: por cada inserción, a parte del dato en si, hay que escribir la intención de realizar la inserción previamente en el log de transacciones. Esta operación es síncrona, y es la que esta provocando una gran cantidad de esperas.&lt;/p&gt;

&lt;p&gt;Para tratar de remediarlo, se me ocurrió tratar de reducir el número de cláusulas INSERT que enviamos al servidor mediante las sentencias de inserción múltiples de SQL Server 2008, que nos permiten insertar en el mismo statement hasta mil filas(*). Ya sabéis, algo así:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; Test(ID, Payload) &lt;span class="kwrd"&gt;VALUES&lt;/span&gt;
(NEWID(), &lt;span class="str"&gt;&amp;#39;AAA&amp;#39;&lt;/span&gt;),
(NEWID(), &lt;span class="str"&gt;&amp;#39;BBB&amp;#39;&lt;/span&gt;),
...
(NEWID(), &lt;span class="str"&gt;&amp;#39;XXX&amp;#39;&lt;/span&gt;)&lt;/pre&gt;


&lt;p&gt;Modifique un poco la aplicación para realizar estas sentencias, quedando el código del siguiente modo:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading.Tasks;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data.SqlClient;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; ConsoleApplication5
{
    &lt;span class="kwrd"&gt;class&lt;/span&gt; Program
    {

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)
        {
            Stopwatch watch = Stopwatch.StartNew();

            var mainTask = &lt;span class="kwrd"&gt;new&lt;/span&gt; TaskFactory().StartNew(() =&amp;gt;
            {
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
                &lt;span class="kwrd"&gt;new&lt;/span&gt; Task(() =&amp;gt; DoWork(), TaskCreationOptions.AttachedToParent).Start();
            });

            mainTask.ContinueWith((t) =&amp;gt;
            {
                watch.Stop();
                Console.WriteLine(watch.Elapsed);
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            Console.ReadLine();
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DoWork()
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; connStr = &lt;span class="str"&gt;&amp;quot;Data Source=.;Initial Catalog=DemoInserts;Integrated Security=true;&lt;br /&gt;&lt;/span&gt;&lt;span class="str"&gt;Application Name=DemoInserts&amp;quot;&lt;/span&gt;;

            &lt;span class="kwrd"&gt;int&lt;/span&gt; countIterations = 0;
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (countIterations &amp;lt; 63) &lt;span class="rem"&gt;// 63&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection conn = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection(connStr))
                {
                    conn.Open();

                    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlCommand cmd = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlCommand())
                    {
                        cmd.Connection = conn;

                        &lt;span class="kwrd"&gt;int&lt;/span&gt; countValues = 0;
                        var builder = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();

                        builder.Append(&lt;span class="str"&gt;&amp;quot;INSERT INTO Test(Id,Payload) VALUES &amp;quot;&lt;/span&gt;);

                        &lt;span class="kwrd"&gt;while&lt;/span&gt; (countValues &amp;lt; 1000)
                        {
                            builder.Append(&lt;span class="str"&gt;&amp;quot;(NEWID(), REPLICATE(&amp;#39;X&amp;#39;,20)) &amp;quot;&lt;/span&gt;);

                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (countValues != 999)
                                builder.Append(&lt;span class="str"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;);

                            countValues++;
                        }

                        cmd.CommandText = builder.ToString();
                        cmd.ExecuteNonQuery();
                        countIterations++;
                    }
                }
            }
        }
    }
}&lt;/pre&gt;

&lt;p&gt;Con esta nueva versión, usando ocho hilos, baje el tiempo a… (redoble de tambor, por favor)&lt;strong&gt; 4 segundos escasos!!!! &lt;/strong&gt;&lt;/p&gt;

&lt;p align="left"&gt;Llegados a este punto me sorprendí yo mismo; no creí que pudiera bajar tanto el tiempo de estas inserciones, y por primera vez vi peligrar mi dentadura ;) Como me encanta tener datos y números de cada mejora que voy logrando, volví a lanzar la prueba y consulté las estadísticas de esperas del servidor durante el tiempo de ejecución de la misma:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_16E51285.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_6E663070.png" width="454" height="64" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podéis ver, el hecho de agrupar las inserciones en batches ha hecho milagros! ahora mismo el servidor esta dedicando aproximadamente el mismo tiempo a escribir en el log de transacciones que en en resolver bloqueos de latches, una situación más normal, y que ha repercutido de manera espectacular en el rendimiento de estas inserciones.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(*): Por si alguien se lo pregunta, yo tampoco tengo ni puñetera idea de por qué el hard-limit de mil filas.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Y por hoy ha estado bien, ¿no? ;)&lt;/h3&gt;

&lt;p&gt;Con esta entrada he buscado abriros un poco el apetito y, con un poco de suerte, picar a alguien más para que entre al pequeño juego que tenemos Unai y yo. He explicado mis aproximaciones iniciales, pero me reservo para la siguiente entrada la solución ‘buena, buena’ desde el lado del SQL Server.&lt;/p&gt;

&lt;p&gt;Para los mas ansiosos os iré adelantando que se basa en particionar la tabla para evitar contención sobre la misma; los detalles de implementación los pondré en mi siguiente post, pero como mis actualizaciones son como los despertares del &lt;strong&gt;lazy_writer&lt;/strong&gt; (&lt;em&gt;ya sabéis, puede ser dentro de 3 milisegundos, o dentro de 3 años!&lt;/em&gt;), os he querido adelantar la técnica por si queréis investigarla por vosotros mismos.&lt;/p&gt;

&lt;p&gt;A modo de resumen, voy a finalizar con otra gráfica de estas elegantes y vistosas, que hoy tengo el día ejecutivo ;)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_650CC175.png"&gt;&lt;img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_6A7B3219.png" width="404" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;&lt;font style="font-weight:normal;"&gt;&lt;/font&gt;&lt;/h5&gt;

&lt;h5&gt;&lt;font style="font-weight:normal;"&gt;Por cierto, si os preguntáis que tal lo hizo MongoDb… vais a tener que esperar a que Unai lo publique en &lt;a href="http://geeks.ms/blogs/unai/"&gt;su blog&lt;/a&gt;. No obstante, os puedo adelantar que fue capaz de bajar de estos 4 segundos….&lt;/font&gt;&lt;/h5&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;..&lt;/p&gt;

&lt;p&gt;&lt;font style="font-weight:normal;"&gt;.&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&lt;font style="font-weight:normal;"&gt;&lt;em&gt;¡¡¡¡Pero yo también!!!! Muahahahaha!!! ;)&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Keep Rockin’!&lt;/em&gt;&lt;/p&gt;

&lt;h5&gt;Rock Tip:&lt;/h5&gt;

&lt;p&gt;Hacía mucho tiempo que no compartía con vosotros uno de mis rock tips… o mejor dicho, hacía mucho que no compartía nada con vosotros! Tengo el blog muy dejado, pero un servidor no da para más :(&lt;/p&gt;

&lt;p&gt;En esta ocasión me traigo a uno de mis descubrimientos del año, los geniales &lt;a href="http://en.wikipedia.org/wiki/Reckless_love"&gt;Reckless Love&lt;/a&gt;. Banda finlandesa liderada por el increíble &lt;em&gt;Olly Herman&lt;/em&gt;, quien fuera vocalista de &lt;a href="http://en.wikipedia.org/wiki/Crashd%C3%AFet"&gt;Crashdiet&lt;/a&gt; por una breve temporada y una de las personas con mas carisma y buen rollo que he visto nunca sobre un escenario. Herederos de las mejores raíces del hard rock melódico ochentero, pero con un increíble toque &lt;em&gt;dance&lt;/em&gt; y discotequero, puedo afirmar que verles en directo es la experiencia mas cercana a ver al &lt;a href="http://en.wikipedia.org/wiki/David_Lee_Roth"&gt;David Lee Roth&lt;/a&gt; sin recurrir a un De Lorean con condensador de fluzo.&lt;/p&gt;

&lt;p&gt;El tema que he escogido es el single de su segundo (y último hasta la fecha) disco: &lt;a href="http://www.youtube.com/watch?v=LV8wPokZNig"&gt;Hot&lt;/a&gt;. No tiene gran relación con la temática de la entrada, pero realmente me apetece compartir este tema con el mundo: si a uno solo de vosotros le hace sentir tan solo una decima parte de lo bien que me sienta a mi escuchar este temazo, ya habrá justificado saltarme mi costumbre de poner temas relacionados. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201723" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Rendimiento/default.aspx">Rendimiento</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/MongoDB/default.aspx">MongoDB</category></item><item><title>Forget Me Not: SQL Server Crash Dump Analysis at SQL Bits</title><link>http://geeks.ms/blogs/palvarez/archive/2010/10/31/forget-me-not-sql-server-crash-dump-analysis-at-sql-bits.aspx</link><pubDate>Sat, 30 Oct 2010 22:36:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:184140</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=184140</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/10/31/forget-me-not-sql-server-crash-dump-analysis-at-sql-bits.aspx#comments</comments><description>&lt;p&gt;Time flies! It’s been more than six months since I had the chance of speaking about SQL Server crash dump analysis at SQL Bits in London. &lt;/p&gt;  &lt;p&gt;As you will understand, for me it was a huge honor to share event with SQL Server heroes like Simon Sabin, Ramesh Meyyappan and, obviously, Connor Cunningham – who came from Redmond to London just to give his lecture on my same slot and leave me with just a handful of attendants which I’m sure were left at my session because they thought Connor was the guy with long hair :)&lt;/p&gt;  &lt;p&gt;Luckily, the organizers of the event recorded all the tracks and they are now available freely for everyone at &lt;a href="http://www.sqlbits.com/"&gt;their website&lt;/a&gt;, so in case you attended SQL Bits but wasn’t able to attend to my session, or if you were unable to get to SQL Bits at all, just &lt;a href="http://www.sqlbits.com/Agenda/event6/Photograph__SQL_Server_Crash_Dump_Analysis_/default.aspx"&gt;click here&lt;/a&gt; and you will be able to see and download my session. By the way, I strongly recommend you to check the rest of the sessions; some of them were really impressive.&lt;/p&gt;  &lt;p&gt;Lastly, I would like to send a big ‘thank you’ to all the organizers at SQL Bits. They did a tremendous job to achieve an excellent event, even though several factors were against them – such a little Icelandic volcano that I’m sure many of you will remember :) &lt;em&gt;Thank you guys, you rock!&lt;/em&gt;&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;This post’s &lt;em&gt;Rock Tip&lt;/em&gt; is &lt;a href="http://www.youtube.com/watch?v=Pf7aFTFiwuU"&gt;‘Forget Me Not’&lt;/a&gt;, one of the biggest hits from the L.A. band &lt;a href="http://en.wikipedia.org/wiki/Bad_English"&gt;Bad English&lt;/a&gt;, led by the great voice of &lt;a href="http://en.wikipedia.org/wiki/John_Waite"&gt;John Waite&lt;/a&gt; and the unmistakable guitar of Mr. &lt;a href="http://en.wikipedia.org/wiki/Neal_Schon"&gt;Neal Schon&lt;/a&gt;. A great song, released on 1989, which blends the melodic AOR and West Coast style with some bright moments from Neal’s Les Paul.&lt;/p&gt;  &lt;p&gt;Why did I choose this song for this post? To begin with, because even though it’s already been a while since this event took place, I won’t forget it for a long time! Not only because I had the chance of meeting great people, speak about something I’m passionate about in an excellent venue and attend some great sessions, but also because I was involved in one of my craziest journeys; trying to reach a customer while all European transport and accommodation system were about to collapse due to the eruption of some Icelandic volcano was definitely one of the highlights of my life! J&lt;/p&gt;  &lt;p&gt;On the other hand, the song seemed so appropriate because it was composed and performed by Bad English and… well, let’s say that my English skills used to be a lot better that what is shown on that video; sadly, it was a long time since I had last spoken publicly in English, and that shows on the recording. I just hope it is not so bad that you can’t follow it!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=184140" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category></item><item><title>Forget Me Not: Análisis de Volcados de Memoria en SQL Server</title><link>http://geeks.ms/blogs/palvarez/archive/2010/10/30/forget-me-not-an-225-lisis-de-volcados-de-memoria-en-sql-server.aspx</link><pubDate>Sat, 30 Oct 2010 21:51:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:184138</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=184138</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/10/30/forget-me-not-an-225-lisis-de-volcados-de-memoria-en-sql-server.aspx#comments</comments><description>&lt;p&gt;¡Cómo pasa el tiempo! Fue ya hace más de medio año, exactamente el pasado 16 de Abril, que tuve la oportunidad de hablar un poco sobre depuración de volcados de memoria de SQL Server para el diagnóstico avanzado de problemas en la sexta edición del SQL Bits de Londres. &lt;/p&gt;  &lt;p&gt;Como os podréis imaginar, para mi fue un inmenso honor compartir escenario con grandes de la talla de &lt;em&gt;Simon Sabin&lt;/em&gt;, &lt;em&gt;Ramesh Meyyappan&lt;/em&gt; y, sobre todo &lt;em&gt;Connor Cunnigham&lt;/em&gt;, Principal Software Architect del equipo del Query Optimizer, que se vino desde Redmond a Londres con el único propósito de dar una charla en el mismo slot que yo y dejarme sin asistentes! ;)&lt;/p&gt;  &lt;p&gt;Afortunadamente, la organización del evento grabó todas las sesiones y acaban de ponerlas a disposición de todo el mundo en su pagina web, por lo que si acudisteis al evento pero no pudisteis asistir a mi &lt;em&gt;track&lt;/em&gt;, o si Londres os quedaba un poco lejos, &lt;a href="http://www.sqlbits.com/Agenda/event6/Photograph__SQL_Server_Crash_Dump_Analysis_/default.aspx"&gt;aquí&lt;/a&gt; podéis ver y descargar mi sesión. Os recomiendo que echéis un vistazo a las mismas, porque muchas de ellas son realmente excelentes. &lt;/p&gt;  &lt;p&gt;Por último, me gustaría agradecer a toda la organización del SQL Bits su esfuerzo para lograr un evento tan excelente, a pesar de que muchos factores se alinearon para complicarlo todo…. como cierto volcán islandés que nos dejó a muchos buscándonos la vida para atender nuestros compromisos fuera de Londres, y a otros tratando de llegar a tiempo para dar sus sesiones. &lt;em&gt;Great job, guys…You rock! :)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;NOTA: Evidentemente, todas las sesiones están en inglés.&lt;/em&gt;&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;En este caso, el rock tip será &lt;a href="http://www.youtube.com/watch?v=Pf7aFTFiwuU"&gt;‘Forget Me Not’&lt;/a&gt;, uno de los grandes exitazos de los angelinos &lt;a href="http://es.wikipedia.org/wiki/Bad_English"&gt;Bad English&lt;/a&gt;, liderados por el británico &lt;a href="http://es.wikipedia.org/wiki/John_Waite"&gt;John Waite&lt;/a&gt; a la voz y la inconfundible guitarra del señor &lt;a href="http://es.wikipedia.org/wiki/Neal_Schon"&gt;Neal Schon&lt;/a&gt;. Un tema de 1989 que mezcla tan bien ese puntito de caña con el estilo melódico y West Coast que caracteriza a esta banda.&lt;/p&gt;  &lt;p&gt;¿Por qué he seleccionado el &lt;em&gt;Forget me Not&lt;/em&gt;? Pues para empezar, porque aunque ya hace bastante tiempo, no me había olvidado ni del evento, ni de la charla, ni de las peripecias que me sucedieron en ese viaje; creedme, esas no las olvidaré en la vida… Por otra parte, me pareció apropiado poner un tema de los Bad English, ya que en esa ocasión, como podréis comprobar los que veáis el video, no tenía yo mi mejor día en cuanto a soltura con la lengua de Shakespeare y Tim Minchin &lt;img style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" class="wlEmoticon wlEmoticon-smile" alt="Sonrisa" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/wlEmoticon_2D00_smile_5F00_34F79905.png" /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=184138" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/WinDbg/default.aspx">WinDbg</category></item><item><title>Heaven: Taller de BI con SQL Server 2008R2 en Pamplona</title><link>http://geeks.ms/blogs/palvarez/archive/2010/10/26/heaven-taller-de-bi-con-sql-server-2008r2-en-pamplona.aspx</link><pubDate>Tue, 26 Oct 2010 17:48:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:183796</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=183796</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/10/26/heaven-taller-de-bi-con-sql-server-2008r2-en-pamplona.aspx#comments</comments><description>&lt;p&gt;Los días 3 y 4 de Noviembre voy a tener la oportunidad de impartir un taller sobre &lt;strong&gt;Business Intelligence con SQL Server 2008R2&lt;/strong&gt; en el &lt;a href="http://www.cesnavarra.net/default.aspx"&gt;Centro de Excelencia de Software de Navarra&lt;/a&gt;, lo que supondrá una oportunidad magnífica para darle un repaso al estado del stack de Business Intelligence en la plataforma de Microsoft, comentar algunas cosas interesantes que se pueden hacer con los &lt;em&gt;juguetes&lt;/em&gt; nuevos que tenemos a mano (estoy pensando en PowerPivot y en integración con StreamInsight aqui ;)) y, como no, disfrutar un poco de las tierras navarras, su vinito y sus pintxos que tanto me gustan!!&lt;/p&gt;  &lt;p&gt;A continuación os dejo la agenda establecida para el curso, para ir poniéndoos los dientes largos :)&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Vistazo a la Plataforma de BI de Microsoft      &lt;ul&gt;       &lt;li&gt;SSIS, SSAS y SSRS &lt;/li&gt;        &lt;li&gt;Integración con Sharepoint &lt;/li&gt;        &lt;li&gt;Consideraciones de Despliegue e Infraestructura &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Introducción a SQL Server 2008 Integration Services      &lt;ul&gt;       &lt;li&gt;Desarrollo de Soluciones ETL con SSIS &lt;/li&gt;        &lt;li&gt;Depuración y Gestión de Errores &lt;/li&gt;        &lt;li&gt;Configuración y Despliegue de Paquetes &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Introducción a SQL Server 2008 Server Analysis Services      &lt;ul&gt;       &lt;li&gt;Desarrollo de Soluciones Multidimensionales con SSAS &lt;/li&gt;        &lt;li&gt;Trabajando con Cubos y Dimensiones &lt;/li&gt;        &lt;li&gt;Trabajando con Hechos y Grupos de Medidas &lt;/li&gt;        &lt;li&gt;Consultando soluciones Multidimensionales &lt;/li&gt;        &lt;li&gt;Personalizando la funcionalidad del cubo (Drilldown, Reports, etc...) &lt;/li&gt;        &lt;li&gt;Introducción a la Minería de Datos &lt;/li&gt;        &lt;li&gt;Mejoras en SQL Server 2008 / SQL Server 2008 R2 &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Introducción a SQL Server 2008 Server reporting Services      &lt;ul&gt;       &lt;li&gt;Creación de Informes Básicos &lt;/li&gt;        &lt;li&gt;Mejorando los Informes Básicos &lt;/li&gt;        &lt;li&gt;Manipulando DataSets &lt;/li&gt;        &lt;li&gt;Empleando Report Models &lt;/li&gt;        &lt;li&gt;Publicación y Ejecución de Informes &lt;/li&gt;        &lt;li&gt;Subscripciones para Distribución de Informes &lt;/li&gt;        &lt;li&gt;Administración del Report Server &lt;/li&gt;        &lt;li&gt;Informes con Código &lt;/li&gt;        &lt;li&gt;Mejoras en SQL Server 2008 / SQL Server 2008 R2 &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Otras Caracterésticas:      &lt;ul&gt;       &lt;li&gt;Clientes: Excel y PowerPivot &lt;/li&gt;        &lt;li&gt;Monitorización de Rendimiento y Estabilidad &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Si estáis interesados y tenéis esos días disponibles, no dejéis de visitar la página del &lt;a href="http://www.cesnavarra.net/default.aspx"&gt;Centro de Excelencia de Software de Navarra&lt;/a&gt; para consultar la información detallada del evento, así como la forma de registro.&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;Como la mayoría de vosotros sabéis, tengo la costumbre de acompañar cada entrada de este blog con un poquito de buen Rock n’ Roll; me encanta la idea de compartir con vosotros otra de mis pasiones, y quiero creer que en alguna ocasión haya podido descubriros algún grupo interesante. En alguna ocasión ya os comenté que a veces me resulta muy complicado escoger el tema, pues trato de que el título de la canción tenga alguna relación con la parte técnica del post… ¡creedme cuando os digo que esa tarea suele llevarme casi tanto tiempo como escribir la propia entrada!&lt;/p&gt;  &lt;p&gt;Lamentablemente en esta ocasión me toca hacer una excepción; la canción escogida ha sido una decisión puramente personal y nada tiene que ver con el contenido técnico del blog. Los que me conocéis puede que sepáis que uno de mis grupos favoritos es &lt;a href="http://en.wikipedia.org/wiki/Gotthard_(band)"&gt;Gotthard&lt;/a&gt;, una increíble banda de Hard Rock liderada por el simpatiquísimo Leo Leoni a la guitarra y la inconfundible voz y presencia de Steve Lee. &lt;/p&gt;  &lt;p&gt;Lamentablemente, el día 5 de Octubre de 2010, la que ya estaba siendo una semana muy dura de por si se terminó de torcer para mí al conocer la noticia del fallecimiento de &lt;a href="http://en.wikipedia.org/wiki/Steve_Lee_(Gotthard_singer)"&gt;Steve Lee&lt;/a&gt; en un desafortunadísimo accidente de tráfico; solo nos queda el consuelo de que murió cumpliendo un sueño que llevaba planeando muchos años, un viaje interestatal en su Harley Davidson con sus amigos.&lt;/p&gt;  &lt;p align="left"&gt;Se me ha hecho increíblemente difícil escoger una canción para esta entrada, pero al final me he decantado por una versión con voz en directo de su balada &lt;a href="http://www.youtube.com/watch?v=QX2bLv4vios"&gt;‘Heaven’&lt;/a&gt;, donde seguro que se encuentra ahora cantando con algún &lt;a href="http://www.youtube.com/watch?v=UaoP9J7kBWU"&gt;‘Angel’&lt;/a&gt; este auténtico gentleman… Y aunque no acompañe al post, termino dejándoos el último videoclip que grabaron, para el tema &lt;a href="http://www.youtube.com/watch?v=TKnY6xeAs8E"&gt;‘Need to Believe’&lt;/a&gt;; video que creo que tardaré años en poder ver sin que se me haga un nudo en la garganta…&lt;/p&gt;  &lt;p align="left"&gt;Algún día le dejaré mi pequeño recuerdo en el paso del Gotardo, pero por ahora sirva este minúsculo homenaje para recordarle: &lt;em&gt;Danke für alles, Steve…&amp;#160; du gaben uns tolle Songs… du machte uns lächeln und glücklich seing. Mein Beileid geht an die Familie, Freunde und die Band.&lt;/em&gt;&lt;/p&gt;  &lt;p align="left"&gt;Keep rockin’…&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=183796" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category></item><item><title>Tell Me Where To Go: Estudio de Consultas AdHoc en SQL Server</title><link>http://geeks.ms/blogs/palvarez/archive/2010/07/27/da-consultas-adhoc.aspx</link><pubDate>Tue, 27 Jul 2010 15:39:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:179905</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=179905</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/07/27/da-consultas-adhoc.aspx#comments</comments><description>&lt;p&gt;Uno de mis temas favoritos a la hora de dar charlas de rendimiento de SQL Server es el estudio de la cache de planes de ejecución y la presencia de consultas AdHoc. Puedo pasarme horas hablando sobre ello, y contando batallitas… muy a pesar de los pobres asistentes que deben acabar hasta las narices de las consultas AdHoc, de mí, y de mi santa madre :)&lt;/p&gt;  &lt;p&gt;Pero no nos engañemos, si me apasiona tanto este tema es porque se trata de un aspecto muy importante de la salud del servidor y de las aplicaciones que le atacan. Y, además, resulta muy fácil comprobar si estamos sufriendo algún problema relacionado con la presencia masiva de consultas AdHoc en el sistema. &lt;/p&gt;  &lt;p&gt;Lo curioso es que, a pesar de lo mucho que me gusta y lo importante que es el tema, no le he hecho justicia con artículos en este blog. Y con esto no quiero decir que no haya escrito acerca de ello; &lt;a href="http://geeks.ms/blogs/palvarez/archive/2008/05/18/these-days-un-d-237-a-en-la-vida-de-una-consulta.aspx"&gt;aquí&lt;/a&gt; podéis encontrar una breve descripción del ciclo de vida de las consultas en SQL Server, y &lt;a href="http://geeks.ms/blogs/palvarez/archive/2008/06/13/out-of-time-a-vueltas-con-los-planes-compilados-en-sql-server-2008.aspx"&gt;aquí&lt;/a&gt; podéis leer sobre la opción de optimización para cargas de trabajo AdHoc en SQL Server 2008. &lt;/p&gt;  &lt;p&gt;Sin embargo, creo que nunca he explicado como procedo a estudiar el estado de salud de la cache de planes de ejecución y procedimientos almacenados, así que espero redimirme un poquito con esta entrada.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;NOTA: En esta entrada no voy a explicar el qué son las consultas AdHoc, ni el por qué pueden resultar perniciosas desde el punto de vista del rendimiento. Para esta explicación os recomiendo revisar los dos enlaces que os he puesto un poco más arriba.&lt;/em&gt; En esta ocasión solo me centraré en el proceso de estudio de estas consultas.&lt;/p&gt;  &lt;h4&gt;Vistazo General&lt;/h4&gt;  &lt;p&gt;Una de las maneras más rápidas y cómodas de comprobar si tenemos una elevada presencia de consultas AdHoc en el sistema es mediante los informes del SQL Server Management Studio (SSMS).&lt;/p&gt;  &lt;p&gt;Aunque parezca mentira, voy a dedicar un par de párrafos y capturas de pantalla a detallar como localizar estos informes. Con el paso de los años y las charlas es ido aprendiendo que, curiosamente, estos informes son tan potentes como desconocidos. Lo más habitual es que más de la mitad de los asistentes a mis sesiones desconozcan la existencia de los mismos, por lo que aprovecho para presentarlos a quienes aún no los conozcáis.&lt;/p&gt;  &lt;p&gt;Dentro de la interfaz del SSMS, y más concretamente, en el menú pop-up (el del botón derecho del ratón) de todos los nodos del Object Explorer, tenemos una opción llamada Reports.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_7A4F165B.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;margin-left:0px;border-left-width:0px;margin-right:0px;" title="image" border="0" alt="image" align="right" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_3D6A6EBC.png" width="137" height="244" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Esta opción es contextual: vamos a tener informes a nivel de instancia, a nivel de base de datos, de usuarios, etc. Evidentemente, hay ciertos tipos de nodos que no tienen ningún informe predefinido, pero siempre podríamos crearnos informes personalizados incluso para los nodos vacíos; son simples ficheros RDLC.&lt;/p&gt;  &lt;p&gt;Si bien en esta caso solo vamos a trabajar con un informe concreto, os recomiendo encarecidamente que os deis una vuelta por los informes que vienen predefinidos (&lt;em&gt;Standard Reports&lt;/em&gt;), y especialmente por los definidos sobre el nodo de instancia y los definidos sobre los nodos de bases de datos específicas.&lt;/p&gt;  &lt;p&gt;En esta caso concreto, nos interesa un informe llamado &lt;strong&gt;Server Dashboard&lt;/strong&gt;, que se encuentra a nivel de instancia. Por tanto, para llegar a él, pinchamos con el botón derecho sobre el nodo de la instancia. Ahí vámos a &lt;em&gt;Reports –&amp;gt; Standard Reports –&amp;gt; Server Dashboard&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;&lt;i&gt;NOTA: Esto habituado a trabajar con la versión del producto en inglés, por lo que me vais a perdonar que los pantallazos estén en este idioma, y que no realice las traducciones pertinentes.&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_037B2BD0.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_6C6CAA93.png" width="534" height="366" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Como su propio nombre indica, este informe nos muestra un vistazo general del servidor, con la configuración del mismo, versiones del producto, detalles de actividad, etc. Y, cómo no, también nos deja ver un par de gráficas de tarta que alegran el informe con su vivos colores :P&lt;/p&gt;  &lt;p&gt;Estas gráficas muestran el porcentaje de utilización de CPU y de E/S por parte de cada una de las bases de datos del sistema, algo bastante útil para detectar si alguna de las bases de datos está monopolizando los recursos del sistema.&lt;/p&gt;  &lt;p&gt;A continuación os muestro, a modo de ejemplo, un pantallazo del informe en mi máquina local:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_4AA0D202.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_1D3F3C32.png" width="534" height="463" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Si os fijáis, las tareas que más CPU están empleando en mi entorno no son relacionadas con ninguna de las bases de datos presentes (&lt;em&gt;msdb&lt;/em&gt;, &lt;em&gt;PerfDW&lt;/em&gt;, &lt;em&gt;ReportServer&lt;/em&gt; y &lt;em&gt;db_ProcedimientosAdministrativos&lt;/em&gt;), sino con tareas AdHoc.&lt;/p&gt;  &lt;p&gt;Como podéis ver, un rápido vistazo a este informe nos muestra que podríamos estar experimentando un problema de consultas AdHoc en el sistema, ya que el consumo de CPU de las consultas AdHoc muy es elevado. ¿Quiere esto decir que si en la gráfica no aparece un gran consumo de CPU o E/S por consultas AdHoc, estamos libres del problema?&lt;/p&gt;  &lt;h4&gt;… pues va a ser que no :)&lt;/h4&gt;  &lt;p&gt;Cierto es… aunque tengamos muy poca presencia de consultas &lt;em&gt;AdHoc &lt;/em&gt;en el diagrama, es posible que las consultas de este tipo sean un problema en nuestro sistema. Desde aquí, haciendo un pequeño esfuerzo, puedo escuchar vuestras voces de incredulidad en la distancia:&lt;/p&gt;  &lt;p&gt;- ¡¿Cómo es posible?! &lt;em&gt;(…se oyen las voces desde más alla del Manzanares…)      &lt;br /&gt;&lt;/em&gt;- Das ist Unglaublich!! &lt;em&gt;(…algun avezado lector desde la puerta de Brandemburgo…)&lt;/em&gt;     &lt;br /&gt;- Cómo ye, ¡ho! &lt;em&gt;(…estremecedores palabras que oigo entre Mieres y La Moreda…)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;¡Muy fácil! Puede ser que el sistema tenga miles de consultas AdHoc, muy livianas, cuya ejecución no es costosa ni en CPU ni en E/S, pero sin embargo genera presión por recompilación, etc.&lt;/p&gt;  &lt;h4&gt;Entrando en Detalle&lt;/h4&gt;  &lt;p&gt;Vale, ya sabemos que puede ser necesario investigar un poco más ¿Cómo podemos hacerlo? Yo recomiendo empezar por comparar el ratio entre consultas AdHoc y consultas No AdHoc. A continuación os pongo un ejemplo capturado de un cliente en el que he estado recientemente: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;SELECT      &lt;br /&gt;&amp;#160;&amp;#160; COUNT(*)       &lt;br /&gt;FROM sys.dm_exec_cached_plans       &lt;br /&gt;WHERE objtype LIKE &amp;#39;Adhoc&amp;#39; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;En el caso concreto de este servidor, esta consulta ha devuelto &lt;strong&gt;15636&lt;/strong&gt; &lt;strong&gt;planes adhoc&lt;/strong&gt;. ¡No es precisamente un número pequeño de planes de ejecución en la cache! Vamos a ver ahora cuantos planes de ejecución no adhoc hay en la cache: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;SELECT      &lt;br /&gt;&amp;#160;&amp;#160; COUNT(*)       &lt;br /&gt;FROM sys.dm_exec_cached_plans       &lt;br /&gt;WHERE objtype NOT LIKE &amp;#39;Adhoc&amp;#39;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;La consulta anterior nos indica que hay &lt;strong&gt;706 planes de ejecución de consultas no AdHoc&lt;/strong&gt;. Evidentemente, el ratio entre unas y otras es extremadamente preocupante, y signo evidente de que el sistema está generando constantemente consultas AdHoc. &lt;/p&gt;  &lt;p&gt;&lt;em&gt;NOTA: Es difícil dar reglas a seguir en estos casos, pero generalmente puedo decir que si detecto que más del 30% de las consultas de la cache son de tipo AdHoc, considero que hay un problema que investigar respecto a la generación y parametrización de las consultas.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;El siguiente paso sería detectar la memoria empleada en planes reutilizados, y en planes no reutilizados, y catalogarlos apropiadamente. En este caso yo utilizo un script, basado en el excelente trabajo de &lt;a href="http://sqlblog.com/blogs/davide_mauri/archive/2010/07/23/viewing-how-much-memory-is-used-by-not-reused-query-plan.aspx"&gt;Davide Mauri&lt;/a&gt;, que me viene de perlas en estos casos:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;WITH Planes AS      &lt;br /&gt;(       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SELECT       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Reutilizado = CASE       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; WHEN usecounts &amp;gt; 1 THEN &amp;#39;Plan Reutilizado (Mb)&amp;#39;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ELSE &amp;#39;Plan No Reutilizado (Mb)&amp;#39;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; END,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; size_in_bytes AS [Tamaño (Mb)],       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; cacheobjtype AS TipoObjetoCache,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objtype AS Tipo       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; FROM       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; sys.dm_exec_cached_plans       &lt;br /&gt;),       &lt;br /&gt;Agregado AS       &lt;br /&gt;(       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SELECT       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Reutilizado,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Tipo,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TipoObjetoCache,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [Tamaño (Mb)] = SUM([Tamaño (Mb)] / 1024. / 1024.)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; FROM       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Planes       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; GROUP BY       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Reutilizado,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TipoObjetoCache,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Tipo       &lt;br /&gt;),       &lt;br /&gt;Pivote AS       &lt;br /&gt;(       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; SELECT *       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; FROM       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Agregado a       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; PIVOT       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ( SUM([Tamaño (Mb)]) FOR Reutilizado IN ([Plan Reutilizado (Mb)], [Plan No Reutilizado (Mb)]) ) p       &lt;br /&gt;)       &lt;br /&gt;SELECT       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Tipo,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TipoObjetoCache,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; [Tamaño Reutilizado (Mb)] = SUM([Plan Reutilizado (Mb)]),       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; [Tamaño No Reutilizado (Mb)] = SUM([Plan No Reutilizado (Mb)])       &lt;br /&gt;FROM       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Pivote       &lt;br /&gt;GROUP BY       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Tipo,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TipoObjetoCache       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; WITH ROLLUP       &lt;br /&gt;HAVING       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; (Tipo IS NULL AND TipoObjetoCache IS NULL ) OR       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; (Tipo IS NOT NULL AND TipoObjetoCache IS NOT NULL )&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Volviendo al caso de mi cliente, la ejecución de esta consulta devolvió los siguientes resultados:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_32497988.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_09CA9774.png" width="534" height="229" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Como podéis comprobar, en este caso el tamaño no reutilizado es casi similar al listado para los planes reutilizados, lo cual es otro indicativo claro de que hay un gran problema de no reutilización de planes de ejecución debido a consultas AdHoc mal parametrizadas. &lt;/p&gt;  &lt;p&gt;Después de comprobar que realmente estamos sufriendo el problema ¿cual sería mi siguiente paso? Pues el más divertido de todos… &lt;em&gt;¡buscar al culpable!&lt;/em&gt; ;)&lt;/p&gt;  &lt;p&gt;Para ello, buscaría las consultas que aparecen en la cache, de tipo AdHoc, y cruzaría la vista con la funcion &lt;em&gt;sys.dm_exec_sql_text&lt;/em&gt; para poder sacar el texto de la SQL a partir del handle:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;SELECT      &lt;br /&gt;&amp;#160;&amp;#160; refcounts,       &lt;br /&gt;&amp;#160;&amp;#160; size_in_bytes,       &lt;br /&gt;&amp;#160;&amp;#160; cacheobjtype,       &lt;br /&gt;&amp;#160;&amp;#160; text       &lt;br /&gt;FROM       &lt;br /&gt;&amp;#160;&amp;#160; sys.dm_exec_cached_plans       &lt;br /&gt;&amp;#160;&amp;#160; CROSS APPLY sys.dm_exec_sql_text(plan_handle)       &lt;br /&gt;WHERE objtype LIKE &amp;#39;Adhoc&amp;#39;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Os muestro una salida parcial para que veais el problema (sin mostrar toda la consulta y revelar parte del modelo de datos de mi cliente, evidentmente):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_74CBB961.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_6DCC06DC.png" width="534" height="212" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Como se puede ver, las consultas son iguales, variando exclusivamente en los parámetros; el hecho de que sigan recompilandose y no se reutilicen es significativo, y un potencial problema de rendimiento (como ya se comentó en los otros posts). &lt;/p&gt;  &lt;p&gt;¡Ya tenemos nuestros culpables! ¡¡Yeah!!&lt;/p&gt;  &lt;h4&gt;Resumiendo&lt;/h4&gt;  &lt;p&gt;A modo de resumen, yo abordaría el estudio del siguiente modo:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Revisión del informe&lt;em&gt; &lt;strong&gt;Server Dashboard&lt;/strong&gt;&lt;/em&gt; para buscar presencia de consultas &lt;em&gt;AdHoc&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;Consulta sobre &lt;em&gt;&lt;strong&gt;sys.dm_exec_cached_plans&lt;/strong&gt;&lt;/em&gt; para ver el ratio &lt;em&gt;AdHoc/No AdHoc&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;Consulta para ver la memoria fugada en planes no reutilizados &lt;/li&gt;    &lt;li&gt;Si procede, revisar las consultas problematicas. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Fácil, sencillo y para toda la familia :) &lt;/p&gt;  &lt;p&gt;Después de ver esta información, tendremos una buena idea de si estamos siendo víctimas de algún tipo de problema derivado de la presencia masiva de consultas &lt;em&gt;AdHoc&lt;/em&gt; en nuestro sistema. Si fuera así, habrá que comprobar la presencia de consultas dinámicas sin preparar, consultas sin parametrizar desde el cliente, etc.&lt;/p&gt;  &lt;p&gt;Espero que os haya resultado interesante la entrada, y os animo a que probéis en vuestros servidores SQL Server: ¡seguro que más de uno de vosotros se lleva una sorpresa!&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Rock Tip:&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Los últimos rock tips, si bien han sido temazos, se han alejado un poco de mi corazoncito hardrockero ochentero, así que es buen momento de retomarlo. Y para ocasiones especiales, nada mejor que los grandísimos &lt;i&gt;glam-metaleros&lt;/i&gt; noruegos &lt;a href="http://en.wikipedia.org/wiki/Wig_Wam"&gt;Wig Wam&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Representantes de su país en el festival de Eurovisión de 2005, con el temazo ‘&lt;a href="http://www.youtube.com/watch?v=0XIyCKgA8z8"&gt;In My Dreams&lt;/a&gt;’, en esta ocasión nos quedamos con su balada ‘&lt;a href="http://www.youtube.com/watch?v=f-csCNH5Ds8"&gt;Tell Me Where To Go&lt;/a&gt;’ para acompañar este post. &lt;/p&gt;  &lt;p&gt;A todo esto, apuntaros esta fecha en vuestros calendarios: 18 de Septiembre de 2010. Ese será el día que los chicos de WigWam nos visitarán en Madrid por primera vez, en la sala Ritmo y Compás ¡No creí que mis ojos fueran a ver esto! Ya solo queda ver por estas tierras a &lt;a href="http://en.wikipedia.org/wiki/Steel_Panther"&gt;Steel Panther&lt;/a&gt; y seré un hombre plenamente feliz :)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=179905" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Rendimiento/default.aspx">Rendimiento</category></item><item><title>I Know You’re Here: Materiales de Optimizacion de SQL Server en el CIIN</title><link>http://geeks.ms/blogs/palvarez/archive/2010/07/26/i-know-you-re-here-materiales-de-optimizacion-de-sql-server-en-el-ciin.aspx</link><pubDate>Mon, 26 Jul 2010 20:35:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:179875</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=179875</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/07/26/i-know-you-re-here-materiales-de-optimizacion-de-sql-server-en-el-ciin.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://geeks.ms/media/p/179873.aspx"&gt;Aquí&lt;/a&gt; os dejo los materiales de la sesión de optimización de SQL Server que tuve la suerte de dar el pasado viernes en tierras cántabras, gracias a la invitación de los chicos del CIIN. &lt;/p&gt;  &lt;p&gt;Quiero aprovechar para dar las gracias también a todos los asistentes por las interesantes preguntas y la atención a lo largo de una sesión de más de 5 horas… sé que es duro, y más aún en viernes y, sobre todo, siendo el primer día de las fiestas de Santander! :) &lt;/p&gt;  &lt;p&gt;Para los que no hayáis podido ver la sesión el viernes ni presencialmente ni a través de LiveMeeting, pero tengáis interés en la optimización de SQL Server, os dejo &lt;a href="https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?culture=es-ES&amp;amp;EventID=1032456404&amp;amp;CountryCode=ES"&gt;aquí&lt;/a&gt; el enlace al evento grabado para que lo podáis descargar y ver tranquilamente a vuestro ritmo.&lt;/p&gt;  &lt;p&gt;Si se me quedó alguna pregunta por responder, o tenéis más dudas, no dejéis de consultármelas a través del blog o de mi dirección de email!&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;“&lt;a href="http://www.youtube.com/watch?v=jY8wyKuLY2k"&gt;I Know You’re Here&lt;/a&gt;”, del grandísimo Steve Vai, es el tema que he escogido en esta ocasión como Rock Tip. Más que nada porque siempre es un placer ver que la gente sacrifica su tiempo personal por acudir a los eventos de la comunidad, por intentar aprender y compartir. Porque sé que siempre estáis ahi, por eso me pareción un Rock Tip apropiado ;)&lt;/p&gt;  &lt;p&gt;¡¿Que decir de &lt;a href="http://en.wikipedia.org/wiki/Steve_vai"&gt;Steve Vai&lt;/a&gt;?! Creo que a todos los que nos gusta la música y nos apasiona la guitarra nos proporciona el mismo feeling: envidia cochina! XD Sus creaciones te pueden gustar más o menos, pero su estilo, su técnica y su virtuosísmo no te van a dejar indiferente. Como lo describiera &lt;a href="http://en.wikipedia.org/wiki/Brian_May"&gt;Brian May&lt;/a&gt; en el concierto de leyendas de la guitarra, en Sevilla en 1991: “.. el genio, el maestro de la guitarra de la era espacial.. mr. Steve Vai”. Ahí es nada.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=179875" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Comunidad/default.aspx">Comunidad</category></item><item><title>Pinball Map: Cuidado con los Mapeos en NHibernate</title><link>http://geeks.ms/blogs/palvarez/archive/2010/06/08/pinball-map-cuidado-con-los-mapeos-en-nhibernate.aspx</link><pubDate>Tue, 08 Jun 2010 11:25:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:177786</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>31</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=177786</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/06/08/pinball-map-cuidado-con-los-mapeos-en-nhibernate.aspx#comments</comments><description>&lt;p&gt;Ermm… si, chicos y chicas, sonará raro, pero hoy voy a hablar de NHibernate. Sé que me arriesgo a la condenación eterna en las llamas del infierno, pero yo soy así de altruista y me la juego por vosotros! ;)&lt;/p&gt;  &lt;p&gt;Uno de los clientes con los que he estado esta semana(*) estaba experimentando problemas de rendimiento en el acceso a datos en su aplicación, sospechando que el causante pudiera ser una vista poco optimizada. Afortunadamente, el cliente tenía muy bien localizada la operativa más costosa, hasta el punto que podíamos llegar con gran facilidad a la consulta problemática, que era la siguiente:&lt;/p&gt;  &lt;p&gt;&lt;font size="1" face="Consolas"&gt;EXEC sp_executesql N&amp;#39;     &lt;br /&gt;SELECT       &lt;br /&gt;&amp;#160;&amp;#160; this_.ID as ID90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.BorradoLogico as BorradoL2_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.Descripcion as Descripc3_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.Estado as Estado90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.VisibleWeb as VisibleWeb90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.CodigoDB2 as CodigoDB6_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.FechaPrevistaInicioComercializacion as FechaPre7_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.FechaFinComercializacion as FechaFin8_90_0_,&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160; this_.Comentarios as Comentar9_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.URLFoto as URLFoto90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.Orden as Orden90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.URLFotoMiniatura as URLFoto12_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.SufijoID as SufijoID90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.MarcaID as MarcaID90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.VersionId as VersionId90_0_       &lt;br /&gt;FROM&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160; VistaProblematica this_       &lt;br /&gt;WHERE       &lt;br /&gt;&amp;#160;&amp;#160; this_.CodigoDB2 in (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) and       &lt;br /&gt;&amp;#160;&amp;#160; this_.SufijoID in (@p10, @p11, @p12, @p13, @p14) and this_.BorradoLogico = @p15&amp;#39;,      &lt;br /&gt;N&amp;#39;@p0 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p1 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p2 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p3 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p4 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p5 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p6 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p7 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p8 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p9 &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;,@p10 bigint,@p11 bigint,@p12 bigint,@p13 bigint,@p14 bigint,@p15 bit&amp;#39;,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p0 = N&amp;#39;040&amp;#160; &amp;#39;, @p1 = N&amp;#39;1F7&amp;#160; &amp;#39;, @p2 = N&amp;#39;1G3&amp;#160; &amp;#39;, @p3 = N&amp;#39;209&amp;#160; &amp;#39;,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p4 = N&amp;#39;3R3&amp;#160; &amp;#39;, @p5 = N&amp;#39;8S1&amp;#160; &amp;#39;, @p6 = N&amp;#39;8S6&amp;#160; &amp;#39;, @p7 = N&amp;#39;8T4&amp;#160; &amp;#39;,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p8 = N&amp;#39;8T8&amp;#160; &amp;#39;, @p9 = N&amp;#39;9AK&amp;#160; &amp;#39;, @p10 = 1819, @p11 = 1820, @p12 = 1821,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p13 = 1822, @p14 = 3614, @p15 = 0&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;De un primer vistazo, podemos ver que la consulta esta generada automáticamente por NHibernate. No es que sea inherentemente malo, solo lo digo a título informativo :)&lt;/p&gt;  &lt;p&gt;Procedimos a comprobar los tiempos de esta consulta con SET STATISTICS TIME ON:&lt;/p&gt;  &lt;p&gt;&lt;font size="1" face="cons"&gt;SQL Server Execution Times:     &lt;br /&gt;&amp;#160;&amp;#160; CPU time = &lt;font color="#ff0000"&gt;703 ms&lt;/font&gt;,&amp;#160; elapsed time = &lt;font color="#ff0000"&gt;796 ms&lt;/font&gt;&lt;/font&gt;.&lt;/p&gt;  &lt;p&gt;A la vista del tamaño de filas y la vista, sí que es cierto que el tiempo de ejecución de casi un segundo parece ser demasiado elevado. Por ello, procedimos a analizar el número de operaciones de E/S de cada elemento involucrado en la consulta, mediante SET STATISTICS IO ON:&lt;/p&gt;  &lt;p&gt;&lt;font size="1" face="consoles"&gt;(50 row(s) affected)     &lt;br /&gt;&lt;font color="#ff0000"&gt;Table &amp;#39;Worktable&amp;#39;. Scan count 51, logical reads 92037, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.&lt;/font&gt;      &lt;br /&gt;Table &amp;#39;Versiones&amp;#39;. Scan count 53, logical reads 316, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.      &lt;br /&gt;Table &amp;#39;Modelos&amp;#39;. Scan count 106, logical reads 424, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.      &lt;br /&gt;Table &amp;#39;Sufijos&amp;#39;. Scan count 9852, logical reads 20996, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.      &lt;br /&gt;Table &amp;#39;Colores&amp;#39;. Scan count 10, logical reads 292, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Como se puede ver, hay bastante actividad de E/S en casi todas las tablas, pero lo que me llamó la atención por encima de todo fue la elevada actividad en las &lt;em&gt;worktables&lt;/em&gt;…&lt;/p&gt;  &lt;h5&gt;¿¡Worktables?! ¡¿Que mi madre es eso?!&lt;/h5&gt;  &lt;p&gt;Pues las worktables son un concepto muy importante en SQL Server, y a la vez, muy poco conocido. En muchas ocasiones son la causa de la degradación de rendimiento de un procedimiento almacenado al suministrarle diferentes parámetros, el origen de los temidos Sort Warning y Hash Warning, y la raíz de todos los males de la huma… perdón, que me dejé llevar :)&lt;/p&gt;  &lt;p&gt;Las worktables en realidad son un mal necesario; no son más que unas tablas temporales que se crean en tempDb para las operaciones de Sort y Hash que no han conseguido suficiente memoria como para hacerlas sobre el Buffer Pool, u operaciones grandes de cursores o tipos de datos LOB… en definitiva, son una solución de emergencia para cuando deseamos realizar una operación que va a requerir gran cantidad de memoria.&lt;/p&gt;  &lt;p&gt;Habría muchos ejemplos de su utilización, pero os voy a poner uno muy sencillo: Imaginad que tenemos un procedimiento almacenado para realizar un proceso que hace una JOIN de las filas de dos tablas en un periodo de tiempo determinado. Este procedimiento recibe dos parámetros: fecha de inicio y fecha de fin. &lt;/p&gt;  &lt;p&gt;Ahora imaginad que la primera vez que se despliega ese procedimiento, se ejecuta para un rango de un solo día. Ese procedimiento va a compilarse tratando de optimizar la ejecución para ese rango de fechas: SQL Server podría decidir realizar la JOIN mediante un operador HASH JOIN debido a que el número de filas no es demasiado elevado, y reservará la cantidad de memoria justa para realizar la operacion de HASH para esas filas.&lt;/p&gt;  &lt;p&gt;Supongamos que al día siguiente, esta consulta se realiza para un rango temporal de un mes entero; SQL Server ya tiene el plan cacheado, por lo que va a tratar de reutilizarlo, pero la asignación de memoria para la operación de HASH era la justa para las filas de un día. Al comenzar a ejecutar la consulta, el procesador de consultas detectará que no tiene memoria suficiente y decidirá terminar la operación sobre una Worktable en TempDb. Esto es mucho más lento, pero al menos garantiza que la operación pueda finalizar.&lt;/p&gt;  &lt;h5&gt;Volviendo al Turrón:&lt;/h5&gt;  &lt;p&gt;A la vista de la actividad de E/S en Worktables, decidí confirmar mis sospechas, por lo que adjunté una traza de profiler:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/profiler_5F00_70E247EA.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;" title="profiler" border="0" alt="profiler" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/profiler_5F00_thumb_5F00_75948A3F.png" width="540" height="282" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;¡Bingo! Podemos comprobar que aparece un evento de &lt;em&gt;Hash Warning&lt;/em&gt; al ejecutar la consulta. &lt;/p&gt;  &lt;p&gt;Bien, ya sabemos la razón de nuestro problema de rendimiento: el uso de tempDb. Ahora solo nos queda saber por qué esta consulta esta ejecutándose en TempDb. &lt;/p&gt;  &lt;p&gt;Después de un par de ideas no muy afortunadas basadas en la recompilación de esa consulta, decidí estudiar los tipos de datos de la definición de esa tabla, para ver si coincidían con los que se pasaban como parámetros en el &lt;em&gt;sp_executesql. &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;A continuación os muestro las columnas de la vista en cuestion. Permitidme que antes os avise de que lo que vais a ver a continuación puede herir la sensibilidad de más de un desarrollador o arquitecto de datos(**) :)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/Definicion_5F00_1677D71A.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;" title="Definicion" border="0" alt="Definicion" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/Definicion_5F00_thumb_5F00_7BCB3B00.png" width="373" height="321" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Como podéis ver, la columna CodigoDB2 está definida como &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;, pero en el código de la consulta que genera NHibernate nos pasa el parámetro como &lt;font color="#ff0000"&gt;nvarchar(5)&lt;/font&gt;, lo cual aumenta el peso de la consulta considerablemente, y puede estar provocando que la memoria reservada para la consulta no sea suficiente y tenga que volcar la operación sobre worktables en tempDb.&lt;/p&gt;  &lt;p&gt;Hicimos la prueba, cambiando los tipos de datos sobre la consulta generada por NHibernate en el &lt;em&gt;sp_executesql&lt;/em&gt;, quedando la misma así:&lt;/p&gt;  &lt;p&gt;&lt;font size="1" face="Consolas"&gt;EXEC sp_executesql N&amp;#39;     &lt;br /&gt;SELECT       &lt;br /&gt;&amp;#160;&amp;#160; this_.ID as ID90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.BorradoLogico as BorradoL2_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.Descripcion as Descripc3_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.Estado as Estado90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.VisibleWeb as VisibleWeb90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.CodigoDB2 as CodigoDB6_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.FechaPrevistaInicioComercializacion as FechaPre7_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.FechaFinComercializacion as FechaFin8_90_0_,&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160; this_.Comentarios as Comentar9_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.URLFoto as URLFoto90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.Orden as Orden90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.URLFotoMiniatura as URLFoto12_90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.SufijoID as SufijoID90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.MarcaID as MarcaID90_0_,       &lt;br /&gt;&amp;#160;&amp;#160; this_.VersionId as VersionId90_0_       &lt;br /&gt;FROM       &lt;br /&gt;&amp;#160;&amp;#160; VistaProblematica this_       &lt;br /&gt;WHERE       &lt;br /&gt;&amp;#160;&amp;#160; this_.CodigoDB2 in (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) and       &lt;br /&gt;&amp;#160;&amp;#160; this_.SufijoID in (@p10, @p11, @p12, @p13, @p14) and this_.BorradoLogico = @p15&amp;#39;,      &lt;br /&gt;N&amp;#39;@p0 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p1 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p2 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p3 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p4 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p5 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p6 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p7 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p8 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p9 &lt;font color="#ff0000"&gt;char(5)&lt;/font&gt;,@p10 bigint,@p11 bigint,@p12 bigint,@p13 bigint,@p14 bigint,@p15 bit&amp;#39;,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p0 = N&amp;#39;040&amp;#160; &amp;#39;, @p1 = N&amp;#39;1F7&amp;#160; &amp;#39;, @p2 = N&amp;#39;1G3&amp;#160; &amp;#39;, @p3 = N&amp;#39;209&amp;#160; &amp;#39;,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p4 = N&amp;#39;3R3&amp;#160; &amp;#39;, @p5 = N&amp;#39;8S1&amp;#160; &amp;#39;, @p6 = N&amp;#39;8S6&amp;#160; &amp;#39;, @p7 = N&amp;#39;8T4&amp;#160; &amp;#39;,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p8 = N&amp;#39;8T8&amp;#160; &amp;#39;, @p9 = N&amp;#39;9AK&amp;#160; &amp;#39;, @p10 = 1819, @p11 = 1820, @p12 = 1821,      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p13 = 1822, @p14 = 3614, @p15 = 0&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Tras realizar los cambios, volví a ejecutar la consulta con la información de tiempos y actividad de E/S, y obtuve los siguientes resultados:&lt;/p&gt;  &lt;p&gt;&lt;font size="1" face="Consolas"&gt;SQL Server Execution Times:     &lt;br /&gt;&amp;#160;&amp;#160; CPU time = &lt;font color="#ff0000"&gt;78 ms&lt;/font&gt;,&amp;#160; elapsed time = &lt;font color="#ff0000"&gt;78 ms&lt;/font&gt;.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="1" face="Consolas"&gt;(50 row(s) affected)     &lt;br /&gt;&lt;font color="#ff0000"&gt;Table &amp;#39;Worktable&amp;#39;. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.       &lt;br /&gt;&lt;/font&gt;Table &amp;#39;Colores&amp;#39;. Scan count 10, logical reads 292, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.      &lt;br /&gt;Table &amp;#39;Sufijos&amp;#39;. Scan count 2, logical reads 27, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.      &lt;br /&gt;Table &amp;#39;Versiones&amp;#39;. Scan count 4, logical reads 22, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.      &lt;br /&gt;Table &amp;#39;Modelos&amp;#39;. Scan count 8, logical reads 32, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;¡No está nada mal! Hemos conseguido que la consulta se ejecute diez veces más rápido, sin hacer ninguna modificación real sobre la misma. Toda esa pérdida de tiempo se estaba produciendo por el uso de tempdb como consecuencia de la diferencia entre la memoria estimada y la necesaria.&lt;/p&gt;  &lt;p&gt;Al final, el cliente arregló el mapeo del tipo de datos, estableciendo el sql-type de modo explícito, lo que eliminó este problema puntual. La gran noticia es que, con toda seguridad, este cambio en el mapeo afectará a muchas otras consultas, por lo que se espera un incremento generalizado del rendimiento en todas las consultas.&lt;/p&gt;  &lt;h5&gt;Conclusiones:&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;Es muy importante garantizar la corrección de los tipos de datos en los mapeos de cualquier solución de persistencia.&lt;/li&gt;    &lt;li&gt;Revisad el uso de vuestras tempdb, la creación de worktables y la presencia de eventos de tipo Hash Warning o Sort Warning en vuestros sistemas; es muy posible que os llevéis alguna sorpresa!&lt;/li&gt;    &lt;li&gt;Estaba claro que si yo iba a hablar acerca de NHibernate, no iba a ser enteramente para bien… ;)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Keep Rockin’!&lt;/p&gt; &lt;em&gt;(*): Soy perfectamente consciente de lo mal que puede llegar a sonar esa frase!    &lt;br /&gt;(**): Tengo que dejarlo claro: el modelo de datos NO es mío!!! :)&lt;/em&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;En esta ocasión, voy a dar un poquito más de caña de lo habitual. Los que seguís este blog y sus Rock Tips(tm) sabéis que casi siempre me decanto por un puntito hardrockero melódico, que es lo que suelo escuchar gran parte del tiempo. Sin embargo, en esta ocasión creo que os voy a sorprender con uno de mis grupos favoritos, aunque son de un palo bastante mas heavy: se trata de los suecos ‘&lt;a href="http://en.wikipedia.org/wiki/In_Flames"&gt;In Flames&lt;/a&gt;’, grupo fundado y liderado hasta hace poco por ese genio que es Jesper Strömblad.&lt;/p&gt;  &lt;p&gt;Cuando estaba escribiendo este post sobre el mapeo en Hibernate, no pude evitar que se me viniera a la cabeza su tema ‘&lt;a href="http://www.youtube.com/watch?v=wCvq8VN9owY"&gt;Pinball Map&lt;/a&gt;’; quizá fue simplemente por la palabra map, o quizá porque necesitaba un poco de buen death metal melódico sueco para desintoxicarme de NHibernate xD Sea como sea, me apetece compartirlo con vosotros, así que.. enjoy! ;)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=177786" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Rendimiento/default.aspx">Rendimiento</category></item><item><title>Rainbow In The Dark: Materiales de la sesión de Optimización de SQL Server</title><link>http://geeks.ms/blogs/palvarez/archive/2010/06/01/rainbow-in-the-dark-materiales-de-la-sesi-243-n-de-optimizaci-243-n-de-sql-server.aspx</link><pubDate>Tue, 01 Jun 2010 18:13:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:177557</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=177557</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/06/01/rainbow-in-the-dark-materiales-de-la-sesi-243-n-de-optimizaci-243-n-de-sql-server.aspx#comments</comments><description>&lt;p&gt;El pasado Jueves 27 tuve la oportunidad de pasar un par de horas muy agradables en compañía de la gente de MAD.NUG, hablando de optimización de SQL Server. En resumen, vine a explicar un poco el proceso que yo sigo a la hora de enfrentarme a un problema de rendimiento en un entorno SQL Server que, en la práctica totalidad de los casos, me resulta desconocido.&lt;/p&gt;  &lt;p&gt;Empezamos repasando algunos de los informes básicos que el producto pone a nuestra disposición, para hacernos una idea de la salud general del servidor, y fuimos bajando de nivel y obteniendo más detalle gracias a la utilización de alguna de las muchas DMVs del sistema. Repasamos y explicamos las esperas del servidor (&lt;em&gt;sys.dm_os_wait_stats&lt;/em&gt;) y aproveché para contar un par de batallitas sobre optimizaciones extremas mediante la eliminación de CPUs :)&lt;/p&gt;  &lt;p&gt;Por último, dedicamos la última parte de la sesión a estudiar algunos escenarios curiosos de rendimiento, como el uso inapropiado de UDFs en los predicados de las consultas, el tan conocido empleo de cursores, los peligros de las consultas Ad Hoc y por último, un escenario muy interesante de ordenación en tempDb por problemas de estimación de memoria y &lt;em&gt;parameter sniffing&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;He de admitir que, para ser una sesión de SQL Server, me lo pasé bien! y es que no solo de WinDbg vive el hombre ;) &lt;/p&gt;  &lt;p&gt;Aprovecho para dejaros &lt;a href="http://geeks.ms/media/p/177541.aspx"&gt;aquí&lt;/a&gt; los materiales de la sesión, tanto las PPTs como los scripts que utilicé durante la misma.&lt;/p&gt;  &lt;p&gt;Gracias a todos los asistentes (muy buenas preguntas!) y por supuesto, a la organización de Mad.Nug :) &lt;/p&gt;  &lt;p&gt;Keep Rockin’!&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rock Tip:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Podría tratar de encontrar algún rebuscado nexo entre el Rock Tip de hoy y el texto del post; como que espero que los consejos que compartí con vosotros os sirvan en alguna ocasión como ese ‘arcoíris en la oscuridad’ para resolver algún problema en vuestros entornos SQL Server, o que algunos de esos scripts valen más que el oro al otro lado del arcoíris…&lt;/p&gt;  &lt;p&gt;Pero esta vez no. Esta vez no necesito justificación para mi Rock Tip. Hoy se trata de un homenaje, y para eso no son necesarias excusas. Ronnie James Dio, la voz del heavy metal, el padre de la &lt;em&gt;mano cornuta&lt;/em&gt; (los cuernos heavies de toda la vida!) nos abandonó el día 16 del pasado mes. Un hombre que, pese a sus 67 años, seguía subiéndose a al escenario con una tremenda energía, con una voz asombrosa y sobre todo, con unas ganas de entretener y de ganarse el cariño de sus fans noche tras noche. &lt;/p&gt;  &lt;p&gt;Se nos ha ido un grande, pero está claro que será recordado siempre por su legión de seguidores desde los años 70, los chavales de hoy y, sin duda, los que vendrán.&lt;/p&gt;  &lt;p&gt;Aquí os dejo una versión del “&lt;a href="http://www.youtube.com/watch?v=1Sxc25uWqI8&amp;amp;feature=related"&gt;Rainbow In The Dark&lt;/a&gt;” en directo en el Wacken de 2004, donde podemos ver que el gran &lt;a href="http://es.wikipedia.org/wiki/Ronnie_James_Dio"&gt;Ronnie James Dio&lt;/a&gt; seguía estando como un chaval y disfrutando como si aún estuviera en Black Sabbath allá por 1979!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=177557" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Rendimiento/default.aspx">Rendimiento</category></item><item><title>Looks that Kill: Componentes de DevExpress y ThreadAbortException</title><link>http://geeks.ms/blogs/palvarez/archive/2010/06/01/looks-that-kill-componentes-de-devexpress-y-threadabortexception.aspx</link><pubDate>Mon, 31 May 2010 23:12:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:177520</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=177520</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/06/01/looks-that-kill-componentes-de-devexpress-y-threadabortexception.aspx#comments</comments><description>&lt;h6&gt;Aviso a Navegantes: El siguiente post no va a ser políticamente correcto. Es más, creo que este año los chicos de Developer Express Inc. no me van a enviar un jamoncito ni una botella de vino por Navidad, precisamente. Y sin embargo, me siento en la obligación de compartir esto con vosotros… así que ¡allá vamos!&lt;/h6&gt;  &lt;p&gt;Últimamente he pasado bastante tiempo en tierras Navarras: alegrándome la vista con el verdecito que ya voy echando tanto de menos, disfrutando como un enano de los increibles pintxos de Pamplona y, de cuando en cuando, tirando de WinDbg para resolver algunos problemas de rendimiento que tiene uno de nuestros clientes aquí :) &lt;/p&gt;  &lt;p&gt;Y es que en estas semanas he visto muchos escenarios interesantes: las tradicionales fugas de memoria por manejadores de eventos en páginas ASP.NET, problemas con el tamaño de sesión y el histórico de ViewStates, un curioso caso de excepciones indeseadas en cada invocación a un Servicio Web con transacciones que espero poder postear en breve… vamos, ¡que no me he aburrido!&lt;/p&gt;  &lt;p&gt;Uno de estos problemas, y uno de los más llamativos, tenía que ver con la increible cantidad de excepciones lanzadas en el frontal web de la aplicación; estamos hablando de varias decenas de miles a la hora! A estas alturas no hace falta que os diga que el mero hecho de lanzar una excepción (aunque esta sea capturada por nuestro código) supone un impacto negativo en el rendimiento, y debemos tratar de evitar estas situaciones.&lt;/p&gt;  &lt;p&gt;Si bien el contador de rendimiento &lt;strong&gt;# of Excepts Thrown &lt;/strong&gt;en &lt;strong&gt;.NET CLR Exceptions &lt;/strong&gt;era suficiente para detectar el problema, necesitabamos &lt;em&gt;algo más&lt;/em&gt; para averiguar el tipo de excepiones lanzadas y poder investigar mejor el problema real. Como no podía ser de otra manera, ese &lt;em&gt;algo más&lt;/em&gt; fue WinDbg :)&lt;/p&gt;  &lt;p&gt;Después de adjuntarme al proceso, le pedí a WinDbg que se detuviera cada vez que saltara una excepcion .NET (&lt;em&gt;sxe clr&lt;/em&gt;) y que en cada una de ellas, me mostrara la información de la excepción (&lt;em&gt;!pe&lt;/em&gt;), la pila de llamadas administrada (&lt;em&gt;!clrstack&lt;/em&gt;) y que prosiguiera la ejecución sin manejar la excepción (&lt;em&gt;gn&lt;/em&gt;):&lt;/p&gt;  &lt;p align="center"&gt;&lt;b&gt;sxe –c “!pe; !clrstack; gn” clr&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;La salida demostró que había dos tipos que conformaban la práctica totalidad de las excepciones:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;em&gt;MissingManifestResourceException:&lt;/em&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Esta excepción no me preocupaba demasiado, porque en número era muy inferior a la que veremos a continuación. Sin embargo, es curioso el hecho de que siempre sucedía en unas DLLs de DevExpress. &lt;/p&gt;    &lt;p&gt;A continuación os pongo una ocurrencia del problema (omitiendo la pila de llamadas, que en este caso no es relevante):&lt;/p&gt;    &lt;p&gt;&lt;font size="1" face="Consolas"&gt;(d18.11b4): CLR exception - code e0434f4d (first chance)        &lt;br /&gt;Missing image name, possible paged-out or corrupt data.         &lt;br /&gt;Exception object: 0000000240991ed8         &lt;br /&gt;Exception type: &lt;font color="#ff0000"&gt;&lt;strong&gt;System.Resources.MissingManifestResourceException&lt;/strong&gt;           &lt;br /&gt;&lt;/font&gt;Message: &lt;strong&gt;&lt;font color="#ff0000"&gt;Could not find any resources appropriate for the specified culture or the neutral culture.&amp;#160; Make sure &amp;quot;&lt;font color="#800000"&gt;Resources.DevExpress_XtraScheduler_v9_3_Core.resources&lt;/font&gt;&amp;quot; was correctly embedded or linked into assembly &amp;quot;App_GlobalResources.2gule58b&amp;quot; at compile time, or that all the satellite assemblies required are loadable and fully signed.             &lt;br /&gt;&lt;/font&gt;&lt;/strong&gt;InnerException: &amp;lt;none&amp;gt;         &lt;br /&gt;StackTrace (generated):         &lt;br /&gt;&amp;lt;none&amp;gt;         &lt;br /&gt;StackTraceString: &amp;lt;none&amp;gt;         &lt;br /&gt;HResult: 80131532&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;Después de revisar la solución, comprobamos que todas las referencias a todas las DLLs de DevExpress estaban aparentemente bien, por lo que decidimos involucrar al soporte de&lt;em&gt; Developer Express&lt;/em&gt; en este caso.&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;em&gt;ThreadAbortException: &lt;/em&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Esta excepción ya &lt;a href="http://www.youtube.com/watch?v=XAg5KjnAhuU"&gt;suena peor&lt;/a&gt; ¿verdad? Hacía no mucho, en este mismo cliente, nos habíamos encontrado con el conocido bug de la plataforma en el método Response.End(), pero…. ¡no adelantemos acontecimientos! &lt;/p&gt;    &lt;p&gt;Primero veamos un ejemplo de una de las excepciones que capturamos y su volcado de pila:&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font size="1" face="Consolas"&gt;(d18.11b4): CLR exception - code e0434f4d (first chance)       &lt;br /&gt;Exception object: 0000000200f83940        &lt;br /&gt;Exception type: &lt;strong&gt;&lt;font color="#ff0000"&gt;System.Threading.ThreadAbortException&lt;/font&gt;&lt;/strong&gt;        &lt;br /&gt;Message: Thread was being aborted.        &lt;br /&gt;InnerException: &amp;lt;none&amp;gt;        &lt;br /&gt;StackTrace (generated):        &lt;br /&gt;SP&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IP&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Function        &lt;br /&gt;000000000911E8E0 0000000000000001 System.Threading.Thread.AbortInternal()        &lt;br /&gt;000000000911E8E0 000006427834300A System.Threading.Thread.Abort(System.Object)        &lt;br /&gt;000000000911E930 00000642BC9131D6 &lt;strong&gt;&lt;font color="#ff0000"&gt;System.Web.HttpResponse.End()           &lt;br /&gt;&lt;/font&gt;&lt;/strong&gt;000000000911E980 0000064281AC2EA6 &lt;strong&gt;&lt;font color="#ff0000"&gt;DevExpress.Web.ASPxClasses.Internal.HttpUtils.EndRespons&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font size="1" face="Consolas"&gt;StackTraceString: &amp;lt;none&amp;gt;       &lt;br /&gt;HResult: 80131530        &lt;br /&gt;OS Thread Id: 0x11b4 (23)        &lt;br /&gt;Child-SP&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; RetAddr&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Call Site        &lt;br /&gt;000000000911e980 00000642803d1965 DevExpress.Web.ASPxClasses.Internal.HttpUtils.EndResponse()        &lt;br /&gt;000000000911e9c0 00000642803d049d DevExpress.Web.ASPxClasses.Internal.ResourceManager.ProcessRequest()        &lt;br /&gt;000000000911ea80 00000642bc8f2eb0 DevExpress.Web.ASPxClasses.ASPxHttpHandlerModule.BeginRequestHandler(System.Object, System.EventArgs)        &lt;br /&gt;000000000911eab0 00000642bc8e449b System.Web.HttpApplication+SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()        &lt;br /&gt;000000000911eb10 00000642bc8f2215 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)        &lt;br /&gt;000000000911ebb0 00000642bc8e3553 System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)        &lt;br /&gt;000000000911ec60 00000642bc8e7874 System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)        &lt;br /&gt;000000000911ecc0 00000642bc8e745c System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)        &lt;br /&gt;000000000911ed50 00000642bc8e608c System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)        &lt;br /&gt;000000000911ed90 000006427f602012 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;Como se puede ver, uno de los métodos de las librerias de DevExpress, &lt;strong&gt;DevExpress.Web.ASPxClasses.Internal.HttpUtils.EndResponse&lt;/strong&gt; está &lt;strong&gt;invocando a System.Web.HttpResponse.End(),&lt;/strong&gt; el cual a su vez lanza una excepción de tipo &lt;strong&gt;ThreadAbortException&lt;/strong&gt;.&lt;/p&gt;    &lt;p&gt;Mmm… antes hablabamos de un caso conocido de excepción &lt;em&gt;ThreadAbortException&lt;/em&gt; en las llamadas a &lt;em&gt;HttpResponse.End(),&lt;/em&gt; así que una rápida busqueda nos lleva al &lt;a href="http://support.microsoft.com/kb/312629"&gt;KB312629&lt;/a&gt;, que si no conoceis os recomiendo que leais y comprobéis si vuestras aplicaciones se ven afectadas por él.&lt;/p&gt;    &lt;p&gt;Una comprobación del código fuente del método de DevExpress (con la siempre inestimable ayuda de .NET Reflector), nos revela que los desarrolladores del producto son conscientes del problema, implementando un catch para el &lt;em&gt;ThreadAbortException&lt;/em&gt;:&lt;/p&gt;    &lt;p&gt;public static void EndResponse()     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; HttpContext.Current.ApplicationInstance.CompleteRequest();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; try      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; GetResponse().End();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; catch (ThreadAbortException)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;Sin embargo, esta solución no evita el lanzamiento descontrolado de las excepciones que, como ya se ha comentado, a pesar de ser controladas, siguen teniendo un impacto sobre el rendimiento de la aplicación, ¡por no hablar del ruido que meten a la hora del monitorizar el sistema!     &lt;br /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Con esta información en la mano, elaboré un documento detallado (mucho más que este post) para que mi cliente pudiera abrir un caso de soporte con la gente de DevExpress, esperando que resolvieran el problema que nos estaba impactando severamente en producción, mediante la implementación condicional de una llamada a &lt;b&gt;HttpContext.Current.ApplicationInstance.CompleteRequest()&lt;/b&gt; en lugar de invocar al método HttpResponse.End().&lt;/p&gt;  &lt;p&gt;La respuesta de la gente de DevExpress no se hizo esperar mucho (punto para ellos!), y se resume en lo siguiente:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;No van a cambiar el código, ni a dejar la opcion al desarrollador de asumir el cambio con el &lt;em&gt;CompleteRequest&lt;/em&gt;.&lt;/li&gt;    &lt;li&gt;Del problema de las &lt;em&gt;MissingManifestResourceException&lt;/em&gt; simplemente nos comentaron que esas excepciones son esperadas y que no nos preocupemos.&lt;/li&gt;    &lt;li&gt;Con las dos respuestas (a todas luces insuficientes y debatibles) llegó la notificación del cierre del caso. Sin derecho a réplica.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;En esta ocasion, lo que más rabia me da no es la parte técnica; puedo entender los problemas que tengan para realizar el cambio (aunque no es de recibo que su código levante tantas excepciones), hasta casi puedo entender que su código levanta excepciones buscando recursos localizados inexistentes… pero por lo que no paso es por la dejadez y el mal trato al usuario en el soporte técnico. &lt;/p&gt;  &lt;p&gt;Asi que… ¡Avisados estais! :) Vamos a por el mini-resumen del día…&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Resumiendo:&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;¿Habéis monitorizado su vuestra aplicacion tira excepciones? Si no es así, revisad los contadores de rendimiento y tirad de WinDbg… ¡a lo mejor os llevais una sorpresa!&lt;/li&gt;    &lt;li&gt;Comprobad si teneis &lt;em&gt;ThreadAbortException&lt;/em&gt;, y si es así, evaluad el workaround descrito en el KB.&lt;/li&gt;    &lt;li&gt;¿Estais planteandoos adquirir una licencia para controles de usuario para un nuevo proyecto? ¡Aseguraos de tener un buen soporte, no sabeis lo útil que puede llegar a ser!&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Keep Rockin’!&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;No podía ser de otra manera, este post solo lo podían presentar los chicos de &lt;a href="http://en.wikipedia.org/wiki/M%C3%B6tley_Cr%C3%BCe"&gt;Mötley Crüe&lt;/a&gt; con su “&lt;a href="http://www.youtube.com/watch?v=Noyg4MH8t9Q"&gt;Looks that Kill&lt;/a&gt;”. Apropiado, porque en este caso la vistosa interfaz de usuario de la aplicación es la que contiene un pequeño veneno, como hemos visto ;)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=177520" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/WinDbg/default.aspx">WinDbg</category></item><item><title>Bang Bang!: Optimización Económica en SQL Server</title><link>http://geeks.ms/blogs/palvarez/archive/2010/05/25/bang-bang-optimizaci-243-n-econ-243-mica-en-sql-server.aspx</link><pubDate>Tue, 25 May 2010 20:41:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:177282</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=177282</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/05/25/bang-bang-optimizaci-243-n-econ-243-mica-en-sql-server.aspx#comments</comments><description>&lt;p&gt;Soy un impresentable. No hay manera de que actualice el blog, y cuando lo hago, es para promocionarme de mala manera. Y, como no podía ser de otra manera, esta es una de esas ocasiones :)&lt;/p&gt;  &lt;p&gt;Esta vez tengo que agradecer a &lt;a href="http://geeks.ms/blogs/gtorres/default.aspx"&gt;Gisela&lt;/a&gt;, &lt;a href="http://geeks.ms/blogs/lfraile/"&gt;Luis&lt;/a&gt; y el resto de chicos de Madrid.NET la oportunidad de pasar un ratito &lt;strike&gt;friki&lt;/strike&gt; serio, formal y productivo hablando de optimización &lt;em&gt;económica &lt;/em&gt;de SQL Server. La idea será aprender a localizar de dónde vienen los problemas, en lugar de tratar de optimizar las consultas en base a su &lt;em&gt;duration &lt;/em&gt;elevado de modo sistemático… vamos, la venerable metodología ASM (A Salto deMata(tm)).&lt;/p&gt;  &lt;p&gt;La primera parte del evento abordará las técnicas de revision que yo suelo emplear en mi trabajo en el equipo &lt;strong&gt;DOT&lt;/strong&gt; de Plain Concepts, mientras que la segunda parte se centrará en una serie de casos particulares de optimización que me encuentro en algunos clientes y que, a pesar de que alguno de ellos es muy frecuente, siguen siendo problemas bastante desconocidos para los que no nos pasamos delante de un SQL Server todo el dia :)&lt;/p&gt;  &lt;p&gt;Si el plan os resulta interesante o apetecible, ya sabeis.. ¡nos vemos el jueves! El evento será en las oficinas de Microsoft en La Finca, y los datos del registro los teneis en el siguiente enlace:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032451680&amp;amp;Culture=es-ES"&gt;https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032451680&amp;amp;Culture=es-ES&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Keep rockin’!&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rock Tip: &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;Hoy me toca hacer algo que no me gusta, y que creo que solo hice en otra ocasión en este blog: voy a repetir un Rock Tip. Y voy a hacer esto por tres razones totalmente justificadas:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;El nombre es apropiado… vamos a hacer nuestro el lema de ’&lt;em&gt;Biggest Bang for the Buck&lt;/em&gt;’, así que el &lt;em&gt;Bang Bang!&lt;/em&gt; nos viene que ni pintado… &lt;/li&gt;    &lt;li&gt;Estamos hablando de la que posiblemente sea la mejor canción del mejor grupo de la historia. Punto pelota. xD &lt;/li&gt;    &lt;li&gt;El blog es mio y…. mmmm, creo que recurro con demasiada frecuencia a este punto :) &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Por todo esto, hoy le ha tocado el turno a &lt;a href="http://www.youtube.com/watch?v=doE883HTXpo"&gt;Bang Bang&lt;/a&gt;, un tema del primer disco de &lt;a href="http://en.wikipedia.org/wiki/Danger_Danger"&gt;Danger Danger&lt;/a&gt;. Si os apetece oir una cancion happy, que anima al instante, probadla. Como la gente que me conoce sabe de sobra, esta banda neoyorkina es mi grupo favorito, así que no me extenderé en detalles porque podría llegar a aburriros :)&lt;/p&gt;  &lt;p&gt;Si os interesa la musica de guitarristas para guitarristas, principalmente instrumental, no os perdais los trabajos en solitario de su guitarrista, &lt;a href="http://www.andytimmons.com/"&gt;Andy Timmons&lt;/a&gt;, que para mi es el guitar hero con mas estilo que ha parido madre :) Por cierto, el señor Timmons ha estado esta pasada semana en Madrid… así que también lo celebraremos con un temazo suyo: &lt;a href="http://www.youtube.com/watch?v=KaVVZYOvMFY"&gt;Cry for You&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=177282" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Rendimiento/default.aspx">Rendimiento</category></item><item><title>Photograph: SQL Server Crash Dump Analysis</title><link>http://geeks.ms/blogs/palvarez/archive/2010/04/12/photograph-sql-server-crash-dump-analysis.aspx</link><pubDate>Mon, 12 Apr 2010 14:32:38 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:174445</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=174445</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2010/04/12/photograph-sql-server-crash-dump-analysis.aspx#comments</comments><description>&lt;p&gt;Just a small post to remind that this week I’ll be presenting at &lt;strong&gt;SQLBits VI&lt;/strong&gt;, in UK! I’m going to talk about SQL Server crash dump analysis – some post-mortem debugging techniques that help us to discover what went wrong and why our SQL Server crashed, using mostly WinDbg. We will also do a little tour on managed debugging, showing how these techniques and tools can be useful when trying to detect anomalous behaviors on our .NET Applications accessing the database.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;strong&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/SQLBitsLogo_5F00_5FCF8EA2.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;" title="SQLBitsLogo" border="0" alt="SQLBitsLogo" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/SQLBitsLogo_5F00_thumb_5F00_352387F8.jpg" width="240" height="81" /&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;It goes without saying that I’m really excited to be able to share event with such an incredible list of speakers! There are other incredible tracks at the same time: &lt;strong&gt;Conor Cunningham&lt;/strong&gt; will come all the way from Redmond to London to share with us some of the internals and secrets the Query Optimizer, &lt;strong&gt;James&lt;/strong&gt; will deliver a very interesting session on sequential I/Os (I wish I could invite some of my customers to that session!) and &lt;strong&gt;Satya&lt;/strong&gt; will share his huge experience with us in a best practices session. With this great sessions at the same time, I understand many of you that could be interested in attending my session won’t be able to! So if you cannot attend my session, just catch me anytime on the venue and I will be more than happy to have a nice chat about post-mortem debugging, WinDbg or whatever… by the way, I’m the one with the cowboy boots and long hair! :)&lt;/p&gt;  &lt;p&gt;See you at SQL Bits on Thursday!&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;Each time that I write a new entry on this blog I use to spend a ridiculous amount of time looking for a song that fits the post; you know I don’t want my Rock Tips to be just a bunch of songs that I like without a reason. Well, this time the job was really easy! Think about it: the session is going to be in the UK… so a band from the country is definitely a must. And I’m going to be talking about memory snapshot analysis… about ‘&lt;em&gt;photographs’&lt;/em&gt; of the process memory… so, without further ado, let me introduce you the Rock Tip of the day: &lt;a href="http://www.youtube.com/watch?v=1XSl2QDeIOg&amp;amp;feature=related"&gt;Photograph&lt;/a&gt;, by &lt;a href="http://en.wikipedia.org/wiki/Def_Leppard"&gt;Def Leppard&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;One of that classic 80’s tunes that I love so much, and definitely one of my fave from this always impressive bands. This time I’ve chosen to link the song to a live performance of the band, and not to the promotional video of the single, so you can enjoy the impressive work on the backing vocals, the acting and the always missed guitar playing of the late Steve Clark. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=174445" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/WinDbg/default.aspx">WinDbg</category></item><item><title>Just Push Play: Depuración Avanzada (2ª Parte) en Second Nug</title><link>http://geeks.ms/blogs/palvarez/archive/2009/12/15/just-push-play-depuraci-243-n-avanzada-2-170-parte-en-second-nug.aspx</link><pubDate>Tue, 15 Dec 2009 02:30:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:162556</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=162556</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/12/15/just-push-play-depuraci-243-n-avanzada-2-170-parte-en-second-nug.aspx#comments</comments><description>&lt;p&gt;Lo se, lo se&amp;hellip; &amp;iexcl;os tengo muy abandonados! y de hecho, la entrada de hoy no va a cambiar mucho la situaci&amp;oacute;n, ya que ser&amp;aacute; muy breve; un simple ejercicio de autopromoci&amp;oacute;n :)&lt;/p&gt;
&lt;p&gt;Solo quer&amp;iacute;a recordaros que ma&amp;ntilde;ana, Martes 15 de Diciembre, tengo el placer de poder dar la continuaci&amp;oacute;n del evento de Depuraci&amp;oacute;n Avanzada que d&amp;iacute; en colaboraci&amp;oacute;n con los chicos y chicas de Second Nug.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n teneis los detalles de registro para el evento de ma&amp;ntilde;ana:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032434091&amp;amp;EventCategory=4&amp;amp;culture=es-ES&amp;amp;CountryCode=ES"&gt;&lt;img height="382" width="513" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/Debugging_5F00_15A05356.png" alt="Debugging" border="0" title="Debugging" style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;PISTA: Pinchad en la imagen :)&lt;/p&gt;
&lt;p&gt;En el abordaremos alguna demo de depuraci&amp;oacute;n con WinDbg que nos qued&amp;oacute; pendiente en la primera sesi&amp;oacute;n, as&amp;iacute; como depuracion con CLR 4.0. Por ultimo, terminaremos echando un vistazo a las neuvas caracter&amp;iacute;sticas de depuraci&amp;oacute;n de Visual Studio 2010, que son sencillamente espectaculares. De echo, para una vez que escribo, voy a tirar la casa por la vetnana y tambi&amp;eacute;n os &lt;a href="http://www.microsoft.com/visualstudio/en-us/products/2010/default.mspx"&gt;recuerdo el link a la descarga de Visual Studio 2010 Beta 2&lt;/a&gt;, para que podais jugar con &amp;eacute;l :)&lt;/p&gt;
&lt;p&gt;Keep Rockin&amp;rsquo;!!!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rock Tip:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ya sab&amp;eacute;is, los chicos de Aerosmith est&amp;aacute;n de actualidad por el espect&amp;aacute;culo de prensa rosa que est&amp;aacute;n protagonizando &amp;uacute;ltimamente; la &amp;uacute;tlima barbaridad que yo he escuchado es que Lenny Kravitz quiere sustituir a Steven Tyler a la voz!! Yo me quedo con la idea de que es todo un truco publicitario, la necesidad de hacer un poco de ruido. Y si es as&amp;iacute;, les ha funcionado porque aqui estoy yo para recordaros a todos lo grande que es esta banda! &lt;/p&gt;
&lt;p&gt;En este caso, hemos querido dedicarle el tema &lt;a href="http://www.youtube.com/watch?v=N_E9qT2WhU0"&gt;Just Push Play&lt;/a&gt;&amp;hellip; un tema que nos va a venir al pelo al analizar los volcados de memoria desde el Visual Studio 2010, &amp;iexcl;ya ver&amp;eacute;is! :)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.microsoft.com/visualstudio/en-us/products/2010/default.mspx" title="http://www.microsoft.com/visualstudio/en-us/products/2010/default.mspx"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=162556" width="1" height="1"&gt;</description></item><item><title>Beat The Bullet: Aplazado el Evento de SQL Server en Coruña</title><link>http://geeks.ms/blogs/palvarez/archive/2009/07/16/beat-the-bullet-aplazado-el-evento-de-sql-server-en-coru-241-a.aspx</link><pubDate>Thu, 16 Jul 2009 10:28:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:152484</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=152484</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/07/16/beat-the-bullet-aplazado-el-evento-de-sql-server-en-coru-241-a.aspx#comments</comments><description>&lt;p&gt;No os podéis imaginar lo que me fastidia tener que daros esta noticia, pero me he visto obligado a tener que posponer mi sesión de Optimización de SQL Server que los chicos de .NUGG habían organizado en Coruña.&lt;/p&gt;  &lt;p&gt;Estamos intentando moverla al Viernes de la semana que viene; se que es precipitado, pero si esperamos más, nos metemos en periodo de vacaciones. Espero editar este post a lo largo de la tarde y daros la confirmación definitiva.&lt;/p&gt;  &lt;p&gt;A todos los que estabais apuntados para el evento, por favor, aceptad mis disculpas. A veces estas cosas pasan.&lt;/p&gt;  &lt;p&gt;Parece que esa Estrella Galicia va a tener que esperar un poquito :) Keep Rockin’!&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;Como ya sabréis, &lt;em&gt;Beat The Bullet&lt;/em&gt; es una expresión que viene a querer decir algo así como ‘aguantar estoicamente cuando algo va mal’, una expresión que ya emplee en &lt;a href="http://geeks.ms/blogs/palvarez/archive/2008/03/17/beat-the-bullet-a-veces-ni-con-magia.aspx"&gt;otra entrada de este blog&lt;/a&gt;, curiosamente para hacer referencia a otra sesión en Coruña. En aquella ocasión, el&lt;em&gt; Beat the Bullet&lt;/em&gt; hacia mención al mejor tema del mejor grupo de la historia, el &lt;a href="http://www.youtube.com/watch?v=dRCCP1_09us"&gt;Beat the Bullet&lt;/a&gt; de los &lt;a href="http://en.wikipedia.org/wiki/Danger_Danger"&gt;Danger Danger&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Como no me gusta repetir temas en los Rock Tips, en esta ocasión haré mención a otro temazo con el mismo nombre, el &lt;a href="http://www.youtube.com/watch?v=LQrpgsiSIU4"&gt;Beat the Bullet&lt;/a&gt; de &lt;a href="http://en.wikipedia.org/wiki/Vain_(band)"&gt;Vain&lt;/a&gt;. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=152484" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Comunidad/default.aspx">Comunidad</category></item><item><title>Speed of Light: Evento sobre Optimización de SQL Server en Coruña</title><link>http://geeks.ms/blogs/palvarez/archive/2009/07/14/speed-of-light-evento-sobre-optimizaci-243-n-de-sql-server-en-coru-241-a.aspx</link><pubDate>Mon, 13 Jul 2009 23:20:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:152334</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=152334</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/07/14/speed-of-light-evento-sobre-optimizaci-243-n-de-sql-server-en-coru-241-a.aspx#comments</comments><description>&lt;p&gt;Este Viernes 17 voy a tener la oportunidad de volver a pasarme por tierras gallegas. En esta ocasión, los chicos de .NUGG han tenido a bien invitarme a presentar una sesión sobre Optimización de SQL Server, así que antes de nada, permitidme que agradezca a &lt;a href="http://geeks.ms/blogs/quintas/"&gt;Edu&lt;/a&gt; y a &lt;a href="http://geeks.ms/blogs/eecsaky/"&gt;Euge&lt;/a&gt; su invitación y la organización del evento! Gracias chicos!&lt;/p&gt;  &lt;p&gt;Para ser sinceros, esta sesión no deja de ser una deuda contraída con los asistentes a mi &lt;a href="http://geeks.ms/blogs/palvarez/archive/2009/04/14/calling-on-you-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-a-coru-241-a.aspx"&gt;última sesión en Coruña sobre Depuración y Optimización con WinDbg&lt;/a&gt;. En ella se demostró un claro interés por la optimización de SQL Server, y prometí volver con un temario centrado en exclusiva en este tema. Como lo prometido es deuda, y como necesitaba alguna excusa para tomarme una Estrella Galicia en buena compañía, este viernes nos veremos en Coruña!&lt;/p&gt;  &lt;p&gt;Aquí os dejo los detalles de la sesión, a la que os podéis registrar &lt;a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032421168&amp;amp;Culture=es-ES"&gt;pulsando aquí&lt;/a&gt;. ¡¡Nos vemos en Coruña!!&lt;/p&gt;  &lt;h4&gt;Speed of Light: Optimización de SQL Server&lt;/h4&gt;  &lt;p&gt;&lt;strong&gt;Fecha:&lt;/strong&gt; viernes, 17 de julio de 2009     &lt;br /&gt;&lt;strong&gt;Horario:&lt;/strong&gt; 17:00 - 19:00    &lt;br /&gt;&lt;strong&gt;Lugar:&lt;/strong&gt;     &lt;br /&gt; - UNIVERSIDADE DA CORUÑA    &lt;br /&gt; - Aula 1, Edificio Xoana Capdevielle    &lt;br /&gt; - Campus de Elviña s/n A Coruña 15071    &lt;br /&gt;    &lt;br /&gt;&lt;strong&gt;Descripción:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Esta sesión está dedicada a detallar las técnicas y herramientas que nos permitirán exprimir el rendimiento de nuestro SQL Server al máximo, haciendo un repaso por la teoría implicada, y pasando directamente a ejemplos del Mundo Real™. Se abordarán buenas prácticas de indizado, las consideraciones de almacenamiento más relevantes, el análisis de planes de ejecución, así como la utilización de nuevas características de SQL Server 2008 para optimizar cargas de trabajo. &lt;/p&gt;  &lt;p&gt;1.- Arquitectura general de SQL Server   &lt;br /&gt;2.- Metodología Waits &amp;amp; Queues: Monitorización de Esperas en SQL Server    &lt;br /&gt;3.- Optimización de Almacenamiento    &lt;br /&gt;4.- Optimización del Uso de Memoria    &lt;br /&gt;5.- Aislamiento Transaccional    &lt;br /&gt;6.- Optimización de Consultas&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rock Tip:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Esta vez, tanto la sesión como el post comparten rock tip, que no podía ser otro que el &lt;a href="http://www.youtube.com/watch?v=4I9lT1Nv_bo"&gt;‘Speed of Light’&lt;/a&gt; de los speed-metaleros fineses &lt;a href="http://en.wikipedia.org/wiki/Stratovarius"&gt;Statovarius&lt;/a&gt;. Un tema clásico, con una formación clásica en la banda, antes de que al señor Timo Tolkki le diera por seguir las instrucciones que le dictaba una patata en llamas, a fingir un asalto y acuchillamiento en plena gira, o a hacer cambios ridículos en la formación de la banda con fines promocionales. &lt;/p&gt;  &lt;p&gt;¡Vamos a poner nuestros servidores SQL Server a la velocidad de la luz! Keep Rockin’! &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=152334" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Comunidad/default.aspx">Comunidad</category></item><item><title>Modern Day Cowboy: SOSEX para WinDbg</title><link>http://geeks.ms/blogs/palvarez/archive/2009/06/23/modern-day-cowboy-sosex-para-windbg.aspx</link><pubDate>Tue, 23 Jun 2009 17:33:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:151077</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=151077</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/06/23/modern-day-cowboy-sosex-para-windbg.aspx#comments</comments><description>&lt;p&gt;Quiero pediros un favor. Quiero que digáis todos en alto &amp;quot;Gracias, Steve! Tu molas!”. Y quiero que lo digáis mirando hacia el oeste. Y quiero que lo digáis alto. Y quiero que lo digáis en inglés (dejo la traducción como ejercicio al lector XD).&lt;/p&gt;  &lt;p&gt;No se si Steve Johnson podrá oírnos, pero desde luego se merece nuestro reconocimiento y agradecimiento, pues es el autor de una de las extensiones de WinDbg más espectaculares que he probado nunca, y de la que hoy os quiero hablar: las SOSEX 2.0&lt;/p&gt;  &lt;p&gt;Pero antes, vamos a hablar un poquito de las extensiones en WinDbg…&lt;/p&gt;  &lt;h4&gt;El Depurador Extensible&lt;/h4&gt;  &lt;p&gt;Las extensiones de WinDbg son una de sus características estrella, y lo que le convierten en un depurador tan especial. Estas extensiones son DLLs que exportan funciones que agregan ciertas capacidades al depurador a través de los &lt;em&gt;comandos de extensión&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Si habéis seguido alguna de mis entradas anteriores sobre depuración de código administrado con WinDbg, ya habréis empleado comandos de extensión, ya que la archiconocida SOS.dll es una extensión de WinDbg, y comandos como &lt;strong&gt;!dumpheap&lt;/strong&gt;, &lt;strong&gt;!printexception &lt;/strong&gt;o &lt;strong&gt;!eeheap &lt;/strong&gt;son comandos de extensión exportados por la SOS.dll. Todos los comandos que empiezan con el carácter&lt;strong&gt; !&lt;/strong&gt; (bang, en inglés), son comandos de extensión.&lt;/p&gt;  &lt;p&gt;Podemos consultar todas las extensiones cargadas en WinDbg, y su orden, a través del comando &lt;strong&gt;.chain&lt;/strong&gt;. Un ejemplo de salida de &lt;strong&gt;.chain&lt;/strong&gt; en mi WinDbg:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font size="2" face="Courier New"&gt;0:001&amp;gt; &lt;strong&gt;&lt;font color="#ff0000"&gt;.chain&lt;/font&gt;&lt;/strong&gt;         &lt;br /&gt;Extension DLL search Path:         &lt;br /&gt;        &lt;br /&gt;Extension DLL chain:         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;&lt;font color="#ff0000"&gt;dbghelp&lt;/font&gt;&lt;/strong&gt;: image 6.11.0001.404, API 6.1.6, built Thu Feb 26 03:10:27 2009         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [path: C:\Program Files\Debugging Tools for Windows (x64)\dbghelp.dll]         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;&lt;font color="#ff0000"&gt;ext&lt;/font&gt;&lt;/strong&gt;: image 6.11.0001.404, API 1.0.0, built Thu Feb 26 03:10:26 2009         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [path: C:\Program Files\Debugging Tools for Windows (x64)\winext\ext.dll]         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;&lt;font color="#ff0000"&gt;exts&lt;/font&gt;&lt;/strong&gt;: image 6.11.0001.404, API 1.0.0, built Thu Feb 26 03:10:17 2009         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [path: C:\Program Files\Debugging Tools for Windows (x64)\WINXP\exts.dll]         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;&lt;font color="#ff0000"&gt;uext&lt;/font&gt;&lt;/strong&gt;: image 6.11.0001.404, API 1.0.0, built Thu Feb 26 03:10:20 2009         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [path: C:\Program Files\Debugging Tools for Windows (x64)\winext\uext.dll]         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;&lt;font color="#ff0000"&gt;ntsdexts&lt;/font&gt;&lt;/strong&gt;: image 6.1.7015.0, API 1.0.0, built Thu Feb 26 03:09:22 2009         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [path: C:\Program Files\Debugging Tools for Windows (x64)\WINXP\ntsdexts.dll]&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Como se puede ver, tengo cargadas las extensiones &lt;strong&gt;dgbhelp&lt;/strong&gt;, &lt;strong&gt;ext&lt;/strong&gt;, &lt;strong&gt;exts&lt;/strong&gt;, &lt;strong&gt;uext&lt;/strong&gt; y &lt;strong&gt;ntsdexts&lt;/strong&gt;, que son las extensiones que WinDBG carga por defecto, y gracias a las cuales tenemos comandos de extensión como &lt;strong&gt;!analyze&lt;/strong&gt; y &lt;strong&gt;!locks&lt;/strong&gt; en cualquier despliegue por defecto de WinDbg.&lt;/p&gt;  &lt;p&gt;Ahora que hemos hecho un pequeño repaso a las extensiones y los comandos de extensión, os podéis descargar las SOSEX v2.0 desde &lt;a href="http://www.stevestechspot.com/SOSEXV2NowAvailable.aspx"&gt;esta entrada&lt;/a&gt; en el blog de &lt;a href="http://www.stevestechspot.com/default.aspx"&gt;Steve&lt;/a&gt;, y copiar la DLL en vuestro directorio &lt;em&gt;winext&lt;/em&gt; dentro de las&lt;em&gt; Debugging Tools for Windows&lt;/em&gt;. A partir de ese momento, mediante el comando &lt;strong&gt;.load sosex &lt;/strong&gt;podréis cargar las extensiones y empezar a jugar.&lt;/p&gt;  &lt;h4&gt;SOSEX 2.0&lt;/h4&gt;  &lt;p&gt;&lt;em&gt;NOTA: Una vez cargadas las SOSEX, estas pasan a la primera posición del chain de extensiones, con lo que si invocamos al comando&lt;strong&gt; !help&lt;/strong&gt;, estaremos llamando realmente a&lt;strong&gt; !SOSEX.help&lt;/strong&gt;. A lo largo de toda la entrada me ahorrare el prefijar las llamadas a los comandos de extensión.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Mediante &lt;strong&gt;!help&lt;/strong&gt; vamos a obtener la lista de los comando expuestos por SOSEX. A continuación os detallo los que me resultan más interesantes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;!dlk:&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Este comando nos muestra los interbloqueos producidos entre dos o más &lt;em&gt;sync blocks&lt;/em&gt;, lo que en la practica supone mostrarnos los interbloqueos producidos en código administrado.&lt;/p&gt;    &lt;p&gt;Las viejas SOS nos permitían ver todos los objetos de sincronización a través de la extensión&lt;strong&gt; !syncblk&lt;/strong&gt;, pero la búsqueda de interbloqueos no era trivial, ya que nos obligaba a ver todos los &lt;em&gt;call stacks&lt;/em&gt; de los hilos involucrados.&lt;/p&gt;    &lt;p&gt;La salida de &lt;strong&gt;!dlk&lt;/strong&gt; nos muestra información mucho más directa y concisa:&lt;/p&gt;    &lt;p&gt;&lt;font size="2" face="Courier New"&gt;0:016&amp;gt; &lt;strong&gt;&lt;font color="#ff0000"&gt;!dlk &lt;/font&gt;&lt;/strong&gt;        &lt;br /&gt;Deadlock detected:         &lt;br /&gt;CLR thread 3 holds sync block 00000000024af3b8 OBJ:00000000105cfcb8[System.Object]         &lt;br /&gt;waits sync block 00000000024af1c0 OBJ:00000000105cfde8[System.Byte[]]         &lt;br /&gt;CLR thread 5 holds sync block 00000000024af1c0 OBJ:00000000105cfde8[System.Byte[]]         &lt;br /&gt;waits sync block 00000000024af3b8 OBJ:00000000105cfcb8[System.Object]         &lt;br /&gt;CLR Thread 3 is waiting at DemoThreading.Monitor.WriterFunc()+0x37(IL)         &lt;br /&gt;[&lt;strong&gt;&lt;font color="#ff0000"&gt;c:\demosDOT\DemoThreads\Monitor.cs, line 63&lt;/font&gt;&lt;/strong&gt;]         &lt;br /&gt;CLR Thread 5 is waiting at DemoThreading.Monitor.ReaderFunc()+0x15(IL)         &lt;br /&gt;[&lt;strong&gt;&lt;font color="#ff0000"&gt;c:\demosDOT\DemoThreads\Monitor.cs, line 42&lt;/font&gt;&lt;/strong&gt;]         &lt;br /&gt;1 deadlock detected. &lt;/font&gt;&lt;/p&gt;    &lt;p&gt;Si os fijáis, no solo nos detecta la situación de interbloqueos, sino que es capaz de decirnos el fichero y la línea de código que se estaba ejecutando en cada uno de los hilos involucrados. Esto es impagable.&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;!dumpgen: &lt;/strong&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;En mi día a día como especialista en depuración, una de las tareas a las que más tiempo dedico es a detectar fugas de memoria. No vamos a tratar en este artículo sobre las fugas de memoria administradas, pero me basta que sepáis con que es muy útil detectar los objetos que viven en una generación de memoria determinada. Mediante el comando&lt;strong&gt; !dumpgen&lt;/strong&gt;, SOSEX nos ayuda a estudiar los objetos almacenados en generación concreta. &lt;/p&gt;    &lt;p&gt;A modo de ejemplo, si quisiéramos monitorizar los objetos que viven en generación 2 podríamos ejecutar &lt;strong&gt;!dumpgen 2 –stat&lt;/strong&gt;. Podéis pensar en el como un &lt;strong&gt;!dumpheap&lt;/strong&gt; que, en lugar de inspeccionar todo el &lt;em&gt;managed heap&lt;/em&gt;, inspecciona solo un &lt;em&gt;heap&lt;/em&gt; particular.&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;!gcgen:&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Siguiendo en la línea del &lt;strong&gt;!dumpgen&lt;/strong&gt;, el&lt;strong&gt; !gcgen&lt;/strong&gt; de las SOSEX nos permite averiguar en que generación reside un objeto concreto. Por ejemplo:&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;0:000&amp;gt; &lt;strong&gt;&lt;font color="#ff0000"&gt;!gcgen&lt;/font&gt;&lt;/strong&gt; 00000422714a7dd1           &lt;br /&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;Gen 1&lt;/font&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/font&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;Esto es muy interesante en multitud de escenarios del &lt;em&gt;Mundo Real(tm)&lt;/em&gt;. Recientemente he estado empleando muy frecuentemente el comando &lt;strong&gt;!gcgen&lt;/strong&gt; en un &lt;strong&gt;.foreach&lt;/strong&gt; de un &lt;strong&gt;!dumpheap –mt&lt;/strong&gt; para que me vuelque la generación en la que viven todos los objetos de un determinado tipo, con el fin de poder evaluar que porcentaje de ellos viven en generación 2. Generalmente busco por conexiones a la base de datos, y si el valor es muy elevado, en gran parte de los escenarios se deberá a que se mantienen referencias a esos objetos que impiden su recolección a tiempo. Un ejemplo de este uso sería el siguiente:&lt;/p&gt;    &lt;p&gt;&lt;font size="2" face="Courier New"&gt;.foreach (obj {!dumpheap –mt &amp;lt;&lt;em&gt;MT del Objeto&lt;/em&gt;&amp;gt; -short}) {!gcgen ${obj}}&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;!refs:&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;&lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;El comando de extensión &lt;strong&gt;!refs &lt;/strong&gt;nos muestra una lista con todos los objetos que están referenciando a un objeto determinado, así como otra lista con todos los objetos que son referenciados por este.&lt;/p&gt;    &lt;p&gt;Pensad un poco en ello… es un comando &lt;strong&gt;salvaje&lt;/strong&gt; para averiguar porque un objeto determinado no se va de memoria, quien mantiene referencias sobre el. Es una autentica joya a la hora de buscar fugas de memoria administrada.&lt;/p&gt;    &lt;p&gt;A continuación os pongo un ejemplo que he sacado del blog de John Robbins:&lt;/p&gt;    &lt;p&gt;&lt;font size="2" face="Courier New"&gt;0:004&amp;gt; &lt;strong&gt;&lt;font color="#ff0000"&gt;!refs&lt;/font&gt;&lt;/strong&gt; 0000000002696918         &lt;br /&gt;Objects referenced by 0000000002696918 (System.Diagnostics.DefaultTraceListener):         &lt;br /&gt;00000000026941c0&amp;#160;&amp;#160;&amp;#160;&amp;#160; 40&amp;#160;&amp;#160;&amp;#160; System.String&amp;#160;&amp;#160;&amp;#160; STRVAL=Default         &lt;br /&gt;0000000002696b78&amp;#160;&amp;#160;&amp;#160;&amp;#160; 24&amp;#160;&amp;#160;&amp;#160; System.Collections.Specialized.StringDictionary         &lt;br /&gt;00000642787c78c8&amp;#160;&amp;#160;&amp;#160;&amp;#160; 26&amp;#160;&amp;#160;&amp;#160; System.String         &lt;br /&gt;Objects referencing 0000000002696918 (System.Diagnostics.DefaultTraceListener):         &lt;br /&gt;00000000026941e8&amp;#160;&amp;#160;&amp;#160;&amp;#160; 160&amp;#160;&amp;#160;&amp;#160; System.Diagnostics.ListenerElement         &lt;br /&gt;0000000002695468&amp;#160;&amp;#160;&amp;#160;&amp;#160; 24&amp;#160;&amp;#160;&amp;#160; System.Object         &lt;br /&gt;0000000002697150&amp;#160;&amp;#160;&amp;#160;&amp;#160; 48&amp;#160;&amp;#160;&amp;#160; System.Collections.ArrayList+ArrayListEnumeratorSimple         &lt;br /&gt;Thread 4         &lt;br /&gt;stack:000000001c1be7c8         &lt;br /&gt;stack:000000001c1be880         &lt;br /&gt;stack:000000001c1be8b0         &lt;br /&gt;stack:000000001c1be8e0         &lt;br /&gt;stack:000000001c1be8f0         &lt;br /&gt;stack:000000001c1be920         &lt;br /&gt;stack:000000001c1be930&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;¡Espectacular!&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;!mdt:&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Dejo para el final el que seguramente sea mi comando favorito de las SOSEX. &lt;strong&gt;!mdt&lt;/strong&gt; es la versión administrada del mítico comando &lt;strong&gt;dt&lt;/strong&gt; de los escenarios de depuración nativa de &lt;em&gt;WinDbg&lt;/em&gt;. Sirve para inspeccionar cómodamente un objeto, de modo que podríamos verlo como un sustituto para el venerable &lt;strong&gt;!dumpobject&lt;/strong&gt; de las SOS.dll. Una de mis características favoritas es su parámetro &lt;em&gt;–r&lt;/em&gt;, que permite explorar los objetos que componen el objeto de estudio de modo recursivo. &lt;/p&gt;    &lt;p&gt;A continuación os pongo un ejemplo de&lt;strong&gt; !mdt&lt;/strong&gt; sobre un objeto de tipo &lt;em&gt;Oracle.DataAccess.Client.ConnectionPool&lt;/em&gt;:&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font size="2" face="Courier New"&gt;0:044&amp;gt; &lt;strong&gt;&lt;font color="#ff0000"&gt;!mdt&lt;/font&gt;&lt;/strong&gt; 000000007fffe9d8 &lt;strong&gt;&lt;font color="#ff0000"&gt;-r&lt;/font&gt;&lt;/strong&gt;         &lt;br /&gt;000000007fffe9d8 (Oracle.DataAccess.Client.ConnectionPool)         &lt;br /&gt;&amp;#160;&amp;#160; m_connections:000000007fffeae0 (System.Collections.Stack+SyncStack)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _array:000000007fffeb18 (System.Object[], Elements: 10)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _size:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _version:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _syncRoot:NULL (System.Object)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _s:000000007fffea48 (System.Collections.Stack)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _array:000000007fffea70 (System.Object[], Elements: 10)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _size:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _version:0x8 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _syncRoot:000000007fffeb88 (System.Object)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;NO FIELDS&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _root:000000007fffeb88 (System.Object)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;NO FIELDS&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160; m_mtsConnections:000000007fffebe0 (System.EnterpriseServices.ResourcePool)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _cb:000000007fffeba0 (System.EnterpriseServices.ResourcePool+TransactionEndDelegate)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _target:000000007fffe9d8 (Oracle.DataAccess.Client.ConnectionPool)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;RECURSIVE&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _methodBase:NULL (System.Reflection.MethodBase)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _methodPtr:00000642800fda60 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _methodPtrAux:0000000000000000 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _invocationList:NULL (System.Object)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _invocationCount:0000000000000000 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;NO FIELDS&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160; m_semAvaNumOfCons:0000000000000000 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160; m_timer:000000007ffff008 (System.Threading.Timer)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; __identity:NULL (System.Object)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; timerBase:000000007ffff028 (System.Threading.TimerBase)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; timerHandle:0000000005d40e10 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; delegateInfo:0000000006bc0b90 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; timerDeleted:0x1 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; m_lock:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160; m_clonedCtx:000000007fffee98 (Oracle.DataAccess.Client.OpoConCtx)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; opsConCtx:0000000000000000 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; opsErrCtx:0000000000000000 (System.IntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; pOpoConValCtx:0000000000000000 (System.UIntPtr)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; opoConRefCtx:000000007fffef50 (Oracle.DataAccess.Client.OpoConRefCtx)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; serverVersion:000000007fffe880 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; userID:000000007fffe8b0 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; password:000000007fffe8e0 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; dataSource:000000007fffe910 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; newPassword:00000000dfff0370 (System.String: &amp;quot;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; proxyUserId:00000000dfff0370 (System.String: &amp;quot;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; proxyPassword:00000000dfff0370 (System.String: &amp;quot;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; dbName:000000007fffe938 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; hostName:000000007fffe960 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; instanceName:000000007fffe988 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; serviceName:000000007fffe9b0 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; clientID:NULL (System.String)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; pITransaction:NULL (System.EnterpriseServices.ITransaction)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; conString:000000007fffd350 (System.String: &amp;quot;&amp;lt;censurado ;)&amp;gt;&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; pool:NULL (Oracle.DataAccess.Client.ConnectionPool)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; maxPoolSize:0x64 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; minPoolSize:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; poolIncSize:0x5 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; poolDecSize:0x1 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; poolRegulator:0xB4 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; creationTime:000000007fffef28 (System.DateTime) 2009/06/23 18:53:51.511 VALTYPE (MT=0000064278476ad8, ADDR=000000007fffef28)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; lifeTime:000000007fffef30 (System.TimeSpan) VALTYPE (MT=00000642784769d8, ADDR=000000007fffef30)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _ticks:0x0 (System.Int64)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; timeOut:000000007fffef38 (System.TimeSpan) VALTYPE (MT=00000642784769d8, ADDR=000000007fffef38)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _ticks:0x0 (System.Int64)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; pooledConCtx:NULL (Oracle.DataAccess.Client.PooledConCtx)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; poolName:NULL (System.String)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; bErrorOnOpen:false (System.Boolean)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; validateCon:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; gridCR:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; gridRLB:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; dataSrc:NULL (System.String)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; metaPool:0x1 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; origLifeTime:000000007fffef40 (System.TimeSpan) VALTYPE (MT=00000642784769d8, ADDR=000000007fffef40)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _ticks:0x0 (System.Int64)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; origPoolDecSize:0x1 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; origMinPoolSize:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; exceptMsg:NULL (System.String)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; m_conPooler:NULL (Oracle.DataAccess.Client.ConPooler)         &lt;br /&gt;&amp;#160;&amp;#160; m_counter:000000007ffff108 (Oracle.DataAccess.Client.Counter)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; total:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; potentialTotal:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; threadWait:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; totalAvailable:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; bOwnedByCPCtx:false (System.Boolean)         &lt;br /&gt;&amp;#160;&amp;#160; m_skipDecrement:false (System.Boolean)         &lt;br /&gt;&amp;#160;&amp;#160; m_cpCtx:NULL (Oracle.DataAccess.Client.CPCtx)         &lt;br /&gt;&amp;#160;&amp;#160; m_rlbGravCounter:0x0 (System.Int32)         &lt;br /&gt;&amp;#160;&amp;#160; m_attemptedRequests:0.000000 (System.Single)         &lt;br /&gt;&amp;#160;&amp;#160; m_bSynchronizeStack:false (System.Boolean)&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;No se como lo veis vosotros, pero a mi esto me encanta. Normalmente “pierdo” mucho tiempo explorando los objetos con una sucesión casi interminable de&lt;strong&gt; !dumpobject&lt;/strong&gt;, y este pequeño comando me ahorra muchísimo tiempo.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Hay más comandos de extensión interesantes en las SOSEX, como los relacionados con los &lt;em&gt;breakpoints&lt;/em&gt; en código administrado, la búsqueda de cadenas en el volcado o la inspección de ensamblados, pero los más interesantes y prácticos para mi, hasta el momento, han sido estos que os he descrito. Espero que los disfrutéis y que esta entrada os sirva para ahorrar tiempo y pasarlo aun mejor en vuestras sesiones de depuración.&lt;/p&gt;  &lt;h4&gt;En resumen…&lt;/h4&gt;  &lt;p&gt;Esta librería ha pasado a formar parte de mi kit de depuración hasta el punto que, en el 95% de los casos, al abrir un volcado de memoria en el WinDbg sigo la misma rutina:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;.reload /v /f &lt;/li&gt;    &lt;li&gt;.loadby sos mscorwks &lt;/li&gt;    &lt;li&gt;.load sosex &lt;/li&gt;    &lt;li&gt;&lt;em&gt;¡Empezamos a depurar!&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;No podía dejar pasar la oportunidad de recomendaros su uso, y a la vez, aprovechar el artículo para hablar de la extensiones de &lt;em&gt;WinDbg&lt;/em&gt;. ¡Espero que lo hayáis disfrutado!&lt;/p&gt;  &lt;p&gt;&lt;em&gt;PS: Thanks Steve! I owe you a beer… or a full six-pack!:)&lt;/em&gt;&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;Hoy os traigo una buena noticia; vamos a tener la suerte de recibir a los californianos &lt;a href="http://en.wikipedia.org/wiki/Tesla_(band)"&gt;Tesla&lt;/a&gt; en nuestras tierras, ya que este Martes 23 actuarán en Barcelona, y el Miércoles 24 en Madrid, en la sala Heineken. Allí espero estar mañana a la noche, disfrutando de temazos como &lt;a href="http://www.youtube.com/watch?v=H2FvewiWGTY&amp;amp;feature=channel"&gt;Paradise&lt;/a&gt;, &lt;a href="http://www.youtube.com/watch?v=k9gUJvsfL0E&amp;amp;feature=channel"&gt;Stir It Up&lt;/a&gt;, &lt;a href="http://www.youtube.com/watch?v=-a9DW_zhV84"&gt;Modern Day Cowboy&lt;/a&gt;…&lt;/p&gt;  &lt;p&gt;Precisamente este último tema me pareció apropiado como Rock Tip para éste artículo; no lo puedo evitar, cuando abro el WinDbg e inicio una sesión de depuración, me veo a mi mismo en un camino polvoriento y pedregoso, embarrado desde las botas camperas hasta el sombrero de cowboy, con la seis cuerdas a la espalda, y mis armas listas para la acción. ¿Flipado? Si… pero ¿y lo bien que me lo paso? :) &lt;/p&gt;  &lt;p&gt;En este caso mis armas son mis herramientas, y las SOSEX son una de las últimas adiciones a mi arsenal de depuración. Pensar en las SOSEX como arma me dio la idea de emplear el &lt;a href="http://www.youtube.com/watch?v=0gnJ-fQ1uwA&amp;amp;feature=related"&gt;‘Stick to Your Guns’&lt;/a&gt; de &lt;a href="http://es.wikipedia.org/wiki/Bon_Jovi"&gt;Bon Jovi&lt;/a&gt; para este post, pero luego recordé que &lt;a href="http://en.wikipedia.org/wiki/Tesla_(band)"&gt;Tesla&lt;/a&gt; tocan esta semana en España y que aun no habían aparecido en ningún Rock Tip de este, vuestro blog :)&lt;/p&gt;  &lt;p&gt;Por cierto, si alguno de vosotros va a ver a los chicos de &lt;a href="http://en.wikipedia.org/wiki/Jeff_Keith"&gt;Jeff Keith&lt;/a&gt; este Miércoles en Madrid avisadme, y ya puestos os podéis estirar y invitar a una cervecilla ¿no? :)&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Keep Rockin’!&lt;/em&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=151077" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/WinDbg/default.aspx">WinDbg</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/DOT/default.aspx">DOT</category></item><item><title>Another Day: Sesión de Depuración y Optimización en Barcelona</title><link>http://geeks.ms/blogs/palvarez/archive/2009/06/08/another-day-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-barcelona.aspx</link><pubDate>Mon, 08 Jun 2009 07:18:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:150126</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=150126</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/06/08/another-day-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-barcelona.aspx#comments</comments><description>&lt;p&gt;… y seguimos con la pequeña gira sobre Depuración y Optimización que estamos realizando este año los integrantes del DOT Team de Plain Concepts. Después de &lt;a href="http://geeks.ms/blogs/palvarez/archive/2008/10/04/back-to-the-bullet-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n.aspx"&gt;Santander&lt;/a&gt;, &lt;a href="http://geeks.ms/blogs/palvarez/archive/2009/03/30/enemy-in-me-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-bilbao.aspx"&gt;Bilbao&lt;/a&gt;, &lt;a href="http://geeks.ms/blogs/palvarez/archive/2009/04/14/calling-on-you-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-a-coru-241-a.aspx"&gt;A Coruña&lt;/a&gt; y Madrid, le llega el turno a la Ciudad Condal, donde tendré el placer de presentar una sesión sobre Depuración y Optimización Avanzada de aplicaciones con WinDbg.&lt;/p&gt;  &lt;p&gt;El evento se realizará el próximo día 17 de Junio en las oficinas de Microsoft en Barcelona, en horario de 16:00 a 18:00. Lo cierto es que, si fuera por mi, estaríamos hablando una semana entera sobre el asunto; los que ya me conocéis sabéis la gran razón que tiene esa señora madre mía cuando dice que yo no callo ni debajo del agua. Aun así, intentaremos aprovechar al máximo esas dos horitas. Los interesados podéis apuntaros en este enlace: &lt;a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032417766&amp;amp;Culture=es-ES"&gt;http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032417766&amp;amp;Culture=es-ES&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Como siempre, ¡se aceptan invitaciones a cervecitas! XDD ¡Nos vemos en Barcelona!&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;Otro día más presentando mis juguetes favoritos de depuración, otro día más de charlita de internals de .NET y de Windows. Por eso me pareció muy interesante como Rock Tip para esta entrada el &lt;a href="http://www.youtube.com/watch?v=ugcbya8Z24s"&gt;‘Another Day’&lt;/a&gt;, uno de los temas mas conocidos de los increíbles &lt;a href="http://es.wikipedia.org/wiki/Dream_Theater"&gt;Dream Theater&lt;/a&gt;. Esta banda americana de metal progresivo combinan de un modo espectacular el virtuosismo de sus músicos (todos ellos salidos del Berklee College of Music!) con una musicalidad poco común en este género.&amp;#160; &lt;/p&gt;  &lt;p&gt;Este tema en cuestión apareció en el espectacular &lt;a href="http://en.wikipedia.org/wiki/Images_And_Words"&gt;Images And Words&lt;/a&gt;, de 1992. Un disco muy, pero que muy recomendable para todos los amantes de la buena música y del virtuosismo. Por otra parte estamos de enhorabuena, ya que los chicos de Dream Theater acaban de publicar su último trabajo, el &lt;i&gt;Black Clouds &amp;amp; Silver Linings&lt;/i&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=150126" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/WinDbg/default.aspx">WinDbg</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Comunidad/default.aspx">Comunidad</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/DOT/default.aspx">DOT</category></item><item><title>Gimme Three Steps: Creando nuestro Servidor de Símbolos</title><link>http://geeks.ms/blogs/palvarez/archive/2009/04/15/gimme-three-steps-creando-nuestro-servidor-de-s-237-mbolos.aspx</link><pubDate>Wed, 15 Apr 2009 08:05:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:146759</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=146759</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/04/15/gimme-three-steps-creando-nuestro-servidor-de-s-237-mbolos.aspx#comments</comments><description>&lt;p&gt;Hace unos días, conversando con &lt;a href="http://geeks.ms/blogs/rcorral/"&gt;Rodri&lt;/a&gt; y con &lt;a href="http://geeks.ms/blogs/jlsoria/"&gt;Jose Luis&lt;/a&gt;, surgió la necesidad de crear un documento interno de &lt;a&gt;Plain Concepts&lt;/a&gt; acerca de la utilización de &lt;strong&gt;symstore&lt;/strong&gt; para la creación de un servidor de símbolos a nivel de empresa. Al momento nos dimos cuenta de que esto podía interesar a mas &lt;em&gt;geeks&lt;/em&gt; como nosotros, así que he decidido crear una guía muy breve para la creación de un servidor de símbolos básico. &lt;/p&gt;  &lt;p&gt;¡Espero que os resulte interesante!&lt;/p&gt;  &lt;h4&gt;¿Un Servidor de Símbolos? ¿Para que quiero yo eso?&lt;/h4&gt;  &lt;p&gt;&lt;em&gt;NOTA: En esta entrada no voy a explicar que son los símbolos, ni para que nos sirven, etc. Todo eso está explicado en múltiples artículos de la MSDN, en la documentación de los depuradores correspondientes y entradas de blog tan magníficas como &lt;/em&gt;&lt;a href="http://geeks.ms/blogs/palvarez/archive/2007/12/25/everything-el-resource-governor-en-sql-server-2008.aspx"&gt;&lt;em&gt;esta&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. Y no es por que sea mía :)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Como ya sabréis los que me conocéis personalmente, para mi una sesión de depuración post-mortem es como la quema de iglesias para los blackmetaleros nórdicos; una fuente de diversión inagotable. Sin embargo siempre hay momentos frustrantes, y casi todos ellos tienen que ver con la carencia de símbolos apropiados, o el echo de que WinDbg no puede localizarlos adecuadamente.&lt;/p&gt;  &lt;p&gt;Para facilitar la vida a nuestros depuradores y herramientas varias que necesiten acceder a esta información simbólica de depuración vamos a construir un servidor de símbolos donde se almacenaran tanto los símbolos de nuestras aplicaciones como los que nos descarguemos de otros servidores, como el servidor de símbolos públicos de Microsoft (&lt;a href="http://msdl.microsoft.com/download/symbols"&gt;http://msdl.microsoft.com/download/symbols&lt;/a&gt;). &lt;/p&gt;  &lt;h4&gt;Construyendo nuestro Servidor de Símbolos&lt;/h4&gt;  &lt;p&gt;Vamos a necesitar de tres simples pasos para construir el servidor de símbolos:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Obtener un lugar físico donde almacenar los símbolos:&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Esta parte es la mas sencilla. Necesitamos un lugar donde almacenar los ficheros .pdb, para lo que crearemos un directorio en algún servidor accesible a nivel de nuestra organización y compartiremos esta carpeta. Así de simple :)&lt;/p&gt;    &lt;p&gt;En el resto del articulo supondremos que hemos creado un share llamado &lt;strong&gt;Symbols&lt;/strong&gt; en el servidor &lt;strong&gt;DevSrv01&lt;/strong&gt;. Por tanto, el servidor de símbolos se encontrará en &lt;a&gt;\\DevSer01\Symbols&lt;/a&gt;.&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Configurar las herramientas para que utilicen ese lugar como servidor de símbolos:&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Ahora debemos instruir a nuestra aplicación de que busque los símbolos en nuestro servidor concreto. En el caso de WinDbg podemos recurrir directamente a la configuración de la ruta de búsqueda de símbolos desde &lt;strong&gt;File –&amp;gt; Symbol File Path…&lt;/strong&gt; o &lt;strong&gt;Ctrl+S&lt;/strong&gt;. Desde ahí podemos establecer la ruta, que en nuestro ejemplo bien podría ser “SRV*\\DevSrv01\Symbols*http://msdl.microsoft.com/download/symbols”, indicando que el servidor de símbolos estará en nuestro servidor, y que también buscará en el servidor público de símbolos de Microsoft. &lt;/p&gt;    &lt;p&gt;&lt;em&gt;NOTA: Para mas información respecto a las cadenas de búsqueda de símbolos, recomiendo mirar la documentación de las Debugging Tools For Windows.&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_07B85F26.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/palvarez/image_5F00_thumb_5F00_0AA9AFDA.png" width="575" height="212" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;A medida que vayamos recargando símbolos (por ejemplo, mediante .reload en WinDbg), buscara la presencia de la versión correcta de los mismos en el servidor de símbolos (&lt;a&gt;\\DevSrv01\Symbols&lt;/a&gt;) y, caso de no encontrarlos, iria al siguiente elemento en la cadena de búsqueda y los descargaría, &lt;strong&gt;copiandolos&lt;/strong&gt; en el servidor &lt;a&gt;\\DevSrv01\Symbols&lt;/a&gt;; de este modo, la segunda vez que fuera necesario cargar los símbolos, estos ya se encontrarían en nuestro nuevo y flamante servidor.&lt;/p&gt;    &lt;p&gt;Una alternativa más práctica es emplear la variable de entorno &lt;em&gt;_NT_SYMBOL_PATH, &lt;/em&gt;estableciéndola&lt;em&gt; &lt;/em&gt;a nuestra cadena de búsqueda de símbolos. Prácticamente todas las aplicaciones que hace uso de los símbolos intentan buscar primero en esa variable de entorno, como es el caso de &lt;em&gt;WinDbg&lt;/em&gt;, &lt;em&gt;adplus&lt;/em&gt;, etc… Sin embargo, hay una notable excepción: el &lt;strong&gt;Process Explorer &lt;/strong&gt;de SysInternals. Como seguramente sabréis, ésta magnifica herramienta también puede emplear los símbolos para generar volcados de memoria, ver la información de los call stacks de los diferentes threads de un proceso en ejecución, etc. En esta herramienta tendremos que establecer el servidor de símbolos manualmente, ya que no lee de _NT_SYMBOL_PATH. ¡Avisados estais! :)&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Poblar el servidor de símbolos con cada nueva build:&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;Como ya sabréis, el mayor problema de los servidores de símbolos es mantener el orden dentro del caos que suponer tener múltiples versiones de un mismo módulo. Con cada nueva compilación, las direcciones de memoria de los distintos objetos pueden cambiar, asi como los &lt;em&gt;offset&lt;/em&gt;, etc. Si intentamos depurar un proceso o un volcado de memoria con una versión incorrecta de los módulos los resultados pueden ser imprevisibles.&lt;/p&gt;    &lt;p&gt;Os voy a comentar un ejemplo típico de depuración con símbolos incorrectos que seguro que os suena a más de uno: ¿alguna vez habéis realizado una depuración paso a paso con un depurador integrado en el entorno de desarrollo, y habéis comprobado que, en cierto momento, la línea que estáis ejecutando apunta a una línea inexistente o en blanco? Eso generalmente se debe a la utilización de unos .PDBs antiguos. Por ejemplo, se han agregado unas cuantas líneas de código a un método, pero al depurar empleamos la información de cuando ese método ocupaba menos, etc. Ala.. ¡un nuevo misterio resuelto! xD&lt;/p&gt;    &lt;p&gt;Para evitar estos problemas, lo mejor es asegurarnos de que, cada vez que realizamos una nueva compilación, copiamos los nuevos .PDB al servidor de símbolos. La idea es buena, pero ahora tenemos que ver como la implementamos; daros cuenta que no puedo copiar directamente el fichero .pdb porque habría colisión de nombres. Si tengo un ensamblado llamado &lt;em&gt;miEnsamblado.exe&lt;/em&gt;, y lo compilo cinco veces, tendré cinco ficheros miEnsamblado.pdb. Hay que buscar un mecanismo que permita almacenarlos sin que se sobrescriban, y haciendo posible que una herramienta que consuma los símbolos pueda coger el adecuado para una versión concreta.&lt;/p&gt;    &lt;p&gt;Esto se consigue a través de una estructura de directorios especial en el servidor, basada en un hash del modulo, que no vamos a explicar en detalle en esta entrada. Lo que si os diré es que, gracias a una pequeña utilidad llamada &lt;strong&gt;symstore&lt;/strong&gt;, que se distribuye con las propias &lt;em&gt;Debugging Tools for Windows&lt;/em&gt;, podemos agregar nuevos .PDBs a nuestro servidor y automática se colocarán correctamente.&lt;/p&gt;    &lt;p&gt;Un ejemplo de uso de &lt;strong&gt;symstore&lt;/strong&gt; sería el siguiente:&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;symstore add /r /f c:\sources\aplicacion\bins\*.* /s &lt;a&gt;\\DevSrv01\Symbols&lt;/a&gt; /t &amp;quot;Aplicacion 1&amp;quot; /v &amp;quot;Build 123&amp;quot;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;En ese ejemplo agregamos al servidor todos los símbolos que se encuentran en la ruta definida, especificando el nombre de producto (/t) y la versión (/v). Para ver todos los parámetros, nuevamente recomiendo recurrir a la documentación de las &lt;em&gt;Debugging Tools for Windows&lt;/em&gt;.&lt;/p&gt;    &lt;p&gt;Ahora solo necesitamos automatizar el proceso después de la build, ya sea mediante una acción post-build, msbuild, o vuestro mecanismo favorito :)&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;Resumen&lt;/h4&gt;  &lt;p&gt;En este articulo no hemos entrado en profundidad en ninguno de los puntos; no hemos explicado que son los símbolos y para que valen, ni la sintaxis de la ruta de búsqueda de símbolos, ni como se genera el &lt;em&gt;hash&lt;/em&gt; de cada versión de los símbolos y como éste se emplea para estructurarlos en el sistema de ficheros, etc. No, ese no era el objetivo de esta entrada del blog. El objetivo era, única y exclusivamente, contaros que se puede hacer y daros unas indicaciones básicas de cómo lograrlo; abriros un poco el apetito y de paso, publicar algo de lo que estamos haciendo internamente en Plain Concepts.&lt;/p&gt;  &lt;p&gt;¡Espero que os haya sido de utilidad! Keep Rockin’!&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;Allá por 1973 &lt;a href="http://en.wikipedia.org/wiki/Lynyrd_Skynyrd"&gt;Lynyrd Skynyrd&lt;/a&gt; publicaron su primer disco, su gran debut, “&lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/Pronounced_Leh-Nerd_Skin-Nerd"&gt;pronounced &amp;#39;lĕh-&amp;#39;nérd &amp;#39;skin-&amp;#39;nérd&lt;/a&gt;&lt;/em&gt;”; este disco incluía temazos como el &lt;a href="http://www.youtube.com/watch?v=sHQ_aTjXObs"&gt;Simple Man&lt;/a&gt; (para mi una de las mejores canciones de toda la historia… así de &lt;em&gt;simple &lt;/em&gt;;)) y el &lt;a href="http://www.youtube.com/watch?v=Y2YICwlDVfg"&gt;Free Bird&lt;/a&gt;, recientemente revitalizado gracias al Guitar Hero.&lt;/p&gt;  &lt;p&gt;En aquel álbum aparecía también el tema que protagoniza el rock tip de este articulo; &lt;a href="http://www.youtube.com/watch?v=SM3jgkChV6M"&gt;Gimme Three Steps&lt;/a&gt;. En realidad, la historia que cuenta esta canción no tiene mucho que ver con este artículo; esos tres pasos de los que habla la canción son los que le pide una chica a su captor para escapar corriendo de él. La letra es muy buena, espectacular, pero yo hago una reinterpretación y me quedo con los tres simples pasos que necesitamos para montar nuestro servidor de símbolos mediante &lt;strong&gt;symstore&lt;/strong&gt;. &lt;/p&gt;  &lt;p&gt;Bueno chicos, este fue el rock tip de hoy… ya veis que tengo el día sureño! :)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=146759" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/WinDbg/default.aspx">WinDbg</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/DOT/default.aspx">DOT</category></item><item><title>Calling On You: Sesión de Depuración y Optimización en A Coruña</title><link>http://geeks.ms/blogs/palvarez/archive/2009/04/14/calling-on-you-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-a-coru-241-a.aspx</link><pubDate>Tue, 14 Apr 2009 15:47:11 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:146737</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=146737</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/04/14/calling-on-you-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-a-coru-241-a.aspx#comments</comments><description>&lt;p&gt;Después de pasar &lt;a href="http://geeks.ms/blogs/palvarez/archive/2009/03/30/enemy-in-me-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-bilbao.aspx"&gt;una tarde genial en Bilbao&lt;/a&gt; con los chicos de &lt;a href="http://www.artalde.net/"&gt;Artalde.NET&lt;/a&gt; hablando sobre depuración avanzada con WinDbg, ahora le toca el turno a otra ciudad norteña; el grupo de usuarios de A Coruña (.NUGG) ha tenido a bien invitarme a hablar durante un par de horillas sobre uno de mis temas favoritos: la depuración y optimización de aplicaciones usando WinDbg y algún que otro juguetito :) El evento será el próximo Viernes 24 en la Facultad de Informática de A Crouña.&lt;/p&gt;  &lt;p&gt;Aquí podéis acceder a la pagina de inscripción al evento y consultar los detalles del mismo: &lt;a title="https://msevents.microsoft.com/cui/eventdetail.aspx?eventid=1032412774&amp;amp;culture=es-es" href="https://msevents.microsoft.com/cui/eventdetail.aspx?eventid=1032412774&amp;amp;culture=es-es"&gt;https://msevents.microsoft.com/cui/eventdetail.aspx?eventid=1032412774&amp;amp;culture=es-es&lt;/a&gt; y ya sabéis, si estáis por cerca de la Coruña y os apetece dedicar un par de horas a descubrir herramientas y técnicas de depuración avanzada y charlar un poquillo sobre internals de .NET, no dejéis de pasaros por el evento. &lt;/p&gt;  &lt;p&gt;Y ya aprovechando el post, tengo que confesaros una cosa: cuando me plantee la idea de recorrer diferentes grupos de usuarios de .NET para hablar principalmente de WinDbg pensé que, o bien directamente la idea fuera descartada por los grupos, o bien no tendríamos afluencia de gente. Y una vez más, como viene siendo habitual en mi para este tipo de previsiones, me equivoque de mala manera :) Hasta el momento me he encontrado con gran asistencia y, lo que es mejor aun, multitud de preguntas y comentarios, tanto síncronamente (en los propios eventos) como asíncronamente (por correo, blog, etc.). De verdad, ¡muchas gracias a todos por vuestra participación e interés!&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;No es la primera vez que los heavies cristianos &lt;a href="http://en.wikipedia.org/wiki/Stryper"&gt;Stryper&lt;/a&gt; hacen acto de presencia por aquí en este humilde blog, y seguramente no sea la última tampoco; ya sabéis como va esto… el blog es mío y traigo a quien me apetece xD En este caso, se trata del que, para mi, es uno de sus mejores temas: ‘&lt;a href="http://www.youtube.com/watch?v=UI8ylsHKIMg&amp;amp;feature=related"&gt;Calling on You&lt;/a&gt;’,&amp;#160; aparecido en su discazo ‘&lt;a href="http://en.wikipedia.org/wiki/To_Hell_with_the_Devil"&gt;To Hell With the Devil&lt;/a&gt;’ de 1986. Si no los conocéis, pegadles un orejazo. Encontrareis muy buenas melodías, técnica a patadas en todos los instrumentos y, sobre todo, una voz principal y unos coros que no os dejaran indiferentes. &lt;/p&gt;  &lt;p&gt;Me pareció un rock tip apropiado para este post, ya que es un pequeño llamamiento para que vengáis a acompañarnos en el evento. Sea como sea, el Viernes 24 volverá a sonar el Calling on You en A Coruña :)&lt;/p&gt;  &lt;p&gt;Keep Rockin’!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=146737" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/WinDbg/default.aspx">WinDbg</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Comunidad/default.aspx">Comunidad</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/DOT/default.aspx">DOT</category></item><item><title>Enemy In Me: Sesión de Depuración y Optimización en Bilbao</title><link>http://geeks.ms/blogs/palvarez/archive/2009/03/30/enemy-in-me-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-bilbao.aspx</link><pubDate>Mon, 30 Mar 2009 18:45:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:145938</guid><dc:creator>Pablo Alvarez</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/palvarez/rsscomments.aspx?PostID=145938</wfw:commentRss><comments>http://geeks.ms/blogs/palvarez/archive/2009/03/30/enemy-in-me-sesi-243-n-de-depuraci-243-n-y-optimizaci-243-n-en-bilbao.aspx#comments</comments><description>&lt;p&gt;Como ya &lt;a href="http://geeks.ms/blogs/ilanda/archive/2009/03/24/artalde-net-depuraci-243-n-avanzada-con-windbg.aspx"&gt;comentó Ibon en su blog&lt;/a&gt;, este miércoles voy a tener la oportunidad de pasar un magnifico rato con los chicos de &lt;a href="http://www.artalde.net/"&gt;Artalde.NET&lt;/a&gt; hablando de uno de mis temas favoritos: la depuración avanzada de aplicaciones .NET.&lt;/p&gt;  &lt;p&gt;Pasaremos un ratito entretenido (¡o eso espero!) hablando de WinDbg y su uso para detectar bugs esquivos y problemas de rendimiento; por el camino discutiremos ciertos detalles de la implementación de .NET e internals que de seguro nos resultarán útiles para hacer código mas robusto, estable y eficiente. Y después… tapitas y pinchitos por Bilbao!! No se a vosotros, pero a mi el plan me suena de maravilla :)&lt;/p&gt;  &lt;p&gt;Así que ya sabéis, si estáis por Bilbao este Miércoles y os apetece bajar a las trincheras, no dejéis de registraros &lt;a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032407902&amp;amp;culture=es-ES"&gt;aquí&lt;/a&gt; y pasar a hacernos una visitilla. &lt;/p&gt;  &lt;p&gt;&lt;em&gt;NOTA: A la finalización del evento subiré aquí mismo los materiales del mismo.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;NOTA2: Ya ha finalizado el evento, y con el retraso que me caracteriza (¡sorry!) os pongo el enlace a la descarga de las presentaciones de la sesión. Aprovecho también para dar las gracias a todos los asistentes: ¡que bien me cuidáis en Bilbao! &lt;/em&gt;&lt;/p&gt;  &lt;h5&gt;Rock Tip:&lt;/h5&gt;  &lt;p&gt;Como dice el titulo de &lt;a href="http://www.youtube.com/watch?v=EBxl-Lz2378"&gt;este gran tema&lt;/a&gt; de los &lt;a href="http://en.wikipedia.org/wiki/Vains_of_Jenna"&gt;Vains of Jenna&lt;/a&gt;, muchas veces el enemigo esta en nosotros mismos; esta frase me parece muy apropiada para las sesiones de depuración, sobre todo cuando nos toca depurar nuestro propio código. Por ello, este rock tip va para esta banda de sleaze rock tan poco conocida pero tan interesante. &lt;/p&gt;  &lt;p&gt;Enjoy, and Keep rockin’!!!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=145938" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Eventos/default.aspx">Eventos</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/Comunidad/default.aspx">Comunidad</category><category domain="http://geeks.ms/blogs/palvarez/archive/tags/DOT/default.aspx">DOT</category></item></channel></rss>
