Clickez pour obtenir d'autres articles sur les thèmes suivant :
envoyer à un ami
Clickez ici pour envoyer ce papier à un ami (ou à un ennemi, selon votre état d'esprit).
Version imprimable
Clickez ici pour la version imprimable. Mais si vous aimez les arbres, préférez la version électronique (PDF) juste à côté...
Version PDF Amoureux de la nature, clickez-ici (ou scannez le QR code) obtenir une version PDF.
Version qrcode Scannez ce QR code pour lire cet article sur votre mobile.
Drupal, Views et les dangers du clickodrome....
le lun, 29/06/2009 - 20:40 dans Drupal

Je l'avoue bien volontier, j'ai mis du temps à reconnaître que CCK était un outil réellement indispensable. Il n'y a que les imbéciles qui ne changent pas d'avis dit le dicton. Mais s'il est un module qui continue après tout ce temps à me laisser comme une poule devant un couteau, c'est bien Views. Et encore, c'était avant d'étudier d'un peu plus près les performances de la bête...

Cas d'école

Raison de mon énervement passager, une vue prise "au hasard" parmi plus de 140 (ouch!) sur un projet qui souffre de quelques lenteurs... Un vue toute simple présentée sous la forme d'un bloc contenant une liste elle-même issue d'une pauvre requête sensée renvoyer 1 enregistrement avec comme critères un type du noeud, une date CCK dans le passé et un tri par date décroissante. Pas le Pérou donc, et pourtant il faut pas moins de 230ms à Views pour générer cette petite vue. Relativement lent donc au regard du travail effectué, ce sera donc le cas pratique que j'utiliserais pour comprendre ce qui se passe.

La requête SQL

Pour voir un peu la tête de la requête générée, il est possible soit d'utiliser l'aperçu de Views2, soit, plus simplement, de mettre des traces en sortie de db_query. Voilà ce que cela donne :

SELECT
 DISTINCT(node.nid) AS nid,
 node_data_field_contenu_1.field_contenu_1_nid AS node_data_field_contenu_1_field_contenu_1_nid,
 node.type AS node_type,
 node.vid AS node_vid,
 node_data_field_contenu_1.field_contenu_2_nid AS node_data_field_contenu_1_field_contenu_2_nid,
 node_data_field_contenu_1.field_contenu_3_nid AS node_data_field_contenu_1_field_contenu_3_nid,
 node_data_field_contenu_1.field_contenu_4_nid AS node_data_field_contenu_1_field_contenu_4_nid,
 node_data_field_contenu_1.field_contenu_5_nid AS node_data_field_contenu_1_field_contenu_5_nid,
 node_data_field_contenu_1.field_contenu_6_nid AS node_data_field_contenu_1_field_contenu_6_nid,
 node_data_field_date.field_date_value AS node_data_field_date_field_date_value
FROM node node
LEFT JOIN content_field_date node_data_field_date ON node.vid = node_data_field_date.vid
LEFT JOIN content_type_une node_data_field_contenu_1 ON node.vid = node_data_field_contenu_1.vid
WHERE
 ((node.type IN ('tagazok')) AND (node.STATUS <> 0))
 AND (DATE_FORMAT(STR_TO_DATE(node_data_field_date.field_date_value, '%Y-%m-%dT%T'), '%Y-%m-%d\\T%H:%i:%s') <= '2009-06-30T00:55:00')
ORDER BY node_data_field_date_field_date_value DESC
LIMIT 0,1
Requêtes à la Views

Avouons déjà que c'est tout de même très moche, et à ceux qui me dirait "mais c'est pas grave, on le voit pas", je répondrais "le code HTML de MS-Word aussi personne ne le voit, pourtant y'en a plein que ça défrise...".

Mais au delà de ces considérations esthétiques propres à chacun, voyons ce que nous avons dans notre besace à la Prévert:

  • Un aliasing inutile de tous les champs (jusqu'à un node node bien mignon)
  • Une condition de barbare pour sélectionner une simple date dans le passé.
  • Un recherche dans un ensemble d'une seule valeur (node.type in ('tagazok')).
  • La remontée d'une tripotée de champs sans intérêt alors que seuls les field_contenu_XXX étaient demandés.
  • Un Distinct qui fait joli avec le limit 0,1.

Nous ne pouvons pas faire grand chose sur la condition barbare, mais voyons à quoi ressemblerait un code SQL débarrassé du reste de joyeusetés. Il ne s'agit pas vraiment d'optimisation mais juste d'un petit nettoyage printanier.

SELECT b.* FROM node n
LEFT JOIN content_field_date a ON n.vid = a.vid
LEFT JOIN content_type_une b ON n.vid = b.vid
WHERE
 n.type='tagazok' AND
 n.STATUS <> 0 AND
 (DATE_FORMAT(STR_TO_DATE(a.field_date_value, '%Y-%m-%dT%T'), '%Y-%m-%d\T%H:%i:%s') <= '2009-06-29T18:38:49')
ORDER BY a.field_date_value DESC
LIMIT 1
requête à la main

MySQL le fautif ?

Notre premier test consistera donc à voir si les performances diffèrent significativement entre des deux requêtes. Pour ce faire, j'ai simplement crée un script Drupal procédant à 1000 exécutions de chacune des deux requêtes :

RequêteItérationsTemps
Views10000.54
Manuelle10000.47

Déjà rien que là, on a gagne 13.3% de performances ce qui est assez inquiétant. En effet, d'un point de vue purement sémantique, les deux requêtes sont tout de même très proches l'une de l'autre, et les bases de données sont sensées gommer ce genre de détail à travers leur module d'optimisation. J'aurais donc tendance ici à aller taper sur l'optimisateur de requête de MySQL qui semble bien en deçà de ce que l'on a l'habitude de trouver sur une base Oracle ou même PostgreSQL.

Le choix des types de champ

Ceci étant dit, nous parlons là de 13% et cela n'explique pas que le rendu soit si lent. ce qui n'est rien en comparaison de ce que nous coûte la condition barbare. En effet, si l'on retire cette horreur, c'est un gain de 39% que nous obtenons...

Ici Views n'est qu'une victime d'un petite désastre vienant de CCK. En effet, pour gérer les dates dans les contenus, CCK implique l'utilisation du module Date API). Ce dernier lui fournit trois types de date possibles : Date, DateStamp et TimeDate. Chacun de ces types a sa propre représentation interne en base de données. Le type Date n'est rien d'autre qu'un VARCHAR2, DateStamp est un entier contenant un timestamp UNIX et DateTime correspond au type "date" du SGBD.

Du coup, en choisissant le type Date pour un champ, on oblige chaque requête devant implémenter une condition sur ce champ, à jongler entre la représentation textuelle de la date et sa représentation "entière". Des conversions qui ont un coût non négligeable à additionner à celui de devoir travailler sur un plus grand volume de données.

Le type "Date" pour un champ CCK est donc à éviter à tout prix car sinon au profit d'un DateStamp.

Le coût du click

Mais le plus intéressant n'est pas encore là. Pour avoir une vision complète, il nous faut comparer cette fois les vitesses de rendu du bloc views, celui impliqué par en gros 20 lignes de PHP dans un module.

Rendu de blocItérationsTempsselectdeleteinsertupdate
Par Views1002.3153101020
Par un module custom1000.07100000

Notez pour l'échelle de grandeur, que le premier teste (SQL) a été répété 1000 fois pour obtenir ces temps, et seulement 10 fois pour ceux portant sur la génération des blocs. Et là nous sommes juste à 96.4% de performances supplémentaire en faveur de nos 20 lignes de PHP.

Alors pourquoi ? Une partie de la réponse se trouve dans les colonnes suivantes. Disons que pour une simple liste générer 5.3 requêtes SELECT, 1 requête DELETE, 2 requêtes UPDATE et 1 requêtes INSERT, ne peut pas, avec la meilleur bonne volonté du monde, donner de bons résultats.

C'est un peu la quadrature du cercles cette histoire, il faut des requêtes pour remonter les modèles de vues stockées en base, qui vont permettre à grand coups de hooks et de plugins (et donc de temps CPU), de générer une requêtes SQL que l'on va, à grand coups de hooks et de plugins formater en une simple liste à puces. Et comme tout ceci prend du temps, on rajoute en plus des couches de cache pour cacher la misère (les INSERT/DELETE/UPDATE). Tout cela pour s'éviter de rédiger 20 lignes de PHP, c'est un peu dur.

Le cache de block ne sauvera personne

Après j'en entend qui disent "pas grave, y'a le cache de blocks, et puis si c'est pas suffisant, y'a le cache de page". Certes, mais déjà le cache de page ne fonctionne que pour les visiteurs anonymes et celui de block fait ce qu'il peut avec les authentifiés.

Ensuite les caches de bloc ET de page sont virés dès qu'un contenu et/ou commentaire est ajouté. Autant dire que sur un site à gros trafic il ne faut pas trop y compter. Si si, je vous assure... Ligne 776 de comments.module :

// Clear the cache so an anonymous user can see his comment being added.
cache_clear_all();

Et si l'on regarde la fonction cache_clear_all() :

if (!isset($cid) && !isset($table)) {
  // Clear the block cache first, so stale data will
  // not end up in the page cache.
  cache_clear_all(NULL, 'cache_block');
  cache_clear_all(NULL, 'cache_page');
  return;
}

Et voilà...

Conclusion

Autant Views est clairement plus lent qu'un travail fait proprement à la main, autant il ne faut pas non plus jeter le bébé avec l'eau du bain. Pour de petits sites tranquilles ce module permet à un non-développeur de fabriquer sans connaissance particulières ses propres listes, flux, blocs, etc... Maintenant pour un site "pro", il faut clairement réfléchir un peu avant de coller cela sur une home-page.

Pour le reste, Views est une redoutable documentation interactive permettant en quelques clicks de comprendre la construction de requêtes un peu tordues du genre "comment avoir la liste des contenus ayant les meilleurs notes et écrits par mes amis". Rien que pour cela je lui suis redevable Smile

Les commentaires

Damien , le lun, 29/06/2009 - 23:07

"Un recherche dans un ensemble... d'une seule valeur (node.type in ('tagazok'))"
ça normalement avec un SGBD digne de ce nom ça n'a pas d'impact.

Moi ce qui me choque dans cette requête, c'est la condition sur DATE_FORMAT(STR_DATE()) que je soupçonne être responsable d'un scan complet de la table lors de l'exécution. Un petit EXPLAIN serait intéressant. Sinon c'est vrai que le "FROM node node" est très marrant Smile

Yoran, le mar, 30/06/2009 - 01:17

Ban, j'ai tenté une session de rattrapage pour ce pov' Views en allant chercher la "vraie" requête qu'il faut en base. C'est un peu mieux que ce qu'il prétend sur l'interface, il y a bien un LIMIT. Du coup les perfs c'est légèrement meilleur que pour le premier test. En revanche, j'ai un peu halluciné lorsque j'ai rajouté des compteurs d'INSERT/UPDATE/DELETE/SELECT. On marche un peu sur la tête là...

Sinon, pour le coup du "in", lorsqu'il s'agit de mySQL, je reste méfiant. Si tu regardes ma requête faite "à la main" et la version "views", il n'y a rien que l'optimisateur d'un Oracle ou d'un postgreSQL n'aurait remis proprement à plat. Le cas des alias est assez flagrant car rien qu'en faisant voler ces "longueurs" on gagne en performances. En somme tout doit tenir dans ton "un SGBD digne de ce nom" Wink

Pour le coup de la condition barbare, moi ce qui me choque c'est que DATE API trouve malin de fournir des dates stockés sous forme de chaîne de caractère... On peut critiquer le choix d'un timestamp (ce que Drupal utilise partout) au profit d'un TimeDate propre à la base, mais une chaîne, c'est totalement indéfendable. Et encore là, il n'y a qu'une condition, je n'ose pas imagine ce que cela donne avec un ou deux intervalles de dates... Et c'est là qu'on touche au gros malaise avec CCK, pas possible de migrer les champs d'un type à l'autre sans se frapper la moulinette qui va bien...

Narno, le mar, 30/06/2009 - 13:20

En effet, ça n'est pas nouveau : le module Views est fortement critiqué pour 2 choses : son UI flippante et ses performances médiocres.
Ton analyse est très intéressante, mais quelles pistes d'évolutions/corrections donnerai tu au(x) maintainer(x) ? Ce module est génial dans le principe et dans l'utilisation (une fois l'interface amadouée, on est d'accord) : alors que pourrions nous faire pour le transformer en réelle killer app ? Smile

Yoran, le mar, 30/06/2009 - 14:10

Tu vas dire que je prêche pour ma paroisse Smile Mais si tu es mainteneur sur un gros projet, j'ai du mal à envisager son équipe sans un développeur capable de coder une requête SQL et les 10 lignes de PHP qui vont avec. Si c'est un moindre projet, les performances de Views ne sont en soit pas un problème.

Sinon pour ce qui est des pistes d'évolution, franchement je n'y crois pas beaucoup. Views est en gros un modeleur de requête comme tu en as dans Access depuis plus de 10ans. Cela n'a jamais fait de miracles ni remplacé une requête à la mano, mais ça fonctionne. Pour views, tu rajoutes en plus la complexité des modules contributions avec chacun leur schéma de table. Là ça devient pour le moins coton...

Maintenant pour être constructif, ce que je verrais bien dans Drupal c'est :
- un "DataSource API". L'idée est de pouvoir ajouter des sources de données prise en charge par des modules implémentant l'API (ex. datasource_sql, ou datasource_rss, etc..). Le mainteneur peut ainsi créer les datasources qu'il désire et pourquoi pas les combiner à la yahoo pipes.
- un "Presentation API". L'idée pour le mainteneur est de faire créer des connexion entre une source de donnée, et un module de "presentation" (ex. presentation_bloc, presentation_rss, presentation_page, etc.).

En adoptant ce principe, Views n'est plus qu'une interface graphique permettant de simplifier la génération de requêtes SQL. Le développeur peut ensuite optimiser cette requête pour un datasource donné. Il peut aussi créer des présentations "custom".

Bref, avec du temps, on en fait des choses Smile Moi pour l'instant je me suis fait un module d'une bêtise grave, façon "nouveau type de contenu" avec un champ supplémentaire pour coller une requête SQL. Avec cela je génère toutes mes listes et je n'ai pas les contraintes de Views comme le fait de ne pas pouvoir appliquer le module printer (et donc les sorties pdf). Et ça répond à 99% de mes besoins Smile

coreight , le mar, 08/09/2009 - 10:34

Bonjour et merci pour cet article très intéressant.

Utilisateur de Drupal depuis peu, je me suis rapidement rendu compte des limites de Views pour effectuer des requêtes "tordues" (du style trier une table selon un champ pour en extraire les 10 premieres entrées, puis trier ces 10 entrées selon un autre champ => je ne vois pas vraiment comment faire avec le module)

Indépendemment de la plus grande facilité de coder ça "à la main", le critère de performance que vous évoquez içi conforte largement mon idée de me passer de views.

Cependant je me demande quelle est la méthode la plus efficace pour insérer son propre code, mes recherches me donnent des résultats différents : certains ne jurent que par la création de modules dédiés, ce qui me parait très lourd. La solution que vous présentez - nouveau type de contenu avec un champ pour la requête - me parait idéale.

Quels sont les inconvénients de cette méthode ? (pourquoi "bêtise grave"?)

 

Merci d'avance

Yoran, le jeu, 10/09/2009 - 11:28

Pour médiapart j'ai expérimenté plusieurs méthodes.

1/ L'approche par module pure est effectivement trop lourde. Le module doit être envisagé comme une unité de sens, ce qui entraîne une multiplication peu productive des petits pains Wink

2/ L'approche "type de contenu liste" marche pas mal du tout mais est un peu restreinte en terme de formatage des résultat sauf à étendre exagérément le paramétrage du dit type de contenu.

3/ L'approche "librairie" est celle que j'ai retenue. J'ai un module "datasource" qui contient une série de fonction de haut niveau (un datasource qui contient la partie SQL, les paramètres, la pagination, etc) me permettant de construire des requêtes génériques et d'en exploiter rapidement le résultat (ex. Créer un flux RSS ou une carte Google à partir du datasource XXX). Avec cette aproche, et en utilisant comme base les requêtes gracieusement fournies par les anciennes vues views, on a converti très rapidement les centaines de vues du projet.

La "bétise grave" fait ici référence à la simplicité du module (3). personnellement je n'ai pas vu d'inconvénient à cette méthode si ce n'est savoir coder en SQL et avoir une bonne connaissance du schéma de base de données.

 

robin , le mar, 30/06/2009 - 14:19

excellente analyse, mais la réalité est là : Views est absolument indispensable ... enfin, disons que sur tous les projets web en Drupal que j'ai monté, j'en ai toujours eu besoin à un moment ou à un autre, alors ... peut être que la solution provisoire est d'optimiser le serveur pour augmenter la performance des requêtes (ce que tout le monde ne sait pas faire, moi le premier) ?

Yoran, le mar, 30/06/2009 - 16:54

Je ne vois pas bien en quoi il est indispensable. Drupal a une API super bien fichue qui perment en 20 lignes (10 c'était un peu exagéré) de faire exactement la même chose qu'un bloc views avec en gain la vitesse, et le contrôle.

function mon_module_block($op = 'list', $delta = 0, $edit = array ()) {
  switch ($op) {
    case 'list' :
      return array (
        'ma_liste' => t('Ma liste'),
        'cache' => BLOCK_CACHE_GLOBAL
      );

    case 'view' :
      if ($delta == 'ma_liste') {
        $cursor = db_query("SELECT nid FROM node where bla bla");
        while ($node = db_fetch_object($cursor)) {
          $node = node_load($node->nid);
          $output .= "<li>" . l($node->title, "node/" . $node->nid) . "</li>";
        }
        return array (
          'subject' => t("Ma list"),
          "<ul>$output</ul>"
        );
      }
  }

Alors je sais pas, c'est peut-être une question de personnalité mais je préfère passer un peu de temps à comprendre cette API qu'un temps clairement équivalent à capter l'IHM de Views Smile

montesq , le dim, 05/07/2009 - 10:46

Effectivement le bout de code fait autant l'affaire et a l'avantage d'être propre...
Toutefois, pour moi l'intérêt de views se révèle plus dans l'affichage sous forme de tableau avec la gestion de la pagintation, les headers de colonnes cliquables pour trier la liste, les critères de recherche...
Et là tu ne me feras pas croire que tu peux faire cela en 20 lignes de codes (ou alors je suis passé à côté de quelque chose)!
@+

Yoran, le dim, 05/07/2009 - 19:04

Mais quant je dis que Drupal est un framework de malade Wink

Alors tu disais ? tableau, pagination, header cliquables pour les tris...

function mon_module_tablea_callback() {
  $header = array(
    array('data' => t('Title'), 'field' => 'title', 'sort' => 'asc'),
    array('data' => t('author'), 'field' => 'u.uid'));

  // Requête triées en fonction de l'en-tête
  $query='SELECT r.*,u.*  FROM node n  
          INNER JOIN node_revisions r ON r.vid=n.vid
          INNER JOIN users u ON u.uid=n.uid  
          WHERE n.promote = 1 AND n.status = 1'
;
  $result = pager_query($query.tablesort_sql($header), 10);

  // Population du tableau
  $rows=array();
  while ($node = db_fetch_object($result))
     $rows[] = array($node->title, theme('username', $node));

  // Theming du tableau et du pager
  return theme('table', $header, $rows).theme('pager', NULL, 10, 0);
}

voilà, voilà... Smile 20 lignes tout rond, commentaires, déclaration de callback et lignes sautés comprises. Pour les critères de recherche faut juste un chtit formulaire en plus, rien de bien sorcier.

En plus, comme tu le vois, une bonne partie de ce code est totalement générique. Tu peux ainsi assez facilement faire une fonction qui prend en paramètre le header et la requête pour fabriquer la page au complet. Il y aurait juste à améliorer le header pour ajouter le thème à utiliser pour formater la donnée de la cellule (si ce n'est pas déjà une fonction existante, je n'ai pas vérifié). C'est d'ailleurs en gros ce que fait views, on zappe juste l'aspect paramétrage qui lui coûte du temps.

Mais entendons nous bien, s'il fallait maîtriser les API drupal pour l'utiliser, ça lui couperait un large publique, et en cela Views est parfait. Mon seul point depuis le début est que dans le cas d'un site qui nécessite du temps et des moyens, faire l'économie d'un développeur et utiliser views partout est un peu dommage. La seule chose que je cherche à montrer ici c'est que c'est faisable, pas terriblement compliqué, très performant et qu'en plus cela démontre la puissance du framework.

montesq , le dim, 05/07/2009 - 22:05

Trop la classe cette solution!
Je suis complètement convaincu maintenant.
Je préfère autant avoir un module permettant d'avoir une degré de custo maximum en utilisant un code simple et propre plutôt que perdre du temps à comprendre l'UI de views qui est loin d'être intuitive et contestable en matière d'ergonomie (forcément quand on veut atteindre un grand degré de liberté, on perd sur la simplicité). Quid de la pérennité des 2 solutions sur un changement de version de Drupal?

Yoran, le dim, 05/07/2009 - 23:51

Tu m'en vois ravi Smile

Pour le degré de pérénité, je vais juste prendre un exemple. Lorsque Views est passé de la version 1 à la version 2, la conversion n'a pas pu être réalisée de manière automatique lors du processus de mise à jour du module. Du coup, pour un site utilisant une centaine de Drupal 5/views version 1, la migration views2/Drupal 6 a consisté à convertir à la manu (avec l'utilitaire fourni par Views2) les 100 vues une à une, en vérifiant à chaque fois que ça fonctionnait, et en devant changer des tas de trucs qui ne passaient plus. En gros, une semaine de boulot.
Dans le même esprit, avec un module qui contiendrait 100 vues écrites à la mains (ce qui serait idiot, cf factorisation de code), dans l'éventualité improbable ou l'API change radicalement (généralement c'est un paramètre en plus ou en moins), je te laisse imaginer le temps que ça prendrait avec un bon éditeur.
Et ceci sans compter qu'une fois que tu as migré tes vues sur ta machine de dev, faut refaire les exports/imports sur la machine de prod en priant St Gretta que tout passe correcte. Tandis que dans du code, ma foi...
Maintenant cela ne m'empêche pas d'utiliser Views à haute dose, pour me générer des requêtes un peu tordues entre les données de plusieurs modules, que je colle ensuite après nettoyage dans un module Smile

Sylvain , le mer, 04/11/2009 - 08:15

je débute avec Drupal. Je suis sur drupal 5 actuellement, j'ai créé des fonctions, je les ai placé dans template.php

maintenant ma question est comment appelle t on ces fonctions ?

ma fonction montheme_test() par exemple comment puis je l'appeler pour la déclancher sur une page précise ?

Yoran, le mer, 04/11/2009 - 08:35

Je pense que tu devrais poser ta question sur le forum drupalfr.org, section "développement", cela permettrait aux autres de profiter de la réponse.

Pour lier une fonction PHP (appelée callback) avec une chemin (étrangement appelé "menu"...) tu dois implémenter dans ton module un hook_menu ( http://api.drupal.org/api/function/hook_menu/5 pour drupal 5 )

Tostinni , le mer, 01/07/2009 - 21:54
Yoran, le mer, 01/07/2009 - 22:09

En fait non, mais je ne suis pas loin d'être d'accord avec lui. Pour ce papier (le mien Smile, je part de ce constat sur la tête de cette pauvre requête pour arriver finalement à un problème beaucoup plus grave, celui de la lourdeur du module lui-même. Peut-être n'est-ce pas assez clair dans mon discours.

Au fond, une requête super-optimisé ne ferait gagner que 10 à 15% de performance sur une des dizaines de requêtes effectués pour construire la vue. Autant dire des cacahouètes. Le problème n'est donc pas moins la requête que les requêtes qu'il faut pour arriver à la construire, et les traitements qu'il faut pour en faire son rendu final. Finalement c'est là que le bas blesse avec ce module, et c'est effectivement le même problème avec Panels.

Maintenant pour revenir à la requête en elle-même, au fond le vrai problème ici est le pitoyable moteur d'optimisation de mySQL. Je peux te garantir que cette même requête exécutée au hasard sur une base Oracle, n'aurait donné aucune différence de performance avec ma requête à la main.

nyl auster , le jeu, 09/07/2009 - 09:07

Hello Yoran !
Sur les mesures je suis complètement d'accord, d'autant que comme tu le soulignes le framework de Drupal soulage très largement le codage d'une requête sql. De toute façon le principe de faire des requetes sql pour construire des requêtes sql refroidit tout de suite ...

mais on pourrait faire le même reproche à l'égard de Drupal en général et de n'importe quel CMS : Le premier site que j'ai fait (tout en php) à l'époque avait besoin d'une seule et unique requete sql pour afficher toutes les données (ma première jointure de table, ce fut un moment d'émotion). En passant le même site sous un CMS (modx) je suis passé entre 50 et 120 requetes sql : ça déprime quand on essayait de n'en faire qu'un à trois par pages max...

Yoran, le jeu, 09/07/2009 - 16:29

Les philosophies ne sont pas les mêmes. Lorsque tu fais un logiciel à façon, comme ton premier site, on ne gère pas les milles choses qui sont un standard dans Drupal. La bonne question est alors "en as t'on besoin ?". Tout est une question de temps au fond. Si on traçait deux courbes, avec en ordonnée le nombre de fonctionnalités à développer, et en abscisse, le temps pris pour les implémenter, ta courbe "mon site en PHP" évoluerait en exponentiel, celle d'un CMS, évoluerait en linéaire. Alors jusqu'à ce qu'elles se croisent, évidement tu as tout intérêt à faire un développement à la main car un tel site ira TOUJOURS beaucoup plus vite qu'un CMS quel qu'il soit, mais une fois passé le croisement, c'est de moins en moins possible.

Ce même principe est applicable entre deux CMS, celui qui est le moins évolutif gagnera toujours en vitesse sur celui qui est plus modulaire, mais les courbes fonctionnalités/temps de dev vont évoluer de la même manière.

Pareil encore si on parle d'un module comme Views et de faire ses requêtes à la main, à part que là on réduit la courbe à un sous-enseble fonctionnalité. Mais j'ai bien conscience que si l'on a 20 jours pour coder 1000 vues, ça tiendra jamais sans Views, mais Views sera toujours plus lent qu'un module à la mano.

En somme faire 3 pages max en Drupal, c'est peut-être pas la meilleur des choses à faire Smile

Pak1ange , le dim, 12/07/2009 - 19:17

Bonjour,

Quel plaisir de retrouver votre site ou les informations sont précieuses Wink d'autant qu'il semble avoir été remis à jours ces derniers temps.

Pour ce premiers com, je viens vous demander le lien pour télécharger les icônes que vous utilisés sur ce site pour les avatars et autres mise en pages. J'avais vue passer un lien sur l'un de vos commentaires mais je ne sais plus le retrouver.

J'avais trouvé cette bibliothèque (que j'avais téléchargée) plutôt complète mais un formatage malencontreux... Pfttt... Erf.

Merci d'avance.

Yoran, le lun, 13/07/2009 - 15:39

Une partie vient d'ici : http://gnome-look.org/content/show.php/buuf+icon+theme?content=44539

Pour le reste, cela vient des thèmes Oxygen pour KDE 4 et Tango qui ont le mérite de fournir du SVG. Pour les liens, il faut chercher sur kde-look.org.

DrupalFrance , le sam, 18/07/2009 - 23:00

Hello,

Discussion fort intéressante.

Quelques petites remarques en passant, même si elles arrivent un peu après la bataille :

- La question des perf est-elle encore pertinente ? Ne faut-il pas utiliser Drupal comme un "assembleur" de pages et s'en remettre à d'autres (proxy, cache, etc.) pour servir ces pages aux utilisateurs ?

- C'est bien que tostinni ait mentionné le post de merlinofchaos : compte tenu de tout ce que Views est capable de faire et de tous les scénarios qu'il doit accommoder, le résultat ne peut pas être aussi clean qu'une requête maison, dédiée à un cas précis. Moi, il y a des tas de trucs que Views fait que je me passe volontiers de coder, pas parce qu'il le fait mieux que moi, mais simplement parce qu'il n'y a aucune valeur ajoutée dans un codage maison.

- Tu soulignes que ce n'est pas tant la requête que la lourdeur de la machinerie Views qui plombe les perfs. Que penses-tu dans ce cas de faire un copier-coller de la requête générée par Views pour la thémer ensuite manuellement ? (technique que j'ai vu mentionnée dans plusieurs "case studies")

- Pourquoi pas de theme('item_list', $items) dans le premier exemple ? Smile

Au final, pour moi, la question est : où placez-vous la valeur de votre application/site ? Dans les performances ou dans les fonctionnalités ?

Bien-sûr, je ne parle pas du cas où les performances dégradent tellement l'expérience que le site perd toute sa valeur (il paraîtrait même que quelques millisecondes de perdues dans le chargement d'une page Amazon feraient perdre des milliers de ventes...). Je parle d'un scénario où on a des deadlines serrées et où il est peut-être plus important de se concentrer sur les fonctionnalités qu'on développe que sur le fait de gagner un peu de temps.

Vincent

Yoran, le sam, 18/07/2009 - 23:27

Salut Vincent Smile

La question des perf est-elle encore pertinente ? Ne faut-il pas utiliser Drupal comme un "assembleur" de pages et s'en remettre à d'autres (proxy, cache, etc.) pour servir ces pages aux utilisateurs ?
Je me souviens d'une longue discussion en bagnole sur ce sujet. Tu ne peux pas te reposer sur une infrastructure pour gagner en performance. En tout cas pas dans tous les cas. Si tu prends un site Drupal fortement authentifié et donc fortement customisé pour chaque utilisateur, que deviennent tes caches, proxy & co. Ils ne font qu'aider et tu va devoir démultiplier ton infra technique pour suppléer un manque d'intelligence dans le code.

Moi, il y a des tas de trucs que Views fait que je me passe volontiers de coder, pas parce qu'il le fait mieux que moi, mais simplement parce qu'il n'y a aucune valeur ajoutée dans un codage maison.
Je ne dis pas le contraire et je ne cherche pas à noyer le bébé avec l'eau du bain. Si tu n'as aucun besoin de performances, pourquoi pas. Et cela dépend aussi de ta rapidité à coder. J'ai eu le cas récemment de Views+Calendar. Sérieusement, le temps que je comprenne comment cette usine à gaz fonctionne pour un 80% du besoin, j'ai eu plus vite faire de me faire mon pauvre calendrier qui réponde à 100% du besoin.

Tu soulignes que ce n'est pas tant la requête que la lourdeur de la machinerie Views qui plombe les perfs. Que penses-tu dans ce cas de faire un copier-coller de la requête générée par Views pour la thémer ensuite manuellement ? (technique que j'ai vu mentionnée dans plusieurs "case studies")
Hé bé, tu as lu ma conclusion ou pas ? Smile C'est très exactement l'usage que je lui trouve Smile Je vais même aujourd'hui un peu plus loin en bossant sur un module "datasource" qui me permet de faire en gros la même chose que views, mais avec une boite à outil pour développeur. Je teste cela avec un de mes clients et on arrive à générer les 3/4 des vues existantes en 10 minutes pièce.

