Lenteur requête simple

Bonjour,

Je suis très surpris par un temps d’accès en ORDA.
La base est en 17.4. La table en question comporte 110 enregistrements et le code est fort simple.

$orda:=Créer objet
$orda.dataClass:=ds["Table"]
$orda.entSel:=$orda.dataClass.all() //#1
$orda.champs:=Créer collection("Code";"Libelle")
$orda.donnees:=$orda.entSel.toCollection($orda.champs) //#2

En local, c’est instantané.
À distance, en ADSL très convenable, la ligne #1 prend 8 sec. et la #2 13 sec.
Je m’attendais plus à un temps comparable à un SELECTION VERS TABLEAU.

Y a-t-il quelque chose dans le code qui provoque cette lenteur ou bien ?

Non, c’est toCollection() qui est un tue-le-temps, j’ai le même souci en v17r4 (j’ai pu “contourner” en mettant dans storage). Il faut regarder pourquoi collection.extract() est mieux que toCollection(), après quoi tu chiales pour changer de version. Pareil pour la notion de contexte dans les requêtes…

Bonjour Arnaud,

Je ne comprend pas ta réponse.
extract() est applicable à une collection. toCollection() me sert à récupérer des données d’une entitySelection.
Du coup, y-a-t un contournement possible en orda ?

J’avoue honteusement ne pas avoir encore joué avec la 18r3, mais ce n’est pas ce que je lis dans le blog :

The new extract() member method is available on an entity selection .
You can now build a customized collection from an entity selection!

Comme dit plus haut, dans mon cas il s’agit d’une collection “stable pendant la session”, je pouvais accepter que sa constitution prenne du temps du moment qu’après je la mets dans Storage où je n’ai plus qu’à la lire.
Si ce n’est pas ton cas, en v17 faut se débrouiller “à l’ancienne” : soit selection vers tableau, soit en orda avec une méthode executer sur serveur (EoS).
J’ai fait un essai rapide de cette seconde solution : accès distant, collection constituée à partir d’une entity selection de 431 enregistrements, 8 champs dont 4 issus de la table “principale” et 4 autres issus d’une table “parente” (lien N -> 1)

  • en “normal” ma collection met 8000ms à se constituer
  • en EoS ça tombe à 200ms environ

soit 2,5%…

À noter, lorsque tous les champs viennent de la table principale, toCollection() est nettement plus rapide, dans les 800ms. Je pense que la lenteur vient de la présence de champs étrangers" à cette table, c’est dans ce cas seulement où j’ai droit à la fenêtre-qui-fait-mal :
Capture d’écran 2020-10-09 à 10.16.21
Du coup je suppose que la présence des champs étrangers oblige 4D à “peigner” les enregistrements un par un.

Je suis très inquiet sur orda là. Je trouve le fonctionnement génial mais je ne m’attendais pas à une telle lenteur en distant.
Ce problème de toCollection() ne doit pas faire oublier que le all() aussi est problématique dans mon simple exemple. 8 sec. sur une table de 110 enregistrements, c’est pas possible. Et là, le extract() n’y changerait rien.

J’avais cru comprendre qu’une “ligne” orda partait en une seule requête au serveur qui l’exécutait et renvoyait le résultat.
Cette possibilité de mettre beaucoup de choses sur une seule ligne permettait d’optimiser grandement les échanges C/S.

Là, je ne sais plus que penser. J’en suis sincèrement à me dire que je vais arrêter orda jusqu’à nouvel ordre dans ces conditions. C’est trop lent. On s’en sort 1000 fois mieux, au sens propre, avec un SELECTION VERS TABLEAU.

Juste pour être sûr, t’as moyen de réitérer ton exemple en v18.2 ?
Car il y a eu des corrections de bugs et des optimisations (je ne suis pas certains qu’elles ont toutes été incluse en v17.4).

Pour rappel: 4D Server : La commande SELECTION VERS TABLEAU est optimisée pour 4D Server. Chaque tableau est créé sur le serveur puis envoyé en totalité sur le poste client.

En est-il de même pour les commandes ORDA ?

Bonjour Stanislas,

J’ai copié/collé ton code dans la base. Mode distant, idem Arno.

1 ms pour une table de 630 enregistrements.
Alors je ne sais que dire.

Notre dernière expérience: sur cette table nous avions un champ objet à priori gros facteur de ralentissement, nous l’avons viré dans une autre table et les recherches sont re-devenues rapides… on arrivait à la minute…

PS: un champ objet write Pro

Stanislas,
pour compléter la réponse d’Éric, il ne faut pas être inquiet sur orda. C’est la version que tu utilises qui n’en délivre pas tout le potentiel, ou toi qui n’es pas encore suffisamment familiarisé pour le caresser dans le sens du poil.

