Django et PostgreSQL sous la charge



Documents pareils
ECR_DESCRIPTION CHAR(80), ECR_MONTANT NUMBER(10,2) NOT NULL, ECR_SENS CHAR(1) NOT NULL) ;

Cours Bases de données 2ème année IUT

OpenPaaS Le réseau social d'entreprise

Langage propre à Oracle basé sur ADA. Offre une extension procédurale à SQL

La programmation orientée objet Gestion de Connexions HTTP Manipulation de fichiers Transmission des données PHP/MySQL. Le langage PHP (2)

NFA 008. Introduction à NoSQL et MongoDB 25/05/2013

SYSTÈMES D INFORMATIONS

Paginer les données côté serveur, mettre en cache côté client

Session S12 Les bases de l optimisation SQL avec DB2 for i

ISC Système d Information Architecture et Administration d un SGBD Compléments SQL

PHP et mysql. Code: php_mysql. Olivier Clavel - Daniel K. Schneider - Patrick Jermann - Vivian Synteta Version: 0.9 (modifié le 13/3/01 par VS)

Module Administration BD Chapitre 1 : Surcouche procédurale dans les SGBDS

Les bases de l optimisation SQL avec DB2 for i

CREATION WEB DYNAMIQUE

Performance web. Mesurer. Analyser. Optimiser. Benjamin Lampérier - Benoît Goyheneche. RMLL Beauvais. 8 Juillet 2015

Tutoriel de formation SurveyMonkey

Encryptions, compression et partitionnement des données

Modélisation PHP Orientée Objet pour les Projets Modèle MVC (Modèle Vue Contrôleur) Mini Framework

Mysql. Les requêtes préparées Prepared statements

Configurer la supervision pour une base MS SQL Server Viadéis Services

La présente publication est protégée par les droits d auteur. Tous droits réservés.

A.E.C. GESTION DES APPLICATIONS TECHNOLOGIE DE L'INFORMATION LEA.BW

laposte.net) Ministère de l'éducation nationale Atelier sécurité Rabat RALL 2007

1. Base de données SQLite

Olivier Mondet

Mysql avec EasyPhp. 1 er mars 2006

Bases de Données et Internet

Notes de cours : bases de données distribuées et repliquées

Compétences Business Objects

MS SQL Express 2005 Sauvegarde des données

Bases de données et sites WEB Licence d informatique LI345

SQL. Oracle. pour. 4 e édition. Christian Soutou Avec la participation d Olivier Teste

Principales failles de sécurité des applications Web Principes, parades et bonnes pratiques de développement

Plan Général Prévisionnel (1/2) (non contractuel) Internet et Outils L1/IO S2-IO2 Bases de données: Jointures, Transactions

Les déclencheurs. Version 1.0. Grégory CASANOVA

Bases de SQL. Hacks 1-6 CHAPITRE UN

8. Gestionnaire de budgets

Les bases de données

Cours 3. Développement d une application BD. DBA - Maîtrise ASR - Université Evry

COMMANDES SQL... 2 COMMANDES DE DEFINITION DE DONNEES... 2

Tests de montée en charge avec Tsung

Langage SQL (1) 4 septembre IUT Orléans. Introduction Le langage SQL : données Le langage SQL : requêtes

Programmation C++ (débutant)/instructions for, while et do...while

Bases de données avancées

Ora2Pg Performances. (C) 2013 Gilles Darold

Cours 8 Not Only SQL

PHP et les Bases de données - Généralités

PHP 5. La base de données MySql. A. Belaïd 1

L offre décisionnel IBM. Patrick COOLS Spécialiste Business Intelligence

Création et Gestion des tables

Pratique et administration des systèmes

algèbre requêtes relationnelles équivalentes méthodes de calculs équivalentes limites par les ressources : mémoire, disques, cpu...

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object)

Présentation Windows Azure Hadoop Big Data - BI

1. Qu'est-ce que SQL? La maintenance des bases de données Les manipulations des bases de données... 5

td3a correction session7az

Module Com231A - Web et Bases de Données Notion 5 : Formulaires et utilisation des Bases de Données avec PHP

Stockage du fichier dans une table mysql:

Le langage SQL pour Oracle - partie 1 : SQL comme LDD

Construire une application marketing Facebook sur la plateforme Windows Azure

