Surviving the Night

El blog de Pablo Doval sobre .NET, SQL, WinDbg...

Pinball Map: Cuidado con los Mapeos en NHibernate

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! ;)

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:

EXEC sp_executesql N'
SELECT
   this_.ID as ID90_0_,
   this_.BorradoLogico as BorradoL2_90_0_,
   this_.Descripcion as Descripc3_90_0_,
   this_.Estado as Estado90_0_,
   this_.VisibleWeb as VisibleWeb90_0_,
   this_.CodigoDB2 as CodigoDB6_90_0_,
   this_.FechaPrevistaInicioComercializacion as FechaPre7_90_0_,
   this_.FechaFinComercializacion as FechaFin8_90_0_, 
   this_.Comentarios as Comentar9_90_0_,
   this_.URLFoto as URLFoto90_0_,
   this_.Orden as Orden90_0_,
   this_.URLFotoMiniatura as URLFoto12_90_0_,
   this_.SufijoID as SufijoID90_0_,
   this_.MarcaID as MarcaID90_0_,
   this_.VersionId as VersionId90_0_
FROM 
   VistaProblematica this_
WHERE
   this_.CodigoDB2 in (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) and
   this_.SufijoID in (@p10, @p11, @p12, @p13, @p14) and this_.BorradoLogico = @p15',
N'@p0 nvarchar(5),@p1 nvarchar(5),@p2 nvarchar(5),@p3 nvarchar(5),@p4 nvarchar(5),@p5 nvarchar(5),@p6 nvarchar(5),@p7 nvarchar(5),@p8 nvarchar(5),@p9 nvarchar(5),@p10 bigint,@p11 bigint,@p12 bigint,@p13 bigint,@p14 bigint,@p15 bit',
    @p0 = N'040  ', @p1 = N'1F7  ', @p2 = N'1G3  ', @p3 = N'209  ',
    @p4 = N'3R3  ', @p5 = N'8S1  ', @p6 = N'8S6  ', @p7 = N'8T4  ',
    @p8 = N'8T8  ', @p9 = N'9AK  ', @p10 = 1819, @p11 = 1820, @p12 = 1821,
    @p13 = 1822, @p14 = 3614, @p15 = 0

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 :)

Procedimos a comprobar los tiempos de esta consulta con SET STATISTICS TIME ON:

SQL Server Execution Times:
   CPU time = 703 ms,  elapsed time = 796 ms
.

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:

(50 row(s) affected)
Table 'Worktable'. 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.
Table 'Versiones'. 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.
Table 'Modelos'. 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.
Table 'Sufijos'. 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.
Table 'Colores'. 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.

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 worktables

¿¡Worktables?! ¡¿Que mi madre es eso?!

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 :)

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.

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.

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.

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.

Volviendo al Turrón:

A la vista de la actividad de E/S en Worktables, decidí confirmar mis sospechas, por lo que adjunté una traza de profiler:

profiler

¡Bingo! Podemos comprobar que aparece un evento de Hash Warning al ejecutar la consulta.

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.

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 sp_executesql.

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(**) :)

Definicion

Como podéis ver, la columna CodigoDB2 está definida como char(5), pero en el código de la consulta que genera NHibernate nos pasa el parámetro como nvarchar(5), 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.

Hicimos la prueba, cambiando los tipos de datos sobre la consulta generada por NHibernate en el sp_executesql, quedando la misma así:

EXEC sp_executesql N'
SELECT
   this_.ID as ID90_0_,
   this_.BorradoLogico as BorradoL2_90_0_,
   this_.Descripcion as Descripc3_90_0_,
   this_.Estado as Estado90_0_,
   this_.VisibleWeb as VisibleWeb90_0_,
   this_.CodigoDB2 as CodigoDB6_90_0_,
   this_.FechaPrevistaInicioComercializacion as FechaPre7_90_0_,
   this_.FechaFinComercializacion as FechaFin8_90_0_, 
   this_.Comentarios as Comentar9_90_0_,
   this_.URLFoto as URLFoto90_0_,
   this_.Orden as Orden90_0_,
   this_.URLFotoMiniatura as URLFoto12_90_0_,
   this_.SufijoID as SufijoID90_0_,
   this_.MarcaID as MarcaID90_0_,
   this_.VersionId as VersionId90_0_
FROM
   VistaProblematica this_
WHERE
   this_.CodigoDB2 in (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9) and
   this_.SufijoID in (@p10, @p11, @p12, @p13, @p14) and this_.BorradoLogico = @p15',
