Fermer2
ZephLe 08/04/2010 à 15:24
Le titre n'est pas clair, mais je ne sais pas comment formuler ça autrement grin

Je me demande quelle est la façon la plus efficace de résoudre un problème que j'ai toujours traité de façon "crade", mais qui me bloque aujourd'hui puisque le volume de données à traiter devient trop important.

Imaginons que je veuille modéliser des personnes, qui possèdent tout un tas de caractéristiques, et que je veuille conserver pour chacune d'elles la liste des livres qu'elles ont lu. J'ai donc ces deux objets :

[ul][li]Personne[ul][li]Nom[/li][li]Prénom[/li][li]Age[/li][li]... plein d'autres attributs ...[/li][li]Liste des livres lus[/li][/ul][li]Livre[ul][li]Titre[/li][li]Auteur[/li][li]Date de lecture[/li][/ul][/li][/ul]
Je voudrais, en une ou plusieurs requête(s) rapide(s), récupérer certaines personnes (en fonction de critères qui dépendent des attributs de ces personnes) et pour chacune d'elle la liste des livres qu'elles ont lu. Je suppose, bien que ce ne soit pas obligatoire, que je possède deux tables pour contenir mes deux objets. Chaque livre possède une référence vers la personne qui l'a lu, et sera donc dupliqué autant de fois que nécessaire (3 personnes ont lu le même livre => il sera présent 3 fois en base ; dans la vraie vie mes "livres" sont en réalité des entités uniques donc ça n'est même pas une perte de place).

Je vois trois solutions simples :

- Une requête pour récupérer les N personnes qui m'intéressent, puis N requêtes pour récupérer les livres de chacune d'elle. C'est hyper lent, puisque si je remonte 1000 personnes il me faut 1001 requêtes, avec les performances que vous pouvez imaginer derrière.

- Une requête avec une jointure, pour remonter d'un seul coup les personnes qui m'intéressent et les livres qu'elles ont lu. Mais si une personne a lu 100 livres, je vais avoir 100 fois chacun de ses champs dans mon résultat, or autant un livre est une petite structure, autant une personne contient beaucoup de champs. Du coup mon résultat peut devenir potentiellement énorme, et donc très lent.

- Une requête avec une jointure, mais comme j'utilise MySQL je me sers de GROUP_CONCAT pour concaténer les champs des livres, de façon à n'avoir qu'une ligne de résultat par personne. Par exemple, si je concatène avec le caractère "|" comme séparateur, une ligne de résultat pourrait ressembler à ça :
Nom
PrénomAge... plein de colonnes ...TitresAuteursDates
CrocOdile27...Titre1|Titre2|Titre3Auteur1|Auteur2|Auteur3Date1|Date2|Date3

Plusieurs problèmes avec cette troisième solution : c'est pas portable (GROUP_CONCAT n'est pas standard), je peux avoir des problèmes s'il y a vraiment trop de livres (il y a une limite pour la taille de la chaine), et je suis obligé d'échapper les "|" dans les valeurs des champs des livres. Malgré ces contraintes, c'est la solution la plus rapide des trois, mais je n'en suis pas vraiment satisfait.

Voyez-vous une solution plus propre et plus performante ? (ce problème me semble tellement générique qu'il y a forcément mieux, j'imagine ?)