Laboratoires de bases de données. Laboratoire n 6. Programmation SQL. par Danièle BAYERS et Louis SWINNEN

Optimisation SQL. Quelques règles de bases

Tous les autres noms de produits ou appellations sont des marques déposées ou des noms commerciaux appartenant à leurs propriétaires respectifs.

Baccalauréat technologique Série : sciences et technologies du management et de la gestion (STMG)

Bases de données et sites WEB

TP Bases de données réparties

Cours Bases de données 2ème année IUT

BASE. Vous avez alors accès à un ensemble de fonctionnalités explicitées ci-dessous :

Sécurité des applications web. Daniel Boteanu

Bases de données Outils de gestion

Base de données relationnelle et requêtes SQL

Le langage SQL (première partie) c Olivier Caron

Bases de Données Avancées PL/SQL

Procédures Stockées WAVESOFT ws_sp_getidtable Exemple : ws_sp_getnextsouche Exemple :... 12

Soon_AdvancedCache. Module Magento SOON. Rédacteur. Relecture & validation technique. Historique des révisions

Master Exploration Informatique des données DataWareHouse

Le Langage SQL version Oracle

Exercices sur SQL server 2000

ArcGIS 10.1 for Server

Gestion centralisée d un réseau de sites discrets. Nicolas JEAN

Sybase Adaptive Server Enterprise 15

Les Triggers SQL. Didier DONSEZ. Université de Valenciennes Institut des Sciences et Techniques de Valenciennes

OUTIL DE TRAVAIL COLLABORATIF

Attaques applicatives

STAGE IREM 0- Premiers pas en Python

Administration des bases de données. Jean-Yves Antoine

Bases de Données Réparties Concepts et Techniques. Matthieu Exbrayat ULP Strasbourg - Décembre 2007

Le Langage De Description De Données(LDD)

Introduction à ElasticSearch

Guide pour l Installation des Disques Durs SATA et Configuration RAID

Gestion de base de données

Paris Airports - Web API Airports Path finding

1-Introduction 2. 2-Installation de JBPM 3. 2-JBPM en action.7

Retour d'expérience migration Oracle vers PostgreSQL. Vincent Moreau Adeo Services

Application Form/ Formulaire de demande

Comment Accéder à des Bases de Données MySQL avec Windows lorqu'elles sont sur un Serveur Linux

SQL Server et Active Directory

Gestion des utilisateurs et de leurs droits

Transcription:

Django et PostgreSQL sous la charge Rodolphe Quiédeville Pourquoi couper la queue du poulet? RMLL - Beauvais 8 juillet 2015 Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 1 / 51

#mylife Admin/Sys tendance DevOps depuis 20 ans 84000 heures de connections au web Nourri au logiciel libre exclusivement Contributeur à Tsung Lead Architect chez PeopleDoc Consultant sur les performances des SI(G) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 2 / 51

2 mots sur PeopleDoc Métiers, dématérialisation des docuemnts RH Conservation des documents 50 ans 3 projets Django distincts 7 plateformes 3 clusters PostgreSQL par plateforme (9.4 et 9.1) une centaine de bases de données 50 Millions de documents, +100% tous les ans Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 3 / 51

Assistant pour cette présentation photo by InAweofGod screation flickr http://bit.ly/1ebqprq Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 4 / 51

Un dimanche matin dans la cuisine le petit Yohann demande à sa mère Maman pourquoi tu coupes la queue du poulet avant de le cuire dans le four? Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 5 / 51

La maman de répondre Je ne sais pas mais j ai toujours vu ma mère faire comme ça, vient on va demander à ta grandmère. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 6 / 51

Créer des données L import est le parent pauvre des optimisations, sous prétexte qu il se produit rarement, ou pas... Prenons un cas simple d import de 300K objets dans une base. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 7 / 51

Créer des données Ce qui vient en premier à l esprit, la boucle classique sur chaque élément create() def insert(values): """Insert values in DB """ for val in values: res = Item.objects.create(method="sequential", datetms=val[ datetms ], name=val[ name ], email=val[ email ], value=val[ value ]) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 8 / 51

Créer des données Il existe des méthodes pour l insertion en batch dans la doc de Django. bulk_create() def dobulk(part_values, method): """Do bulk insert on DB """ poms = [] for val in part_values: poms.append(item(datetms=val[ datetms ], method=method, name=val[ name ], email=val[ email ], value=val[ value ])) Item.objects.bulk_create(poms) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 9 / 51