N'@p0 char(5),@p1 char(5),@p2 char(5),@p3 char(5),@p4 char(5),@p5 char(5),@p6 char(5),@p7 char(5),@p8 char(5),@p9 char(5),@p10 bigint,@p11 bigint,@p12 bigint,@p13 bigint,@p14 bigint,@p15 bit',
    @p0 = N'040  ', @p1 = N'1F7  ', @p2 = N'1G3  ', @p3 = N'209  ',
    @p4 = N'3R3  ', @p5 = N'8S1  ', @p6 = N'8S6  ', @p7 = N'8T4  ',
    @p8 = N'8T8  ', @p9 = N'9AK  ', @p10 = 1819, @p11 = 1820, @p12 = 1821,
    @p13 = 1822, @p14 = 3614, @p15 = 0

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:

SQL Server Execution Times:
   CPU time = 78 ms,  elapsed time = 78 ms.

(50 row(s) affected)
Table 'Worktable'. 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.
Table 'Colores'. 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.
Table 'Sufijos'. 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.
Table 'Versiones'. 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.
Table 'Modelos'. 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.

¡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.

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.

Conclusiones:
  • Es muy importante garantizar la corrección de los tipos de datos en los mapeos de cualquier solución de persistencia.
  • 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!
  • Estaba claro que si yo iba a hablar acerca de NHibernate, no iba a ser enteramente para bien… ;)

Keep Rockin’!

(*): Soy perfectamente consciente de lo mal que puede llegar a sonar esa frase!
(**): Tengo que dejarlo claro: el modelo de datos NO es mío!!! :)
Rock Tip:

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 ‘In Flames’, grupo fundado y liderado hasta hace poco por ese genio que es Jesper Strömblad.

Cuando estaba escribiendo este post sobre el mapeo en Hibernate, no pude evitar que se me viniera a la cabeza su tema ‘Pinball Map’; 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! ;)

Posted: 8/6/2010 13:25 por Pablo Alvarez | con 31 comment(s) |
Archivado en: ,
Comparte este post:

Comentarios

david ha opinado:

Danos un ejemplo de como deberia ser el diseño de la tabla que muestras y el modelo de datos, para tenerl en cuenta.

Gracias por compartir tu experiencia.

# June 8, 2010 2:38 PM

Pablo Alvarez ha opinado:

Hola David! Muchas gracias por tu comentario!

Lamentablemente no puedo proporcionaros el modelo de datos, ya que es propiedad del cliente y obviamente no tendría su permiso para publicarlo aqui ;)

Respecto a la vista en cuestión, si te puedo decir que hay cosas que chirrian mucho: el uso de tipo BIGINT para las claves surrogadas (creedme, no necesitaban 2,147,483,647 identificadores en cada tabla!!), esos VARCHAR(2083) suenan cuanto menos curiosos...

De todos modos, este post no pretende centrarse en las aberraciones que pueda o no tener este modelo de datos.. para eso tengo muchos más suculentos a mano! ;)

Un saludo!

# June 8, 2010 3:00 PM

Alberto Diaz Martin ha opinado:

Muy bueno!! dejando claro que la capa de persistencia debe de llevar una revisión por parte de un DBA y de un buen tuneado. Es lo que tienen las consultas generadas automáticamente

# June 8, 2010 4:09 PM

Sergio Tarrillo ha opinado:

que gran artículo, Maestro!

Saludos,

# June 8, 2010 4:10 PM

devsoftx ha opinado:

Hola Pablo,

Importante tu conclusión:

(*)Es muy importante garantizar la corrección de los   tipos de datos en los mapeos de cualquier solución de  persistencia.

Hubiera sido tambien muy bueno tambien muestres el Mapping de esa tabla y poder ver el buena/mala practica empleada.

Saludos desde Trujillo, Perú

# June 8, 2010 4:16 PM

Marc Rubiño ha opinado:

Genial como siempre Pablo ;-)

# June 8, 2010 5:36 PM

Rafael Huapaya ha opinado:

Hey muy buena la página, volvi a caer por casualidad a tu página ya que la había perdido hace tiempo, y los articulos que publicas son muy buenos, pero ya me había llamado la atención el vinculo que le das con la música jejeje. una abrazo desde Lima, Perú.

# June 8, 2010 8:37 PM

fravelgue ha opinado:

Antes que nada felicitarte por el excelente post. Pero ya que tienes una opinión tan denostada de nhibernate me gustaría que opciones apoyas tu, y porque son mejores que nhibernate?

En este caso me parece que el problema estaba con el mapeo que tenía. Me parece que este tipo de problemas pueden aparecer con otras capas de datos, o tal vez tu conozcas una que sea la solución total?

# June 8, 2010 10:28 PM

Pablo Alvarez ha opinado:

Muchas gracias a todos por vuestros comentarios!!

@Alberto: Bueno, no pido un DBA puro, ya que en muchos clientes 'grandes' ni siquiera tienen eso en el lado de SQL Server!!! :( Pero un bueno arquitecto de datos o un desarollador especializado en ello creo que debería ser un requisito imprescindible. Y, desde luego, no fiarse ciegamente en las consultas autogeneradas :)

