error mysql 2006 al filtrar con gran lista de argumentos

Digamos que tengo un modelo como este:

class Order(models.Model):
       code = models.CharField(max_length=90, db_index=True, unique=True)

Cuando tengo una lista de códigos, list_of_codes, con más de 600.000 elementos y trato de conseguir una lista de códigos que están en mi base de datos, obtengo un error 'MySQL server has gone away' en la segunda línea de abajo - que creo que tiene sentido porque ahí es cuando se evalúa el diccionario así que probablemente está tomando un tiempo y los tiempos de conexión (?):

duplicate_codes = Order.objects.filter(code__in=list_of_codes).values_list('code', flat=True)

duplicates.update([some_dict[code] for code in duplicate_codes]) ## error gets thrown here

Estoy tratando de entender por qué esto está sucediendo y qué sería una buena manera de arreglar esto con la escalabilidad en mente. No puedo encontrar mucho en los docs django sobre filtrar con muchos datos como este. Por ahora, estoy partiendo la lista de códigos y haciendo el filtrado en pedazos.

Pregunta hecha hace 3 años, 4 meses, 29 días - Por devgeek


2 Respuestas:

  • El error "MySQL server has gone away" generalmente ocurre cuando la conexión con la base de datos MySQL se pierde debido a que el servidor ha cerrado la conexión por inactividad o por alcanzar algún límite de tiempo.

    En tu caso, al filtrar con una gran lista de argumentos en la consulta de Django, es probable que la consulta sea demasiado grande para ser manejada de una sola vez y por eso se alcanza el límite de tiempo de la conexión MySQL.

    Una manera de solucionar este problema es dividir la lista de códigos en partes más pequeñas y ejecutar consultas en lotes. Puedes hacer esto de la siguiente manera:

    python
    chunk_size = 1000  

    Tamaño del lote

    for i in range(0, len(list_of_codes), chunk_size): chunk = list_of_codes[i:i + chunk_size] duplicate_codes = Order.objects.filter(code__in=chunk).values_list('code', flat=True) duplicates.update([some_dict[code] for code in duplicate_codes])

    De esta manera, estás dividiendo la lista de códigos en lotes más pequeños y ejecutando la consulta por cada lote, evitando así la sobrecarga en la conexión MySQL.

    Otra forma de optimizar esto sería usando el método iterator() en la consulta para evitar cargar todos los resultados en memoria de una vez. Puedes hacerlo de la siguiente forma:

    python
    duplicate_codes = Order.objects.filter(code__in=list_of_codes).values_list('code', flat=True).iterator()
    
    for code in duplicate_codes:
        duplicates.update(some_dict[code])
    

    Espero que estas sugerencias te ayuden a resolver el error y mejorar la escalabilidad de tu código.

    Respondida el Dec 17, 2020 a las 20:40 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El error "MySQL server has gone away" suele producirse cuando el servidor MySQL cierra la conexión debido a un tiempo de espera. Esto puede ocurrir cuando se realizan operaciones que tardan mucho tiempo en completarse, como filtrar una gran lista de valores en una base de datos.

    Para resolver este problema, puedes utilizar la paginación para dividir la lista de códigos en partes más pequeñas. Esto reducirá la carga en el servidor MySQL y evitará que se agote el tiempo de espera.

    Aquí tienes un ejemplo de cómo puedes utilizar la paginación para filtrar una gran lista de códigos:

    python
    from django.core.paginator import Paginator
    
    

    Divide la lista de códigos en páginas de 1000 elementos cada una

    paginator = Paginator(list_of_codes, 1000)

    Recorre cada página y filtra los códigos en la base de datos

    for page in paginator.page_range: duplicate_codes = Order.objects.filter(code__in=paginator.page(page)).values_list('code', flat=True)

    Actualiza el diccionario con los códigos duplicados

    duplicates.update([some_dict[code] for code in duplicate_codes])

    Este enfoque dividirá la lista de códigos en partes más pequeñas y evitará que el servidor MySQL agote el tiempo de espera. También puedes ajustar el tamaño de la página según el rendimiento de tu servidor MySQL.

    Además de la paginación, también puedes utilizar otras técnicas para mejorar el rendimiento de las consultas de bases de datos, como la indexación, la caché y la optimización de consultas.

    Respondida el Dec 17, 2020 a las 20:51 - por Gemini

    Votos positivos: 0 | Votos negativos: 0