Créer des données Il existe des méthodes pour l insertion en batch dans la doc de Django. bulk_create() def dobulk(part_values, method): """Do bulk insert on DB """ poms = [] for val in part_values: poms.append(item(datetms=val[ datetms ], method=method, name=val[ name ], email=val[ email ], value=val[ value ])) Item.objects.bulk_create(poms) Attention tout de même aux effets de bords possibles. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 9 / 51

Créer des données En utilisant l instruction COPY de PostgreSQL et un fichier temporaire (parfois inutile) cursor.copy_from def copyinsert(values, method): """Use COPY SQL FUNCTION to insert datas """ fields = [ datetms, name, email, value, method ] fpath = os.path.join( /tmp/, str(uuid4())) f = open(fpath, w ) for val in values: f.write( {},"{}","{}",{},{}\n.format(val[ datetms ], val[ name ], val[ email ], val[ value ], method)) f.close() cursor = connection.cursor() cursor.copy_from(open(fpath, r ), loader_item, columns=tuple(fields), sep=, ) unlink(fpath) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 10 / 51

Les résultats Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 11 / 51

Les résultats Un peu plus prêt des étoiles Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 12 / 51

Pourquoi bulk_create est plus rapide? Syntaxe courante INSERT INTO bar (value, ratio) VALUES (1, 3.4); INSERT INTO bar (value, ratio) VALUES (2, 5.4); INSERT INTO bar (value, ratio) VALUES (3, 3.14); Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 13 / 51

Pourquoi bulk_create est plus rapide? Syntaxe connue INSERT INTO bar (value, ratio) VALUES (1, 3.4); INSERT INTO bar (value, ratio) VALUES (2, 5.4); INSERT INTO bar (value, ratio) VALUES (3, 3.14); Syntaxe moins connue INSERT INTO bar (value, ratio) VALUES (1, 3.4), (2, 5.4), (3, 3.14); Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 14 / 51

Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 15 / 51

Yohann et sa maman demande à mère grand pourquoi elle coupait la queue du poulet avant de le cuire Je ne sais pas mais j ai toujours vu ma mère faire comme ça, on va demander à ta grand-mère. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 16 / 51

Yohann et sa maman demande à mère grand pourquoi elle coupait la queue du poulet avant de le cuire Je ne sais pas mais j ai toujours vu ma mère faire comme ça, on va demander à ta grand-mère. Par chance l arrière grand-mère de Yohann vit toujours, le voilà en route avec sa mère pour aller lui poser la question. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 16 / 51

Mettre à jour un lot de données Pendant que Yohann est sur la route nous allons augmenter les ratios de 5% des pommes qui ont un indice = 4 Le modèle class Apple(models.Model): """An apple """ name = models.charfield(max_length=300) indice = IntegerField(default=0) ratio = FloatField(default=0) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 17 / 51

Premier réflexe On lit et on boucle objs = Apple.objects.filter(indice=4) for obj in objs: obj.ratio = obj.ratio * 1.05 obj.save() Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 18 / 51

Premier réflexe On lit et on boucle objs = Apple.objects.filter(indice=4) for obj in objs: obj.ratio = obj.ratio * 1.05 obj.save() 1000 tuples dans la base ==> 1001 requêtes (ou pire) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 18 / 51

F comme Facile Au sens SQL cela revient à un UPDATE des plus classiques. SQL UPDATE apple_apple SET ratio=ratio * 1.5 WHERE indice=4; Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 19 / 51

F comme Facile Au sens SQL cela revient à un UPDATE des plus classiques. SQL UPDATE apple_apple SET ratio=ratio * 1.5 WHERE indice=4; update et F objs = Apple.objects.filter(indice=indice).update(ratio=F( ratio )*1.05) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 19 / 51

F comme Facile Au sens SQL cela revient à un UPDATE des plus classiques. SQL UPDATE apple_apple SET ratio=ratio * 1.5 WHERE indice=4; update et F objs = Apple.objects.filter(indice=indice).update(ratio=F( ratio )*1.05) 1 requête SQL exécutée au lieu de 1001, succès garantit Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 19 / 51