@Sergio: Gracias!!!

@devsoftx: Lamentablemente no tengo la diferencia de los mapeos a mano, pero básicamente en el primer caso el cliente confio en el automapping, estableciendo solo el nombre de la propiedad y el tipo como "String" y en el segundo estableció explicitamente el "AnsiString" y el sql-type de la propiedad column.

@Marc: :) Gracias Marc!!

@Rafael: Gracias Rafael! El día que me reclamen derechos de autor por los Rock Tips no me hará tanta gracia lo de poner la musiquilla :) Pero mientras tanto, espero que no haya nunca un post sin ellos.. es curioso, pero a veces me lleva mas tiempo buscar un buen Rock Tip que escribir el artículo técnico!!

@fravelgue: Gracias por tu comentario! no te equivoques, como puedes ver en mi post, en el artículo no le hecho la culpa explicitamente a NHibernate, y dejo claro que el mapeo es el problema. Es más, en las conclusiones digo explicitamente que ese es un problema "en cualquier solucion de persistencia". Si establezco mal mi mapeo con Entity Framework, voy a caer en el mismo problema, eso esta claro.

Dicho eso, también es cierto que no soy precisamente un ferviente admirador de NHibernate, por decirlo sutilmente. Desde problemas meramente técnicos y conceptuales hasta otros más pragmaticos, como la escasez de soporte...

Resumiendo, no conozco ninguna solucion total, y sinceramente, creer que existe eso es utópico. Actualmente me inclino por EF4, que lo considero espectacular, pero también estoy convencido que en unos años tendrémos algo más: no es la solucion definitiva.

Quizá estaría bien hacer un día un duelo EF vs. NHibernate en la línea del gran duelo Java vs. .NET que protagonizxarán El Bruno y Pablo Bonansea el día 15, pero la verdad es que no me apetece hacerlo aqui, en este post. Solo pretendía aportar algo de luz en un problema técnico :)

# June 9, 2010 9:06 AM

fravelgue ha opinado:

Gracias por la respuesta, creo que el post comparativo sería buenísimo pero creo que aún mucho mejor sería uno con esos problemas técnicos y conceptuales que posee nhibernate.

# June 9, 2010 11:07 AM

Hadi Hariri ha opinado:

Hola Pablo,

Podrías por favor comentar que problemas técnicos y conceptuales son las que te refieres en NHibernate? Si no me equivoco, muchos problemas conceptuales son las que justamente EF 1 tuvo que resolver con EF 4. Por otra parte, respecto a soporte, en que sentido te refieres? Porque aparte de tanto empresas como personas que ofrecen soporte de pago por NH, existen foros y un grupo de desarrolladores muy activos que no solamente ofrecen soporte gratuito sino arreglan fallos y lo ponen a disposición del público de manera casí instantanea, y todo ello con sus correspondientes pruebas unitarias y que sirven como pruebas de regresión para garantizar una calidad en cada despliegue.

Por ello me interesa ver en que puntos crees que hay problemas conceptuales o de soporte.

Gracias.

# June 9, 2010 2:10 PM

devsoftx ha opinado:

Buenas,

Esto se puso candente, Metiendome en lo que no me importa y sin animo de ofender, siento en este post algo como: "Mira, si la culpa la tenia NH" y pues me deja un sin sabor , NH es una gran herramienta , en las manos adecuadas puede dar excelentes resultados y en las que no tanto, pues te lleva a aprender "aspectos" para comprender su comportamiento, esto me hace recordar años atras algo similar respecto al uso y rendimiento de Linq2SQL, algo ya superado.

En lo personal uso tanto Nhibernate como EF, utilizando uno u otro según se requiera y no tenido ningun problema de soporte para NH, llevando ya 3 años con él.

Saludos

# June 9, 2010 2:40 PM

Pablo Alvarez ha opinado:

:) Mira que quereis guerra ¿eh?

Repito, una vez más, que como dije en el post explicitamente, este problema podria suceder bajo cualquier motor de persistencia, y que NO es un problema de NHibernate. Más claro no pude ser.

Si notasteis ese regustillo es porque así quise escribir mi post; es mi estilo 'jocoso' y al que no voy a renunciar, pero repito: no creo que podais encontrar un 'ataque' por mi parte a NHibernate en todo el post.

Si es cierto que en el comentario de esta mañana dije explicitamente que no me gustan bastantes cosas de NHibernate, y me tengo que reafirmar en ello, y más teniendo en cuenta los 'casos' que llevo encima con el. Pero repito, no quiero convertir este post en una guerra entre NHibernate y EF4 ¿ok? Para un post que me sale bien, no lo quiero estropear con los comentarios! ;)