Si tu ne l’as fait, je te conseille vivement de regarder la conférence de Marie Sophie (lien plus haut). Principalement pour constater qu’aucun gamin n’est venu lui f… le souk pendant l’enregistrement (fait remarquable, en plein confinement), accessoirement pour ce qu’elle dit des contextes (sachant que contexte = à partir de la 17r5.)

Tu peux par exemple profiter de ce que tu es en distant pour comparer un tant que non fin de selection (qui est ce qu’on peut demander de pire à un serveur) avec un for each(machin;entitySelection) : le second reste lent mais beaucoup moins que le premier.

Même en v17r4 (sans contexte), j’ai constaté qu’à peu près tout est plus rapide en orda. Dans ton cas, comme tu constate que c’est instantané en local, j’opterais sans trop hésiter pour une méthode EoS - quitte plus tard à utiliser extract(). Mais j’utilise aussi selection vers tableau, je suis opportuniste…

D’après ce qui est dit de $es.extract(), je pense que le mécanisme est similaire.

La première fois qu’on nous a montré orda, je me suis dit “chouette, wakanda est dans 4d” (et je n’aurai pas besoin de me mettre à wakanda et au web).
Donc oui, les commandes orda sont optimisées, mais je pense qu’il faut le voir de façon beaucoup moins ponctuelle que telle ou telle commande, c’est tout le moteur qui fait le pont entre les requêtes client et la base qui est conçu pour ça. À l’époque ils parlaient de waf (wakanda framework), chez 4d, je ne sais pas ce qu’il en est aujourd’hui.
S’ils ont fait ça, c’est pas juste pour le plaisir de la notation à point mais parce que wakanda était conçu pour l’internet et qu’il était vital pour 4D de proposer un client lourd apte à ce terrain. Ils savent parfaitement que, si le seul moyen de faire fonctionner un client 4D distant était TSE, dans quelques années 4d ne serait plus qu’un vestige.

Je ne comprend pas ta réponse @de_MONTARD.Arnaud ? A quoi sert ton test et d’où vient la différence de tes résultats si la commande est déjà optimisée et réalisée sur le serveur ? J’ai l’impression que les elements sont envoyés sur le client (TOUS les elements) et qu’ensuite le .toCollection se fait en local du client…

Autre point: une collection est plus lourde qu’un simple tableau. Et effectivement si l’ensemble de l’enregistrement doit transiter sur le réseau c’est complètement différent que si l’enregistrement reste en local du serveur surtout s’il contient de gros champs objet, etc…

Donc, c’est pas clair. Actuellement, les listbox Entity selection sont optimisées OK (lazy loading, context, etc.) mais on ne parle pas des listbox collection et surtout de comment tu construis ta collection.

Après avoir fouillé un peu, il s’avère que le all() devient très lent si la table comporte un blob. 8 sec, c’est énorme. J’ai du mal à comprendre ça puisqu’on ne demande à ce stade aucune donnée. Une table comportant beaucoup d’enregistrements ne prend pas longtemps s’il n’y a pas de blob.

Le toCollection() n’est finalement pas si lent. Il prend 1,5 sec. pour ramener 110 éléments comportant chacun un code entier long et un libellé court. Je ne sais pas pourquoi j’avais noté 11 sec. hier. Néanmoins 1,5, c’est déjà beaucoup trop pour si peu de données.

Ce qui est sûr, c’est que dans le même contexte, TOUT SELECTIONNER/SELECTION VERS TABLEAU est beaucoup plus rapide. 74 ms en tout.

orda, j’adore et je m’y suis mis autant que possible mais les temps que je constate sont rédhibitoires.

À rien.
Tu as demandé « En est-il de même pour les commandes ORDA ? » : question générale, réponse générale.

Si ta question signifiait « En est-il de même pour la member function es.toCollection ? », la réponse est manifestement non, ce n’est pas optimisé. Si elle l’était, Stanislas n’aurait pas ouvert ce fil, je n’aurais pu produire la copie écran plus haut, je n’aurais pas parlé de lenteur ici, Marie-Sophie n’aurait pas répondu cela sur 4DBB, etc.

Si ta question signifiait « En est-il de même pour la member function es.extract() ? », je n’ai pas eu le temps de tester mais la lecture de ce fil et d’autres liens cités au début me font dire que oui. Quand la poule 4d chante qu’elle a pondu un œuf, c’est rarement pour vanter un œuf pourri.

La listbox n’est que l’interface de visualisation de la collection. Quand à comment construire une collection, il me semble que ce fil ne parle que de ça.

Non la listbox peut être de différent type (je ne t’apprend rien) : Tableau , Selection, Entité selection, Collection. Et si certaines optimisations sont liées TRES fortement à un type précis ce n’est pas le cas des commandes du langage ORDA mais lié à l’utilisation de cet outil d’interface précis.

