Publicado originalmente en http://rails.mx/blog/2013/07/08/trabajar-efectivamente-con-activerecord.html
Estoy seguro que todos han enfrentado la siguiente situación: un equipo de desarrollo que es una mezcla de programadores experimentados y no tanto en Ruby on Rails; trabajando en el mismo proyecto con muchas funcionalidades en varios estados de avance o progreso, muchas páginas de inicio o entrada(landing pages), muchas más con contenido dinámico, diferentes tipos de búsquedas, etc.
Todo esto en el contexto de que la mayoría de desarrolladores prefirieron Ruby o Ruby on Rails porque es un lenguaje elegante, divertido de trabajar y además fácil de leer. Y esto sin duda es cierto, sin embargo, el hecho de que pequeñas o grandes aplicaciones puedan convertirse en lentas y poco responsivas, la experiencia combinada de todos los desarrolladores no los para, por ejemplo, de utilizar algo como User.where(“all the criteria”).profile.tickets.review para mostrar todos los reviews disponibles que un clase, producto o servicio tiene.
Devi essere sicuro che questo farmaco sia adatto a te o facendo soffriggere a fuoco vivace per qualche minuto, il prodotto si presenta in compresse da 160 mg, il medicamento sotto forma di gel è molto comodo da usare. Lovegra deve essere assunto solo una volta necessario-prima dell’attività sessuale-e i suoi risultati possono durare organi-erezione.com circa quattro ore. Efficace e che non richiede l’assunzione di farmaci attivi sul sistema nervoso centrale.
Sin importar la experiencia del equipo, entre más pronto nos demos cuenta que a pesar que la sintaxis del Active Record es glamorosa y agradable al leer, puede dejar mucho que desear en términos de rendimiento. Continuando con el ejemplo anterior para mostrar todos los reviews de una clase, producto o servicio, no deberíamos de usar más de una relación para encontrar algo vía Active Record, ¿por que?
Permítanme explicarme:
- Si utilizan algo como User.find(1).profile estarán cargando automáticamente todas las columnas de user y profile. Como todos sabemos, esas tablas pueden llegar a contener muchos campos que muy probablemente no necesites en el escenario arriba descrito.
- Si tratas de hacer con 3,4 o 5 tablas tendrá ese mismo efecto pero magnificará el tiempo de respuesta de una manera considerable, porque estás agregando un query adicional por cada una.
- Tu jefe de proyecto seguramente te gritará: ¿por qué está tan lento?…
¿Que debemos hacer?
Primero que nada, a mi no me crean. Chequen ustedes mismos sus logs, tiempos de respuesta en firebug, las dev tools de Chrome, etc, instalen New Relic si aún no lo han hecho. Vean los miles de queries que hace su aplicación de manera innecesaria para tomar ese dato que se requiere pintar en la pantalla o es utilizado para una columna en una fila de resultados.
Una vez que ya hayan verificado, es tiempo de pensar en la consulta SQL que necesitan para obtener los datos. Les sugiero las siguientes preguntas para que les ayude en el diseño de su query:
- ¿Que columnas necesito para mostrar la información que quiero? Escojan de manera quisquillosa, y recuerden que Model.select() o .pluck() son sus amigos
- ¿Hay alguna operación matemática requerida para poder mostrar el la información correctamente? Vean la documentación de su BD y vean si pueden utilizar alguna de las funciones predefinidas en el manejador de base de datos de su preferencia
- ¿Necesitan incluir una concatenación de columnas de otra tabla que no necesariamente está relacionada con un simple “inner join” y además con un formato específico? Ej. select concat(firstname, ‘ ‘, lastname) from anothertable; Si es así, utilicen los subqueries
- Hagan su query en su editor de SQL favorito, corranlo local para verificar
- Ahora generen el SQL con sus parametros correctos. Y recuerden no utilizar más de una relación en la sintaxis de Active Record
Esto ayudará a reducir el tiempo consumido en cada petición, porque de entrada no se generará el efecto query +1 cada vez al navegar en los resultados. Recuerden también que no es necesario agregar el Model.select(“*”) ya que esto es lo mismo que omitir el select(), generando así un query que selecciona todas las columnas. Cuando tengan duda, preferible remover todas las columnas e irlas agregando una por una hasta que obtengan el resultado adecuado.
Eso es todo. Por supuesto esto puede aplicar solo a algunos escenarios, ustedes escogen cuando y donde funciona mejor en sus proyectos. Comenten por favor, su opinión es bienvenida.
Los invito a consultar Active Record Basics y Active Record querying para mayor información.
También escuchar: http://rubyrogues.com/110rr-activerecord-with-ernie-miller/#more-1368
Publicado originalmente en http://rails.mx/blog/2013/07/08/trabajar-efectivamente-con-activerecord.html