Las guerras de religion mejor las dejamos para una tarde de cervezas, u otro post destinado a tal efecto ¿os parece?

(...quede claro que me cuesta no entrar al trapo xD)

# June 9, 2010 3:10 PM

Hadi Hariri ha opinado:

Pablo,

Pido disculpas. No pretendo convertir este post en una guerra ni un EF vs NH, ni mucho menos. Conozco en bastante detalle ambas tecnologías y sé las diferencias y ventajas de cada una de ellas.

Lo que si creo que es importante es no lanzar comentarios al aire sin justificación detrás. Se supone que las personas que leen tu blog de alguna manera respetan lo que tienes que decir y consecuentemente de alguna manera pueden hacer caso a tus opiniones.

Mi comentario es más bien referente a lo que mencionabas de que NH no da la talla a nivel técnico, conceptual o en términos de soporte. Decir algo como eso y de alguna manera no entrar en detalles, pues como podrás comprender, puede dejar lugar a dudas. Y personas que no conozcan NH podrían descartarlo como una solución muy factible.

Lamentabelmente y aunque no parezca comprehnsible, hay personas que no investigan por su cuenta y solamente hacen uso de tecnologías de ciertas empresas.

Gracias.

# June 9, 2010 3:48 PM

Pablo Alvarez ha opinado:

Hadi, por favor, no pidas disculpas! ;) Agradezco todos los comentarios, pero comprende que trato de evitar que geeks.ms se convierta en un barrapunto, al menos en lo que respecta a mi pequeño rinconcito de geeks.ms.

(Disclaimer: Tampoco tengo nada en contra de barrapunto ni slashdot ni nada!!! no me busqueis las cosquillas por aqui! :))

Hadi, conozco tu trabajo, soy lector tuyo, y sé de tu gran experiencia tanto con EF como NHibernate. Yo también me he tenído que pelear bastante con las dos tecnologías, aunque de seguro no tanto como tu! Por eso no pretendo sentar catedra ni mucho menos con mis comentarios, pero también os puedo decir que no son gratuitos y hay experiencia detrás de ellos. Lo que si es cierto, y no me di cuenta en su momento pero lo he visto ahora con tu comentario, es que puede parecer que tiro la piedra y escondo la mano. No es eso lo que busco, es simplemente que no quiero 'ensuciar' el post. Pero esta vez voy a intentar responder un poco más claramente. Eso si, no estiremos mucho más el tema por aqui, ¿ok?

Empezamos: creo que jamás he dicho que NHibernate no de la talla :) he trabajado en proyectos muy grandes que emplean NHibernate como solucion de persistencia, seguramente alguno de ellos también conocido por tí, y evidentemente el producto funciona, y funciona muy bien. No soy tan talibán de las tencologías Microsoft, aunque pueda parecerlo.

Lo que si es cierto es que, quizá debido a mi trabajo en el equipo DOT, todo lo que veo en mi día a día son problemas y situaciones alejadas de lo ideal. Te voy a contar algunas de las ultimas cosas a las que me tuve que enfrentar:

- No es un problema de NHibernate como tal, pero quizá si esta poco documentado la no seguiridad frente a hilos del ISession, que ha dado buenos quebraderos de cabeza en algun cliente mio.

- Implementación de soporte concurrente de multiples bases de datos (se hizo uso de una solución muy conocida, publicada en codeproject, pero que presentaba diversos problemas, entre ellos la ausencia de garantias de que se pudiera tener una misma sesión dentro de una petición de ASP.NET... un casito interesante también)

- Soporte: casi siempre redirigidos a foros, cosa que me parece muy bien para un proyecto de la facultad, pero cuando estoy con problemas en un cliente, quiero una respuesta mucho más profesional, con un compromiso detrás. Mis experiencia desde dentro del soporte de Microsoft me hace valorar más este punto que mucha gente, pero todavía hace poco el soporte de Microsoft sacó a un cliente mio de un buen apuro en un caso de gran dificultad. Respecto a los foros de NHibernate, podría publicar aqui algunas respuesta de grandes personajes de la comunidad, como Fabio o Ayende, que rozan casi la falta de respeto cuando se trata de un proyecto empresarial.

Como veis, excepto el tema de soporte, seguramente la mayor parte de los escenarios tienen que ver con el copy&paste generalizado y las malas prácticas, pero mi experiencia dista bastante de ser positiva.Pero repito, dicho esto, no estoy diciendo que NHibernate sea una mala solución, ni muchisimo menos. Es obviamente mucho más maduro que EF, y tiene sus cosas mejores y peores, sobre todo si lo comparamos con EF1. Solo digo que yo y mis clientes hemos tenido experiencias 'no tan buenas' y por eso mis comentarios.