Pagination Et si pour paginer on utilisait Paginator? Avant apples = Apple.objects.all().order_by( pk ) paginator = Paginator(apples, 250) for p in paginator.page_range: for apple in paginator.page(p).object_list: apple.ratio = apple.ratio * 1.05 apple.save() Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 20 / 51

Pagination Et si pour paginer on utilisait Paginator? Avant apples = Apple.objects.all().order_by( pk ) paginator = Paginator(apples, 250) for p in paginator.page_range: for apple in paginator.page(p).object_list: apple.ratio = apple.ratio * 1.05 apple.save() Ceci est une situation tirée de faits réels Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 20 / 51

Pagination Key pagination keyid = 0 while True: apples = Apple.objects.filter(id gt=keyid).order_by( id )[:250] for apple in apples: keyid = apple.id # do want you want here apple.ratio = apple.ratio * 1.05 apple.save() if len(apples) < 250: break Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 21 / 51

Pagination Key pagination keyid = 0 while True: apples = Apple.objects.filter(id gt=keyid).order_by( id )[:250] for apple in apples: keyid = apple.id # do want you want here apple.ratio = apple.ratio * 1.05 apple.save() if len(apples) < 250: break Django crée par défaut des clés primaires, ça tombe bien on en a besoin ici Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 21 / 51

La table tient en cache Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 22 / 51

La table dépasse la taille du cache Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 23 / 51

Si vous parcourez des tables de grandes volumétrie, vous devez oublier OFFSET. Lisez l excellent livre de Markus Winnand pour découvrir la pagination par clée et la joyeuse vie des index. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 24 / 51

Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 25 / 51

Yohann arrivé chez son arrièregrand-mère, la questionne sans attendre. Dit moi grand-grandmamie pourquoi tu coupes la queue du poulet avant de le cuire? Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 26 / 51

L arrière grand-mère de répondre Oh mon petit t es ben mignon, mais ça chais pus ben moé, ch crai bi que j a toujours vu ma mè fai r ainsi. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 27 / 51

L arrière grand-mère de répondre Oh mon petit t es ben mignon, mais ça chais pus ben moé, ch crai bi que j a toujours vu ma mè fai r ainsi. Par chance l arrière-arrière-grandmère de Yohann vit toujours, le voilà une nouvelle fois sur la route avec sa mère pour aller glaner la précieuse information auprès de sa trisaïeule. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 27 / 51

Pendant ce temps là, interessons-nous à la lecture de nos données modèle BigBook class BigBook(models.Model): """The big books """ keyid = models.integerfield(unique=true) author = models.foreignkey(author) title = models.charfield(max_length=30) serie = models.integerfield(default=0) nbpages = models.integerfield(default=0) editors = models.manytomanyfield(editor, blank=true) translators = models.manytomanyfield(translator, blank=true) synopsis = models.textfield(blank=true) intro = models.textfield(blank=true) On va faire une action sur 10% de la table environ, une opération de mise à jour conditionnelle Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 28 / 51

SQL books = BigBook.objects.filter(serie=3).order_by( keyid ) for book in books: keyid = book.keyid # do want you want here if book.nbpages > 500: book.action() Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 29 / 51

SQL books = BigBook.objects.filter(serie=3).order_by( keyid ) for book in books: keyid = book.keyid # do want you want here if book.nbpages > 500: book.action() Dans la méthode.action() on a besoin uniquement du keyid et de nbpages. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 29 / 51

SQL books = BigBook.objects.filter(serie=3).order_by( keyid ) for book in books: keyid = book.keyid # do want you want here if book.nbpages > 500: book.action() Dans la méthode.action() on a besoin uniquement du keyid et de nbpages. SQL >>> BigBook.objects.filter(serie=3).order_by( keyid ) SELECT "july_bigbook"."id", "july_bigbook"."keyid", "july_bigbook"."author_id", "july_bigbook"."title", "july_bigbook"."serie", "july_bigbook"."nbpages", "july_bigbook"."synopsis", "july_bigbook"."intro" FROM "july_bigbook" WHERE "july_bigbook"."serie" = 3 ORDER BY "july_bigbook"."keyid" LIMIT 21 [127.64ms] Execution time : 127.64ms Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 29 / 51

Ré-écriture de la queryset books = BigBook.objects.only( keyid, nbpages ).filter(serie=3).order_by( keyid ) for book in books: keyid = book[ keyid ] # do want you want here if book[ nbpages ] > 500: book.action() Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 30 / 51