Donc, c’est pas la même chose d’utiliser un listbox entité selection ou une listbox collection et surtout en l’état actuel des choses comme tu dis que la commande qui sert à construire la collection n’est PAS optimisée.

C’est exactement le constat qu’on a fait, avec Eric. Pour piger il faut regarder la conf’ de Marie-Sophie (dont “on” va finir par croire qu’elle me graisse la patte mais “on” est mal pensant) et se rappeler de ce qu’est un gros champ : champ qui, de par son type (texte, blob, objet, image), va en général stocker beaucoup beaucoup beaucoup plus d’octets qu’un petit champ scalaire de rien du tout.

En mode classique, si je fais TOUT SELECTIONNER, 4D m’envoie le 1er enregistrement en entier et une sélection (c’est à dire presque rien). Ce premier enregistrement contient le gros champ, mais ce n’est pas très pénalisant car le serveur ne m’a envoyé qu’un enregistrement. Mais si je démarre un tant que non fin de selection, je vais commencer à pas aimer du tout car tous les gros champs vont m’être envoyés les uns après les autres sur le réseau.

En orda, si je fais all(), je pense que c’est très différent de TOUT SELECTIONNER : si j’ai bien compris, 4D m’envoie les 80 1er enregistrements - en clair, il me balance les 80 gros champs en une fois. Après, c’est là que le contexte intervient : le contexte mémorise les attributs lus par le code après la requête. Le coup d’après, si ce code n’a utilisé que INDIVIDU.nom et INDIVIDU.prénom et a ignoré le champ objet INDIVIDU.généalogieComplète, ce champ ne sera plus envoyé par la suite.

Pour le dire autrement, sir on veut tirer partie des contextes face à une table dont un des champs est un monstre, 2 soluces :

  • la première requête ne doit pas être all()
  • plus radical, on met le gros champ dans une autre table, comme l’a fait Eric

Quelle drôle d’idée de m’envoyer des données alors que je n’ai rien demandé !
Dans la version que j’utilise, il n’y a pas encore les contextes.
Sans bouger de champs, je ne vois pas comment je peux faire autrement que all() si je veux tout. Le toCollection() avec le filtre est justement là pour limiter les données renvoyées. Je ne comprend pas l’idée de ces 80 enregistrements envoyés d’office.

Juste une question: pourquoi ce choix du type listbox collection par rapport au choix listbox entité selection ?
Je réitère ma remarque: il serait préférable de travailler en v18.2 qu’en v17.4.

Je pense qu’il faut se mettre à la place du concepteur… Si tu veux que le développeur bénéficie de performances correctes sans trop se poser de question, tu n’as guère le choix : ton système envoie tout et, ensuite, détermine à partir de ce qui est fait de ce tout où il peut gratter du temps. Ça a toujours été le choix de 4D de nous faciliter la vie, parfois à l’excès, mais ça a le mérite de rester simple. Sinon nous ferions du SQL, où on a ce qu’on demande - ni plus ni moins. Quand à pourquoi 80, je pense que c’est simplement le chiffre qui leur permettait d’avoir le meilleur équilibre tout cas confondus, quitte à ce que ce soit inadapté aux cas “extrêmes”.

Ce gros champ, dont je parlais plus haut, pourquoi 4D me l’envoie systématiquement quand je fais du 4d classique ? Parce que sans cela, il devrait me proposer des mécanismes de chargement d’enregistrement sur le client avec ou sans le gros champ : ce serait nettement moins simple… Avec orda, il y a un mieux, il va me l’envoyer la première fois puis cesser quand il se rendra compte que je n’en fais rien. Voir aussi mes deux derniers paragraphes ici et la réponse de Marie-Sophie :
« Oui effectivement, les contexts, pour le moment, ne sont pas accessibles en lecture.
Il faut utiliser des attributs pour qu’ils finissent par figurer dans le context. »

Le mot listbox n’a pas été employé une fois par Stanislas dans ce fil et une fois par moi pour te répondre car tu as mis ça sur le tapis alors qu’on parlait de lenteur d’une requête : c’est quoi le but ?

Non, comme l’a dit Arnaud, la listbox n’est pas concernée par mon souci. Aucune n’est mise en œuvre.

Donc justement, c’est encore pire dans ton cas; lorsque tu fais un .all il transite toutes les infos là où une listbox ne transiterait que les 80 premiers enregistrements (en v18).

Pour construire ta collection, il le fait en local du client donc il a besoin de toutes les infos pour le faire.

La bonne solution (dans ton cas dans ta version), si tu desires absolument utiliser au final une collection précise, c’est de la créer sur le serveur et de transférer ensuite juste cette collection.

Donc, oui pour la simplicité (ET LES PERFORMANCES) par rapport à un simple SELECTION VERS TABLEAU, on repassera…