Espero que con esto quede claro que no escondo la mano. Podeis estar de acuerdo o no, pero eso ya no lo quiero debatir aqui... ya sabeis aquel viejo adagio de que las opiniones son como los culos, cada uno tiene el suyo :) Pues eso, este blog esta para intentar ayudar a la gente, enseñar truquitos de WinDbg o de SQL Server, o lo que se tercie, pero no pretendo ser gurú ni guía, ni sentar cátedra con mis culos (perdón, opiniones!) :)

Por cierto, aunque no lo creais, traté de tener un cuidado exquisito al escribir el post, siendo claro en que eso pasa en cualquier motor de persistencia, pero no quise renunciar a meter NHibernate en el titulo del mismo :)

# June 9, 2010 5:01 PM

Hadi Hariri ha opinado:

Pablo,

Desconozco barrapunto por lo tanto no puedo comentar sobre ello. Lo que si creo que añade mucho valor a un blog son justamente los comentarios. No creo que ensucien un post.

Dicho esto, tampoco es mi intención convertir esto en un debate, pero solo comentarte algunos de los puntos sobre las que hablas:

- Respecto a la sesión, desconozco lo que tú hayas utilizado y sé que hay unas cuantas que tratan de gestionar la sesión y sé de algunas que tienen mucho éxito. La sesión frente a los hilos es algo muy básico de NHibernate que viene bastante bien descrito y hay numerosas blogs sobre ello. El problema que pueda conllevar al mal uso es normalmente debido a que:

1. Que la gente no lee la documentación y no se informa bien

2. Que la gente intenta usar un framework de manera incorrecta o como se dice se "lucha" contra el framework y que normalmente es consecuencia de una mala arquitectura o de lo primero (no leerse la documentación).

Sobre las sesiones en ASP.NET, también he tenido bastante éxito, tanto yo como otros con ello y es muy simple. Lo único que hay que conocer el framework, pero eso pasa con Entity Framework también.

Por último el soporte. Desconozco que mecanismos de soporte gratuito que te ofrece otros fabricantes que no sea Google, Foros o la comunidad en general. Sé que hay opciones de pago. Tampoco puedo hablar en nombre de Fabio ni de Ayende ni de ningún otro miembro de Nhibernate (y honestamente me parece un poco fuera de lugar mencionar personas que no estén involucradas en este debate), pero si puedo opinar sobre no solo el soporte que ofrece NHibernate sino la calidad. He visto con mis propios ojos cómo personas que han tenido problemas y bugs que muchas veces con otros fabricantes (sea Microsoft o otro) se haya dicho que se arreglaría en una versión futura, como los integrantes del equipo de NH han arreglado los fallos y ponerlos a disposición del cliente y sin coste. He visto como gente ha hecho esto en su horario libre, en fines de semana, etc.

También he visto actitudes de personas que han hecho preguntas en los foros sin antes molestarse en buscar un poco o leerse la documentacón. Esto no implica que se les tenga que hablar mal, ni mucho menos, pero el respeto también debe ser mutuo y decir a una persona que se lee la documentación no tiene de mal. También hay que comprender que hay una barrera de idioma entre las personas y muchas veces algo que no suena mal en castellano puedo hacerlo en inglés o una persona no nativa.

Por otra parte, hay más de una empresa que si ofrece soporte de pago de NHibernate, tal como Microsoft lo pueda hacer de Entity Framework, pero tenemos que distinguir lo que es voluntario de lo que es de pago. Pero la profesionalidad es ortogonal a los dos.

Pablo, llevo muchos años en esta profesión y también llevo muchos años no solo trabajando sino colaborando con proyectos Open Source. Te puedo decir sinceramente que veo muchisimas veces, mejores respuestas, mejor reacción, de proyectos open source que de otros fabricantes. Lamentablemente hay un afán a desprestigiar el OSS y hacerlo parecer no profesional. Si te pones a mirar la historia reciente, hay más soporte y continuidad en proyectos OSS que muchos proyectos y frameworks que han salido de fabricantes (y no es necesario mencionarlos).

No dudo ni mucho menos que te hayas peleado con NHibernate, al igual que lo hayas hecho con Entity Framework y tampoco he dicho que este post esté atacando a NH. Lo único que he dicho que hacer afirmaciones sobre las faltas técnicas, las lagunas a nivel conceptual y problemas de soporte de un framework, es necesario respaldarlo. Y todavía no he visto cuales son.

Pero tal como te comenté y tu mismo dices, en algún momento hay que parar de debatir.

Gracias.

# June 9, 2010 6:03 PM

José F. Romaniello ha opinado:

Hace bastante tiempo, que participo en los foros tanto de ingles como de español y jamas he visto tu nombre. Podéis ver mi participación en los siguientes enlaces http://bit.ly/cOJAfl y http://bit.ly/aohszH