Ré-écriture de la queryset books = BigBook.objects.only( keyid, nbpages ).filter(serie=3).order_by( keyid ) for book in books: keyid = book[ keyid ] # do want you want here if book[ nbpages ] > 500: book.action() SQL >>> BigBook.objects.only( keyid, nbpages ).filter(serie=3).order_by( keyid ) SELECT "july_bigbook"."id", "july_bigbook"."keyid", "july_bigbook"."nbpages" FROM "july_bigbook" WHERE "july_bigbook"."serie" = 3 ORDER BY "july_bigbook"."keyid" LIMIT 21 [1.53ms] Execution time : 1.53ms Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 30 / 51

Avec effets secondaires depuis PostgreSQL 9.3 SQL >>> BigBook.objects.only( keyid, nbpages ).filter(serie=3).order_by( keyid ) SELECT "july_bigbook"."id", "july_bigbook"."keyid", "july_bigbook"."nbpages" FROM "july_bigbook" WHERE "july_bigbook"."serie" = 3 ORDER BY "july_bigbook"."keyid" LIMIT 21 [1.53ms] Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 31 / 51

Avec effets secondaires depuis PostgreSQL 9.3 SQL >>> BigBook.objects.only( keyid, nbpages ).filter(serie=3).order_by( keyid ) SELECT "july_bigbook"."id", "july_bigbook"."keyid", "july_bigbook"."nbpages" FROM "july_bigbook" WHERE "july_bigbook"."serie" = 3 ORDER BY "july_bigbook"."keyid" LIMIT 21 [1.53ms] EXPLAIN QUERY PLAN -------------------------------------------------------------------------------------- Sort (cost=162.31..162.31 rows=1 width=12) (actual time=0.628..0.628 rows=0 loops=1) Sort Key: keyid Sort Method: quicksort Memory: 25kB -> Seq Scan on july_bigbook (cost=0.00..162.30 rows=1 width=12) Filter: (serie = 3) Rows Removed by Filter: 3784 Planning time: 0.161 ms Execution time: 0.651 ms (8 rows) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 31 / 51

Avec effets secondaires depuis PostgreSQL 9.3 SQL CREATE INDEX magic ON july_bigbook(id, serie, keyid, nbpages); Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 32 / 51

Avec effets secondaires depuis PostgreSQL 9.3 SQL CREATE INDEX magic ON july_bigbook(id, serie, keyid, nbpages); EXPLAIN QUERY PLAN ------------------------------------------------------------------------------------------- Sort (cost=98.43..98.44 rows=1 width=12) (actual time=0.150..0.150 rows=0 loops=1) Sort Key: keyid Sort Method: quicksort Memory: 25kB -> Index Only Scan using magic on july_bigbook (cost=0.28..98.42 rows=1 width=12) Index Cond: (serie = 3) Heap Fetches: 0 Planning time: 0.199 ms Execution time: 0.177 ms (8 rows) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 32 / 51

Avec effets secondaires depuis PostgreSQL 9.3 SQL CREATE INDEX magic ON july_bigbook(id, serie, keyid, nbpages); EXPLAIN QUERY PLAN ------------------------------------------------------------------------------------------- Sort (cost=98.43..98.44 rows=1 width=12) (actual time=0.150..0.150 rows=0 loops=1) Sort Key: keyid Sort Method: quicksort Memory: 25kB -> Index Only Scan using magic on july_bigbook (cost=0.28..98.42 rows=1 width=12) Index Cond: (serie = 3) Heap Fetches: 0 Planning time: 0.199 ms Execution time: 0.177 ms (8 rows) 0.651ms à 0.177ms sur seulement 4K tuples Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 32 / 51

Du coté des templates Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 33 / 51

Un template classique Du coté des templates {% if object_list.count %} <b>found projets : {% object_list.count %}</b> <div>projets : <ul> {% for projet in object_list %} <li>{{projet.name}}</li> {% endfor %} </ul> </div> {% endif %} Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 33 / 51

Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 34 / 51

with Une solution ici serait d utiliser with pour éviter de refaire les mêmes requêtes plusieurs fois. Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 35 / 51

