En esta página:
Siempre estamos trabajando con Bases de Datos en Django y solo nos enfocamos en que este funcionable, mantenga la estructura de tablas ideal, tener las columnas que sean necesarias y todo esto esta bien, pero son pocos los Desarrolladores que se preocupan por optimizar la Base de Datos, yo honestamente hubo ocasiones en que no las hacia, pero cuando me di cuenta lo útil que puede ser, lo puse en práctica y en este Post voy a compartirte 5 recomendaciones para que optimices tu Base de Datos en Django.
Antes continuar te recomiendo leer el artículo Que es Django, Historia y tu primer Hola Mundo (Corregido: 31-05-2019), si ya conoces sobre Django puedes continuar, no hay problema.
Para compartirte los Tips para la optimización de una Base de Datos en Django, voy a basarme en los siguiente modelos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class Autor(models.Model): nombre = models.CharField(max_length=200) email = models.EmailField() def __str__(self): return self.name class Blog(models.Model): nombre = models.CharField(max_length=100) frase = models.TextField() def __str__(self): return self.name class Entrada(models.Model): blog = models.ForeignKey(Blog, on_delete=models.CASCADE) titulo = models.CharField(max_length=255) contenido = models.TextField(blank=True) likes = models.IntegerField(blank=True, default=0) autores = models.ManyToManyField(Author, blank=True) class Meta: default_related_name = 'entradas' def __str__(self): return self.headline |
No haré un uso netamente de los modelos, solo que para los Tips que te compartiré usaré como referencia estos modelos.
5 Tips para Optimizar una Base de Datos
Hay muchas acciones que podemos realizar para optimizar la consulta, la inserción, actualización, eliminación, etc. en una Base de Datos, he escogido estos Tips y te los comparto a a continuación.
Utiliza get() sabiamente
Has uso del método get() cuando sepas que solo hay un objeto que coincida con tu consulta, si ningún elemento coincide con la consulta, get() te arrojará una excepción DoesNotExist. Si varios elementos coinciden con la consulta, el método get() arrojará una excepción MultipleObjectsReturned, podrías usar el método get() de la siguiente manera
1 2 3 4 5 6 7 8 9 10 11 12 13 |
try: one_entry = Entry.objects.get(blog=2000) except Entry.DoesNotExist: # La consulta no coincide con ningún elemento. pass except Entry.MultipleObjectsReturned: # La consulta coincidió con varios elementos. pass else: # La consulta que coincide con un solo elemento print(one_entry) |
Usa herramientas de Depuración
Para determinar la eficiencia de tu código puedes hacer uso de la herramienta django-debug-toolbar y el método explain() de la API de QuerySet, también es importante comprender cuales son las consultas SQL sin procesar que Django esta realizando. En ocasiones puede que estés ejecutando un query innecesario, analizando lo que hace el query, puedes plantearte optimizar la consulta.
Utiliza los valores de las Foreign Keys
Django ORM recupera de manera automática y almacena en caché las Foreign Keys, puedes optar por hacer uso de estas claves en lugar de realizar nuevamente una consulta innecesaria a la Base de Datos.
1 2 3 4 5 6 7 |
# La base de datos se reutiliza innecesariamente blog_id = Entry.objects.get(id=200).blog_id # Entonces hago uso de la 'foreign key' almacenada en caché, de esta manera la base de datos no se reutiliza innecesariamente blog_id = Entry.objects.select_related('blog').get(id=200).blog.id |
Usa iterator() cuando sea conveniente
Cuando haces un QuerySet generalmente siempre almacena en caché los resultados y al realizar cualquier operación con ese QuerySet, primero verifica los resultados almacenados en caché. Al contrario que el Tip anterior, en este caso puedes hacer uso del método iterator() el cual no realiza una búsqueda en el caché y lee los resultados directamente de la Base de Datos, no guarda resultados en QuerySet.
En algunas ocasiones un QuerySet puede hacer uso de una gran cantidad de objetos con mucha memoria en caché y solo necesitamos acceder a estos objetos una sola vez, entonces haciendo uso del método iterator() evitamos que la consulta no sobrecargue la memoria y la Base de Datos constantemente.
A continuación puedes ver que cuando se recuperan todos los registros de la Base de datos, estos se cargan en la memoria y se iteran una por una
1 2 3 4 5 |
q = Entry.objects.all() for each in q: do_something(each) |
Y si usas el método iterator(), Django mantendrá la conexión SQL abierta, entonces leerá cada fila y llamará a do_something antes de leer la siguiente fila de una tabla de la Base de Datos
1 2 3 4 5 |
q = Entry.objects.all().iterator() for each in q: do_something(each) |
Usa select_related y prefetch_related para consultar Objetos Relacionados
Si estas realizando una consulta que contiene objetos relacionados en la Base de Datos, haciendo uso de los métodos select_related y prefetch_related de Django puedes gestionar adecuadamente tus consultas.
Con select_related puedes obtener un QuerySet que sigue las relaciones de la foreign-key, este selecciona datos adicionales de los objetos relacionados cuando se ejecuta una consulta
1 2 3 4 5 6 7 |
# Afecta la base de datos. e = Entry.objects.select_related('blog').get(id=5) # No afecta la base de datos, porque 'e.blog' pudo ser rellenado previamente b = e.blog |
Y prefetch_related te recupera de manera automática un solo lote de datos con objetos relacionados para cada consulta, por ejemplo a continuación una consulta sin prefetch_related
1 2 3 4 |
Blog.objects.all() ["Tutoriales (react, vue, angular)", "Categorias (aplicaciones, frameworks, articulos)"... |
Con prefetch_related se puede reducir a solo 2 consultas
1 2 3 |
Blog.objects.all().prefetch_related('tutoriales') |
Ambos métodos te ofrecen un mejor rendimiento en tus consultas de objetos relacionados
Conclusión
Como mencione arriba, existen muchos tareas de optimización que le puedes aplicar a tus consultas, querys, etc. En la documentación de Django podemos encontrar métodos que nos pueden ayudar a lograr la optimización que buscamos.
Optimizar las tareas con la Base de Datos es algo muy importante, evitamos consumo excesivo de memoria, sobre todo cuando una gran cantidad de usuarios accede a tu Proyecto y por ende realizarán muchas consultas.
Nota (s)
- Alguno métodos mencionados en este Post, pueden ser eliminados, modificados o continuar, esto no depende de mi, si no de los Desarrolladores que dan soporte a Django.
Síguenos en las Redes Sociales para que no te pierdas nuestros próximos contenidos.