Pourquoi pas de theme('item_list', $items) dans le premier exemple ?
Arf, tu me fais gagner encore quelques lignes là Wink

Le cas Amazon est assez flagrant d'un client que l'on aura jamais ni toi ni moi. J'ai vu de manière assez proche la machinerie qu'ils ont pour avoir de tels temps de réponse, autant te dire que tu n'a JAMAIS un seul élément de page qui soit calculé en temps réelle. Là ce sont de armées de caches qui bossent et derrière une application en Java/J2EE.

Maintenant pour les sites de tailles moyenne sur lesquels je bosse, la performance de Drupal est un point extrêmement problématique. Je n'en suis pas venu à me lancer dans cette "étude" pour la beauté du geste ou une quelquonque orthodoxie. Et là Views est sincèrement une vraie plaie.

Maintenant s'agissant de petits sites au thème relativement uniforme, fortement anonyme et sans communauté/réseaux sociaux, je suis assez d'accord, Views peu faire gagner plus de temps qu'il n'en fera perdre.

Mon seul objectif avec ce papier est un gros "faites gaffe à ce que vous faites et utilisez le en connaissance de cause". En aucun cas je ne benne l'outil.

Maxime Topolov , le mer, 26/08/2009 - 21:02

N'oubliez pas une chose essentielle ! Sur un site à gros traffic il faut considerer la chose sous l'angle budgetaire. En effet Views, offrant un haut niveau d'abstraction (le code de views est une pure merveille, pour peu qu'on met les mains dedans), est plus lent qu'une requete ecrite de maniere spécifique.