with Une solution ici serait d utiliser with pour éviter de refaire les mêmes requêtes plusieurs fois. Python {% with Projets=object_list.all %} {% if Projets.count %} <b>found projets : <ul>{% Projets.count %}</b> <div>projets : <ul> {% for projet in Projets %} <li>{{projet.name}}</li> {% endfor %} </ul> </div> {% endif %} {% endwith %} Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 35 / 51

Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 36 / 51

Dans la même logique nous avons les propriétés des ForeignKey Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 37 / 51

Propriétés des ForeignKey Le modèle class Banana(models.Model): name = models.charfield(max_length=300) variety = models.foreignkey(variety) La view class BananaRelatedListView(ListView): model = Banana paginate_by = 10 Le template {% for object in object_list %} <tr> <td>{{object.name}}</td> <td>{{object.variety.name}}</td> </tr> {% endfor %} Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 38 / 51

Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 39 / 51

On affiche des informations liées au modèle principal, pourquoi ne pas utiliser select_related Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 40 / 51

On affiche des informations liées au modèle principal, pourquoi ne pas utiliser select_related Python class BananaRelatedListView(ListView): model = Banana paginate_by = 10 def get_queryset(self): bananas = Banana.objects.all().select_related() return bananas Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 40 / 51

Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 41 / 51

cas simple, petite volumétrie passe de 76 à 50msec Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 42 / 51

cas simple, petite volumétrie passe de 76 à 50msec forte volumétrie, facteur 10x voir 50x Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 42 / 51

cas simple, petite volumétrie passe de 76 à 50msec forte volumétrie, facteur 10x voir 50x les templates sont ma première source d intérêt sur un projet avec des problèmes de performance Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 42 / 51

Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 43 / 51

le modèle Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 44 / 51

le modèle la view Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 44 / 51

le modèle la view le template Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 44 / 51

Le point de vue des performances le modèle, les méthodes sont explicites (en limitant les niveaux d héritages) Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 45 / 51

Le point de vue des performances le modèle, les méthodes sont explicites (en limitant les niveaux d héritages) la view, vous maîtrisez get_queryset() et surchargez get_context_data() Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 45 / 51

Le point de vue des performances le modèle, les méthodes sont explicites (en limitant les niveaux d héritages) la view, vous maîtrisez get_queryset() et surchargez get_context_data() le template, que va faire le.count? Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 45 / 51

Confrontations d idéologies point Godwin Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 46 / 51

Confrontations d idéologies point Godwin point raw sql Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 46 / 51

Cas ultime votre application reçoit une request. par exemple /blog/api/articles/ GET votre application décode la requête et va contacter votre base de données pour récupérer les lignes correspondant aux 10 premiers articles. Django va convertir ces lignes en objet python votre serializer va convertir ces objets python en JSON votre application va retourner un payload JSON. sur une idée originale de Y. Gabory, https://gitlab.com/boblefrag/livre_django_perf Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 47 / 51

Cas ultime Le template from blog.models import Article from django.views.generic import ListView from django.core import serializers from django import http from django.db import connection from psycopg2 import extras extras.register_default_json(loads=lambda x: x) class AJAXListMixin(object): def get_queryset(self): c = connection.cursor() c.execute(""" SELECT array_to_json(array_agg(row_to_json(t))) FROM( SELECT * FROM blog_article LIMIT 10) t """) return c.fetchone() def render_to_response(self, context, **kwargs): response = http.httpresponse(self.get_queryset()) for t in connection.queries: print t return response class ArticleView(AJAXListMixin, ListView): model = Article paginate_by = 10 Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 48 / 51

Yohann est arrivé, va-t il avoir la réponse à sa question? Grand-grand-Maman pourquoi tu coupes la queue du poulet avant de le cuire? Milles merci à Bruno Bord pour cette histoire Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 49 / 51

Yohann est arrivé, va-t il avoir la réponse à sa question? Grand-grand-Maman pourquoi tu coupes la queue du poulet avant de le cuire? Parce qu à l époque les fours étaient trop petit, et le poulet ne pouvait pas entrer en entier. Milles merci à Bruno Bord pour cette histoire Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 49 / 51

Avec le temps Nous aurions aussi évoqué : django-json-dbindex django-aggtrigg django-hstore djorm-pgarray Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 50 / 51

Questions? On recrute! Rodolphe Quiédeville rodolphe.quiedeville@people-doc.com Document publié sous Licence Creative Commons BY-SA 2.0 Rodolphe Quiédeville (PeopleDoc) Django et PostgreSQL sous la charge 8 juillet 2015 51 / 51