A lo largo de este tiempo me he encontrado preguntando y también respondiendo. Por lo cual me llama mucho la atención la forma en que criticas este, nuestro recurso.

Me parece totalmente mal educado y fuera de lugar de tu parte decir "casi siempre redirigidos a foros, cosa que me parece muy bien para un proyecto de la facultad". Yo he resuelto situaciones de mi empresas, con respuestas que se han dado en el foro. Así que no entiendo en lo mas mínimo esa clasificación que haces de los recursos.

No se a que le llamas "respuesta mas profesional y con compromiso detrás", las veces que he tenido una duda me la han contestado instantáneamente y si ha sido un problema propio de la herramienta me han sabido guiar en como solucionarlo, o ellos mismos han solucionado el problema en cuestión de horas. Me gustaría que entiendas bien esto, "ellos mismos" "sin cobrarme 1 centavo" han solucionado el problema "en cuestión de horas". Si te hace falta puedo proveerte de links a hilos donde ha sucedido esto. ¿Más profesional que eso? ¿y encima gratuito? Remarco esta particularidad, por que es muy difícil de encontrar fuera del ámbito open source.

A donde esta la suite de tests de EF si quiero reportar un bug? A donde esta el trunk de EF!  Gracias a Dios, Microsoft esta aprendiendo a valorar esto y ya se pueden ver otras componentes, como es el caso de MEF pensadas de esta forma.

En mi humilde opinión, creo que estas totalmente equivocado y le has faltado el respeto con eso de "para proyecto de facultad" ha mucha gente como yo que trata de ayudar, sin obtener nada a cambio a muchas personas, entre las cuales hay gente que sabe agradecerlo y como en todos los ámbitos de la vida gente desagradecida capaces de despreciar semejante ayuda.

# June 9, 2010 7:58 PM

Pablo Alvarez ha opinado:

En fin.. esta claro que, o bien he estado mucho mas desafortunado con mis comentarios que de costumbre, o bien este tema es particularmente sensible, o bien teneis mas ganas de filosofar que yo...

José, lamento si te he ofendido, te pido disculpas por ello. Y lo hago de corazón, porque siento que puedes sentir despreciada tu colaboración, y ¡para nada!

Sin embargo, ¿sabes que? yo también escribo en foros desde hace muchos años tratando de ayudar con lo poquito que puedo saber a los demás, escribo en este pequeño rinconcito de geeks.ms para aportar un poco de luz también sobre las cosas que voy descubriendo, doy bastantes charlas al año en grupos de usuarios y eventos... no soy ajeno precisamente a dar y recibir ayuda por internet. Y la verdad, es que me sentaría mal que alguien 'despreciara' mi ayuda. Por esto te repito que creo que no me estas entendiendo correctamente. Permiteme que intente explicarte mi punto de vista:

Si aplicamos tu vision de mis palabras a mi caso particular, entonces ¿Creo que mis opiniones en blog, fotos, etc... son todas basura y que no debería hacerme nadie caso? Pues no, escribo con la mejor de mis voluntades, esperando que sea util a los demás (y si además consigo que paseis un rato ameno, mejor que mejor.. de ahi los rock tips, las tonterias que digo y mi estilo desenfadado). Si embargo, mis opinones en este caso son solo mias; puedo estar mas o menos acertado en ellas, pero si por alguna casualidad sigues algun consejo mio y tu aplicacion se va al carajo, puedes ir pedirle cuentas al maestro armero. Ni mi empresa ni nadie te garantiza su validez, ni te va a indemnizar en caso de que tu proyecto explote por mi mal consejo.

Claro que los foros funcionan, claro que tenemos un gran soporte. Pero para ciertos clientes, para ciertos casos calientes, yo lo que pido es otra cosa: Quiero un SLA, quiero visibilidad del trabajo que se hace, quiero tener un ingeniero onsite si es necesario, un follow de sun, estar con el desarrollador de esa linea de código al telefono si es necesario!

He trabajado en soporte de Microsoft: no voy a decir que sea la mejor organización de soporte del mundo, porque sincerametne no se ni siquiera como podria medirse eso, pero lo que sí se es la cantidad de recursos que teniamos a disposicion nuestra y de nuestros clientes. Hotfixes personalizados no eran nada extrano, ajeno o de otro mundo.. al igual que el contacto directo con gente de grupo de producto, código, simbolos.. lo que querais. Se lo que ofreciamos y se lo que no me puede ofrecer un 'simple' foro...

