7

Sono in Python 2.7 e 1.7.1 con Django Django-restframework Ho un'API che mi restituisce alcuni valori specifici presi fron il database, si utilizza un serializzatore personalizzato come questo:Django REST quadro Serialize estremamente lento

class InventarioSerializer(serializers.ModelSerializer): 
    item = serializers.RelatedField(source='producto.item') 
    ubicacion = serializers.RelatedField(source='ubicacion.nombre') 
    class Meta: 
     model = Inventario 
     fields = ('epc','item','cantidad','ubicacion') 

vista del mio API viene chiamata in questo modo:

class ItemEnInventarioViewSet(InventarioListModelMixin, viewsets.ModelViewSet): 
    serializer_class = InventarioSerializer 
    renderer_classes = (UnicodeJSONRenderer,) 

e la mia ListModelMixin è questa:

class InventarioListModelMixin(object): 
    def list(self, request, *args, **kwargs): 
     item = request.QUERY_PARAMS.get('item', None) 
     inventario = Inventario.objects.filter(producto__item = item) 
     if inventario.count() == 0: 
      return HttpResponse(u"El item %s no se encuentra en el inventario" % item,status=400) 
     self.object_list = inventario 
     # Switch between paginated or standard style responses 
     page = self.paginate_queryset(self.object_list) 
     if page is not None: 
      serializer = self.get_pagination_serializer(page) 
     else: 
      serializer = self.get_serializer(self.object_list, many=True) <<--THIS IS THE PROBLEM 
     return Response(serializer.data) 

Funziona bene, ma quando provo a OTTENERE il DB attorno a 1000 o più voci, il serializzatore lo rende molto molto lento, intorno a da 25 a 35 secondi.

La query sul DB è molto semplice, quindi il DB non rappresenta affatto il problema.

Se ho serializzare il set di query con questa funzione "data = serializers.serialize('json', myQuerySet)" ci vogliono al massimo 3 secondi, ma io non ottenere le informazioni come voglio, è per questo che io uso un serializzatore personalizzato

Esiste un modo più veloce per ottenere quella quantità di valori? Forse con un altro serializzatore? qualche idea?

** RISPOSTA Grazie a Kevin ** Modifica della query:

inventario = Inventario.objects.select_related('producto__item','ubicacion__nombre').filter(producto__item = item) 

... rende il serializzatore non colpire il database di ogni risultato fila per recuperare i valori esteri.

+1

sembra un problema di query ... – Raphael

+0

La mia query è molto semplice, cerca 8 campi con un JOIN INTERNO e uno WHERE, il database restituisce i dati in meno di 0,25 secondi, quindi non è sicuramente la query o il db –

risposta

9

La query sul DB è molto semplice, quindi il DB non rappresenta affatto il problema.

Assicurati di non avere un N+1 issue con le tue domande. Possono essere semplici, ma se ce ne sono molti, ci vorrà molto tempo. Ho scritto un bel po 'su fixing performance issues in Django REST Framework qui, e puoi trovare molto su di esso cercando in giro.

C'è un modo più veloce per ottenere quella quantità di valori? Forse con un altro serializzatore? qualche idea?

Se i dati non cambiano così spesso o si possono affrontare eventuali problemi di memorizzazione nella cache, si può trarre grande vantaggio dall'aggiunta di alcuni caching alla propria API. drf-extensions fornisce alcuni mixaggi utili per il caching che potrebbero aiutarti se il tuo problema non riguarda le tue query.

quando cerco di formare il DB arround 1000 o più voci

ho capito che il codice ha impaginazione integrato in esso, ma voglio sottolineare il valore in usando l'impaginazione quando si lavora con grandi quantità di dati. Le prestazioni nelle richieste tendono ad essere molto lineari e maggiori sono i dati da recuperare più tempo ci vorrà per recuperarli tutti.

+1

Ho fatto la query direttamente nel DB (mssql) e ci vogliono meno di 0,25 secondi per darmi i valori, i miei dati cambiano un sacco di volte in un giorno, quindi il caching non è il modo migliore, perché Posso prendere i dati memorizzati nella cache una o due volte e poi cambia di nuovo. L'impaginazione suona bene ma nel mio codice 'page' è sempre None così il' get_pagination_serializer' non viene mai toccato, come posso effettuare l'impaginazione? è più veloce? –

+0

Se si sta semplicemente eseguendo la query principale ('Blah.objects.all()'), allora mancano le query aggiuntive richieste per le relazioni. Dato che stai usando 'producto' e' ubicacion', devi fare altre domande per questi. Quindi se stai ricevendo un oggetto, devono essere fatte tre domande. Se ogni query richiede 100ms, sono 300ms. Se stai ricevendo 100 oggetti, sono solo 10 secondi nelle query. Questo è chiamato un problema di query N + 1, e sicuramente lo cercherò (e leggerò le risposte collegate). –

+0

Django REST Framework ha una paginazione integrata: http://www.django-rest-framework.org/api-guide/pagination –

7

Per me, le query del database N + 1 non si sono rivelate la risposta. Ci è voluto un pomeriggio di profilazione per individuare, ma dopo averlo fatto la risposta si è rivelata, frustrante, alcuni campi DecimalField nel mio serializzatore.

Il mio caso d'uso era semplice: 3000-4000 istanze che necessitavano di essere serializzate. Tutte le ottimizzazioni di select_related erano state eseguite, tuttavia vedevo ancora 2-3 secondi di tempo di serializzazione anziché i 0,5-5,5 secondi che mi aspettavo. Dopo alcune ore di tentativi ed errori (commentando/disapprovando i campi), ho visto un enorme calo (50%) in runtime quando avevo eliminato tutti i miei DecimalField.

La soluzione, per me, era di cambiare il mio DecimalField in FloatField. Certo che lo fai a costo di una perdita di precisione, ma per i miei scopi andava bene.

+0

Non riesco a trovare nient'altro che suggerisce perché DecimalField sarebbe così lento (lo so che è due anni fa). Oltre a modificare le definizioni dei campi dei modelli, esiste una soluzione diversa? – JohnO

Problemi correlati