Mais Views n'est pas qu'un constructeur de requetes ! Views offre surtout la puissance des arguments / filtres récupérables depuis l'URL, c'est aussi une maniere unique de themer, c'est aussi l'intégration avec Panels & Services...

Donc je dirais sur un gros projet dont ont devra assurer la maintenance, Views est une pure merveille.

Enfin il faut aussi savoir optimiser Views, dans le choix des champs, les relations & co (exporter le code des views depuis la base)...  

Sous l'angle budgetaire prenons un cas concret : 

Si on a besoin de 10 jours de dev de plus ca coute au client entre 4000 et 6000 euros et sans compter le temps de la maintenance, évolutions et modifications... Qui sur un gros site de contenu peut représenter beaucoup.

Acheter un serveur supplémentaire coûte dans les 3000.... 

 

 

Marc , le jeu, 27/08/2009 - 08:39

Je connais de près un bon exemple où ce genre d'âneries a conduit à acheter plutôt 5 serveurs.

On peut arriver à un tel niveau d'inepties (views + cck c'est un must). Moi qui ai été à l'école Allociné, je me marre juste à l'idée de montrer ça à l'un de mes directeurs techniques de cette époque. Je me serais fait dépecer si j'avais ne serait-ce que proposé un outil de ce genre (même si il n'y a rien de ce genre là-bas) Tongue

Sans rire c'est une vraie usine à gaz. 

Donc pour des usages limités et dans des contextes particuliers je ne trouve pas ça idiot.

Mais sur un gros projet, je crois que Yoran me rejoint sur ce point, c'est une bêtise. Si sur un gros projet on a pas de ressources compétentes dédiées ça me paraît dingue. Par ailleurs des views qui seraient l'équivalent de 10 jours de boulot je demande aussi à voir. Soit c'est vraiment un gros machin compliqué et views me paraît encore moins adapté, soit on a une équipe pas super efficace.

Avec Yoran nous avons remplacé toutes les views d'un gros site par un mécanisme de son cru. Je ne sais plus combien Yoran a mis pour coder le moteur à la base de l'opération mais ça doit être une petite poignée de jours (1 ? 2 ?) ensuite il suffisait de reprendre les requêtes, les optimiser, et les recoller dans cet outil. Et on a remplacé TOUTES les views.

Maintenant tant qu'il y a des boîtes qui ne savent utiliser que Views (j'en connais une qui fait payer plus en utilisant Views partout que n'importe quelle autre en passant plus de temps à coder à la main !) ça fera du travail pour les Yoran de la place (et les gens comme moi).

Marc.

Yoran, le lun, 31/08/2009 - 08:02

Salut Marc Smile

Le module DataSource doit en crois peser 2jh pas plus. Et la centaine de vue ont été transposée en une dizaine de jours (au fil de l'eau donc en charge, je dirais 3jh).

 

pounard , le jeu, 27/08/2009 - 16:04

Bon article, je suis tout à fait d'accord, views génère des requêtes absolument immondes, mais je suis pas d'accord sur le pourquoi elles sont immondes:

  • Pour ce qui est des alias, c'est une bonne chose, aliaser ne fait pas perdre de temps au SGBD, et l'aliasing systématique par le module views est fait pour lever les ambiguités, notamment quand on fait des requêtes complexes qui ont besoin de plusieurs fois la même table;
  • Autre point: le IN('toto') avec une seule valeur. Je ne suis pas d'accord sur le fait que ça ralentisse, n'importe quel vrai SGBD (je pense à PostgreSQL) sait optimiser ça tout seul; par contre l'optimiseur interne de MySQL lui, a souvent plutôt intérêt d'être désactivé quand on fait des requêtes un peu sioux;
  • J'aurais tendance à dire, d'expérience (mais je peux me tromper) que ce qui coûte le plus dans cette requête est probablement les LEFT JOIN (ça c'est moche, et dans un schéma SQL correct on est censé s'en passer, le fautif est CCK);
  • Pour les dates, je suis d'accord, c'est tout à fait immonde, mais le support des dates est aléatoire en fonction du SGBD, je comprends que le developpeur ait pu se torturer à ce point pour écrire cette chose immonde, si il veut supporter plusieurs SGBD;
  • Dernière chose, effectivement, le module Views, quelque soit le nombre de caches (à de multiples niveau) qu'il ait, est une vraie moulinette de viking barbare; un vrai constructeur de requête, c'est à la fois sa force, mais aussi ce qui fait sa lenteur. Cependant, avec un bon OPCode cache, on devrait pas trop voir la différence (essayez donc de construire des requêtes avec Zend_Db, vous allez pleurer, sincèrement, quand vous allez voir le temps que ça met);
  • Une petite note qui rejoint celle juste au dessus, la couche d'abstraction de D7 risque probablement de faire exactement la même chose, puis s'agira à partir de cette nouvelle version d'un constructeur de requête, qui dans les fondements doit beaucoup s'apparenter à celui de Views (les hook de partout en moins, bien sûr, appeller des hook en cascade est toujours consommateur).

Il ne faut pas perdre de vue que le problème de la construction des requêtes de views, c'est que ce sont les modules qui proposent une intégration à views qui sont en partie responsable de la description des tables; et les gens qui le font ont souvent tendance à oublier, que par exemple, la jointure est par défaut en "LEFT" dans views si on ne précise pas "INNER" (mot clé qui ne sert pas à grand chose d'ailleurs) dans la description de ses tables.

 

Merci cependant pour cet article, c'est très intéressant.

Yoran, le lun, 31/08/2009 - 09:16

Pour ce qui est des alias, c'est une bonne chose, aliaser ne fait pas perdre de temps au SGBD, et l'aliasing systématique par le module views est fait pour lever les ambiguités, notamment quand on fait des requêtes complexes qui ont besoin de plusieurs fois la même table;

Bien d'accord, cependant aliaser "node" en "node" manque un peu de sel. De plus je ne dis pas que les alias sont mauvais, au contraire, mais que leur longueur excessive semble nuire aux performances de la petite basote mysql. De même pour le "in", je suis bien d'accord que sur Oracle ou PostgreSQL, l'impact est nul, mais ce n'a pas été le cas pour ma base mysql (même s'il reste minime)

Pour les dates, je suis d'accord, c'est tout à fait immonde, mais le support des dates est aléatoire en fonction du SGBD, je comprends que le developpeur ait pu se torturer à ce point pour écrire cette chose immonde, si il veut supporter plusieurs SGBD;

Le support du type "date" est alléatoire, mais l'utilisation du timestamp a quant à lui fait ses preuves, fonctionne sur toutes les bases avec un temps dfe traitement optimum.

Dernière chose, effectivement, le module Views, quelque soit le nombre de caches (à de multiples niveau) qu'il ait, est une vraie moulinette de viking barbare; un vrai constructeur de requête, c'est à la fois sa force, mais aussi ce qui fait sa lenteur. Cependant, avec un bon OPCode cache, on devrait pas trop voir la différence (essayez donc de construire des requêtes avec Zend_Db, vous allez pleurer, sincèrement, quand vous allez voir le temps que ça met);

Mon vieux prof d'algorythmique m'a toujours dis que l'optimisation est le dernier aspect à aborder pour améliorer la vitesse. En d'autres termes un bon algo non optimisé sera toujours beaucoup plus performant qu'une moulinette viking bardée de caches et d'optimsateurs d'opcode. Pour être un peu moins politiquement correcte, il serait temps que ceux qui se disent développeurs web, recommence à apprendre à développer Wink

Pour D7, je ne te renjois pas. C'est une couche d'abstraction à la connexion aux bases de données, et aucunement une abstraction de la construction des requêtes elles-mêmes. A ce titre c'est la même chose que JDBC ou ODBC pour PHP.

Pour conclure sur ta conclusion, moi je retraduit cela en "un développeur (web ou pas) ne peut pas faire l'impasse sur une connaissance du schéma de sa base et que du coup Views, la lui masque".

 

Anonyme , le mar, 08/09/2009 - 17:39

Bonjour,

Un commentaire (Pounard) m'interpelle, plus haut :

J'aurais tendance à dire, d'expérience (mais je peux me tromper) que ce qui coûte le plus dans cette requête est probablement les LEFT JOIN (ça c'est moche, et dans un schéma SQL correct on est censé s'en passer, le fautif est CCK);

Comment ça on est censé s'en passer ? J'ai loupé quelque chose et je dois reprendre mes cours de SQL ? Ou je n'ai pas compris ce que vous souhaitiez dire ?

pounard , le mer, 04/11/2009 - 08:51

Tout dépend du schema de données: on voit que CCK créé une seule table qui rassemble tous champs non multiples pour un type de contenu; dans ce cas, si on fait une requête sur un type de contenu particulier, même si les champs sont vides on peut faire un natural join et non un left join, car l'entrée existe quand même en base de donnée (avec des valeurs NULL ou ''). Quand on fait du champ CCK multiple, je vois pas l'utilité de faire un join dans la requête, car on génèrerait des doublons dès lors que plus de deux éléments sont renseignés, faire une seconde requête pour récupérer les éléments au moment de l'affichage serait presque mieux (ce qui se passe de toute manière au node_load() que l'on le veuille ou non, dès lors qu'on affiche en mode node, de manière générale ce que certains modules font dans leur handlers lors de l'affichage).

DavP , le dim, 13/09/2009 - 10:18

Je trouve cet article fort instructif ! Cela m'a vraiment donné envie d'essayer cette nouvelle approche en créant son propre module au lieu de passer par l'interface graphique de views pour réaliser ses affichages.

Je pense que ça vaudra le coup pour moi de bûcher encore plus sur l'API de Drupal afin de faire ce genre de chose. Cela sera profitable autant pour mon expérience personnel/professionnel que pour la clareté du code et les gains de performance acquis. Smile

Merci beaucoup de nous faire part de ce genre d'alternatives ! Smile

Timos , le mer, 04/11/2009 - 23:35

Hello à tout le monde et merci pour cet article et pour la somme d'infos qui suit. Une petite question : est-ce que panels pose les mêmes problème que view ? Merci, Timothée

Yoran, le dim, 21/02/2010 - 22:47

La je ne saurais dire, je n'ai jamais eu l'occasion (et/ou le besoin) d'utiliser Panel. Et la seule fois où je l'ai rencontré sur un projet, son utilisation se résumait à créer des pages qui auraient aussi bien pu être faites par une module custom et un hook_menu...

Ben , le jeu, 19/11/2009 - 00:12

Salut Yoran,

D'abord merci pour l'article, il est très clair et détaille un problème très intéressant (+ une de ses solutions).

Etant nouveau en Drupal, je comptais utiliser Views pour sa facilité, mais maintenant je préfère tenter le hard coding. En effet, mon site, de part son contenu, aurait nécessité être exclusivement composé de views/panels. Je pense que je lui ferai grand bien en l'allégeant de cette façon.

A ce sujet, j'aurais aimé avoir une mise en page style "grid" ; aurais-tu une idée de comment y arriver ? Peut-être aurais-tu aussi des liens vers une documentation plus détaillée ?

Merci et bon courage,

Ben

Yoran, le dim, 21/02/2010 - 22:49

Tu entends "grid" au sens css ou views du terme ?

Econq, le ven, 19/02/2010 - 10:18

Bonjour Yoran,

Dans ton étude, tu compares la performance de views à la perf d'une requête sql.

Si j'ai bien compris, ta requête sql by-passe views mais aussi le système de hook.

Aurais-tu une idée du gain apporté par le by-pass du système de hook lui-même? (ou de la proportion approximative entre temps consommé par views lui-même et temps consommé par le système de hook)

Yoran, le dim, 21/02/2010 - 22:52

Hum, pour être certain de comprendre, ta question est elle "est-ce que views utilisé uniquement en générateur SQL, sans mise en forme des données, serait aussi performant qu'une requête simple" ? Si c'est cela je dirais "presque" sans aucun doute. De la bouche même d'une des personnes ayant travaillé sur views, la couche présentation est pour le moins "épaisse" (pour reprendre son terme). Maintenant il s'agit là d'une forme d'utilisation du système hooks. En d'autre termes, ce n'est pas le système de hook qui est en cause plus que l'imbrication, la récurrence et la suite de hooks mis en oeuvre pour créer une vue.

Publier un nouveau commentaire

Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement. Si vous avez un compte gravatar, l'utilisez pour afficher votre avatar.
  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • Tags HTML autorisés : <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <br> <p> <img> <sup> <a>
  • Les lignes et les paragraphes vont à la ligne automatiquement.
  • Every instance of custom tags in the input text will be replaced with a specific tool shortcut.
  • Textual smileys will be replaced with graphical ones.

Plus d'informations sur les options de formatage