Os hablaba antes del caso de un caso concreto. Imagaginad que necesito acceder a multiples bases de datos concurrentemente con NHibernate, y que decido buscar en google y encuentro el proyecto que os comentaba antes en codeproject, que tiene algunos problemas serios. Paso a producción y me doy de bruces con ellos, ¿que hago? ¿alguien me indemniza, o me planta nu ingeniero de soporte onsite en 4 horas? y esto NO es una critica para la gente que desarrollo ese proyecto, qe bastante hacen con distribuirlo gratuitamente para que todos podamos usarlo y aprender de el. Simplemente quiero reforzar mi mensaje de que a veces necesitas hasta tener la posibilidad de demandar a alguien ;) (Por dios.. esto es una broma.. no me busqueis tambien la puntilla a esto, ¿ok?

Espero que con esto quede un poco claro mi punto de vista, y repito.. si he ofendido a alguien, por favor, aceptad mis disculpas.

PD: el dia que hable de Oracle me colgais del palo mayor! XDDDD

# June 9, 2010 9:04 PM

Fabio ha opinado:

O sea que todo ese lio eso porque no usaro type="AnsiString" o mejor dicho porque nunca controlaron que a NH le están diciendo una cosa pero en el DB escribiron otra...

Bah?!?! tanto lio ?

# June 10, 2010 5:21 AM

Marc Rubiño ha opinado:

Pablo tu artículo es una buena aportación que se puede sacar de contexto, yo me quedo con la experiencia de una buena herramienta mal utilizada.

Cada uno tiene que sacar las conclusiones y como dice Hadi mirarse muy bien las especificaciones y manuales antes de hacer nada.

Saludos.

# June 10, 2010 9:39 AM

Crowley ha opinado:

Corregidme si me equivoco.

Varchar(2083) tiene logica en el sentido de que el tamaño maximo de las URL's en IE es ese y ademas es el mas pequeño en comparacion de todos los navegadores y servidores web. Si se quiere guardar una url que pitufe en todos los navegadores y servidores no puede ser mayor a 2083.

# June 10, 2010 10:38 AM

Pablo Alvarez ha opinado:

@Fabio: Exacto!! el post solo queria tratar sobre los problemas cuando estableces mal el mapeo. Y yo tampoco me explico a que viene tanto lio! ;)

@Marc: Lo mismo, Marc. De acuerdo en las dos cosas! Gracias por lo de buena aportacion! ;)

@Crowley: Tienes razón en cuanto a la limitación, pero establecer ese valor a 2083 va a reservar mucha más memoria de la necesaria en casi todas las ocurrencias.

Es quizá el valor más seguro, si. Pero seamos sinceros, no va a haber en esta aplicación (ni en casi ninguna) una URL de tal tamaño. Para un varchar(2083), SQL Server va a reservar 1042 bytes por fila para el workspace en memoria. Eso es una animalada, y más teniendo en cuenta que seguramente nunca tengamos mas de 150-250 caracteres.

Por otra parte, también me crispa almacenar imagenes y thumbnails como rutas en la base de datos, pero esa es otra historia :) (además, en este caso tiene cierto sentido por que es una aplicación web y esas imagenes van a ir a cacheado IIS)

De todos modos Crowley, me parece muy interesante tu puntualizacion.

Un abrazo!

# June 10, 2010 11:09 AM

Fabio ha opinado:

@PabloAlvarez

yyy... algo yo me explico, tal vez el lio es generado por tu tono en el post.

Si hubieras aclarado las causas originales del issue tal vez hubiera sido mejor.

Te digo mi interpretación de las causas:

1) MsSQL es tan raro que casi es el unico que elije planes de ejecución dependiendo de la longitud/tipo de los parametros. (hay otras cosas raras en MsSQL pero bueno... otro tema)

2) Tu cliente es probable que no sepa la existencia de tags de mappings como <type> o <sql-type>

3) Tu cliente nunca leyó mi blog fabiomaulo.blogspot.com/.../empezando-con-nhibernate.html

4) Tu cliente prefirió pagarte a vos para que le controle la causa mirando MsSQL en lugar que seguir las buenas practicas que recomendamos en los foros/blogs gratis... que le vamos a hacer..

Por lo de "proyecto de facultad" lo considero una simple macana debida a tu encierro en tu mundo.

Cosa distinta es la comparación entre "soporte pago" y "soporte gratis"... a eso te contesté en twitter.

# June 10, 2010 3:46 PM

Pablo Alvarez ha opinado:

@Fabio:

Respondo a las cosas que tiene sentido responder, dejando las demas al margen para evitar polémicas :)

1) Esto no es del todo cierto. Si te fijas en mi post, el problema no es el plan de ejecución, que es EXACTAMENTE el mismo. El problema es que la consulta sp_executesql lleva el tipo de datos en la parametrización. Si cambias de un tipo a otro, SQL Server intenta ejecutar la consulta en lugar de 'romper', para lo que hace unos convert implicitos de tipo. Esto provoca que el tamaño necesario en memoria sea mayor del previsto en el plan de ejecucion cacheado, con lo que el workspace es insuficiente y tiene que hacer un spill a tempDb. Fabio, algo similar también sucede en Oracle (bind variable peeking) y en muchos otros motores relacionales.

Por tanto, SQL Server no cambia de plan de ejecución ni recompila. Ese NO es el problema, y esa es la razón por la que este post me parece que tiene cierto valor técnico, si me permitís decirlo.

2) Cierto es, mi cliente no conocia los sql-type. Por eso sucedió el problema, por eso le ayude, y por eso hice un post de ello: por si podía ayudar a otras personas con el mismo problema.

Sé que es algo conocido, pero quería dar cifras respecto al impacto de rendimiento de no establecer bien el mapeo. Me pareció interesante, y no creo que este mal blogear al respecto!!!

3) Mi cliente si te leyó, incluso te pregunto y fue respondido. Pero es cierto que ese cliente concreto no tiene un gran nivel de expertise en NHibernate. Nunca lo he negado. Aqui, repito por enésima vez, que este post es para ayudar a gente novata con un problema de novato.

Esto da que pensar: Cuando publico sobre WinDbg recibo criticas porque escribo para un sector muy pequeño, siendo muy 'elitista'. Cuando escribo algo básico, recibo críticas porque es algo básico. En fin...

4) Mi cliente me pagó para otras cosas, y esta fue una parte de la acción. Tenían varios problema de rendimiento y estabilidad que no sabían resolver, y yo se lo localicé y ayude a resolver. Tanto en SQL Server, como en código..

¿Cual es el problema con esto, Fabio? Mi cliente leyó en blogs y foros, copió mucho codigo de internet (parte de él sin revisarlo ni entenderlo) y se encuentra atascado y con prisas para lanzar un producto problemático e inestable. Nos contrató y le resolvimos los problemas que llevaba tiempo intentando resolver sin éxito. ¿Resultado? El cliente esta contento, problemas localizados.

No entiendo el sentido de tu punto 4, pero tengo suerte en una cosa: no necesito demostrar que mis clientes están contentos con mi equipo. Solo tienes que preguntarles a ellos y estoy seguro de las respuestas que vas a recibir :) Y ¿sabes? cuando vuelven a tener problemas, vuelven a llamarnos. Por algo será :)

Por último, repito mis disculpas (una vez más) si os sentisteis ofendidos con lo de "proyecto de facultad", pero creo que ya he aclarado el sentido en el que lo dije. No creo que tenga mucho sentido darle mas vueltas ¿no creeis?

un saludo, Fabio!

# June 10, 2010 4:16 PM

Pedro ha opinado:

> Desde problemas meramente técnicos y conceptuales hasta otros más pragmaticos, como la escasez de soporte...

Yo siempre he tenido excelente soporte y gratis con NH. En cambio con productos MS he tenido soporte pago malo o inexistente.

Cuales serían los problemas conceptuales o pragmáticos de NH ?

Yo diría que si no vas a seguir las recomendaciones y no te vas a preocupar un poco por leer el abundante material que hay y tratar al menos de hacer las cosas bien, más que no usar NH dejá directamente de hacer software, ya tenemos suficiente gente que hace la cosas mal.

Siempre está la alternativa de usar productos de menor calidad como EF, yo creo que para vos esa es una buena alternativa.

# June 10, 2010 4:37 PM

Javier ha opinado:

Je, que quilombo... por que no van a un psicólogo con el manualcito de nhibernate bajo el brazo y nos quedamos todos contentos. :P

# June 10, 2010 4:38 PM

Pablo Alvarez ha opinado:

@Javier: es la idea mas sensata de todos esta post :)

@Pedro: gracias por tu comentario...

# June 10, 2010 4:45 PM

ivowiblo ha opinado:

"Leemos mal el mundo y luego decimos que nos engaña".

Si tratás de clavar un tornillo con un martillo en vez de atornillarlo con un destornillador, no podés culpar a la herramienta. Hay que informarse primero, aprender. Veo que a la gente le encanta hablar.

# June 11, 2010 3:39 PM

El Bruno ha opinado:

Amigo, veo que el problema de las WorkTables que nos comentaste hace un tiempo -> tiene peligro !!!

Excelente Post :D

Salu2

# June 11, 2010 9:29 PM

Pablo Alvarez ha opinado:

@ivowiblo: gracias por el comentario! No puedo estar más de acuerdo contigo!

@Bruno: Gracias!!! Ya ves, me ha caido la del pulpo con la tonteria del post! Estaba pensando usar en las proximas charlitas esta demo con el mapeo de NHibernate, pero casi que no me atrevo! :)

un abrazote!!

# June 13, 2010 5:50 PM