Récupérer des imbrications multiples dans une table MySQL - PHP - Programmation
Marsh Posté le 23-01-2006 à 15:51:15
Tu peux aussi récupérer la table en entier en une fois, la stocker dans un tableau en deux dimensions et travailler sur ce tableau pour reproduire l'arborescence.
Ca sera surement gourmand en mémoire mais aussi surement plus rapide que des disaines de requettes succéssive.
Marsh Posté le 23-01-2006 à 16:01:48
omega2 a écrit : Tu peux aussi récupérer la table en entier en une fois, la stocker dans un tableau en deux dimensions et travailler sur ce tableau pour reproduire l'arborescence. |
pluzun, c'est ce que je fais (en gros) dans ce sur quoi je bose en ce moment.
Marsh Posté le 23-01-2006 à 17:24:57
Ah oui, très bonne idée, il y a vraiment des fois où je me demande à quoi je pense
Merci beaucoup
Marsh Posté le 23-01-2006 à 17:59:19
Le mieux serait de revoir ta procedure d'enregistrement des données.
Si on par de la chaine vide "" pour la racine (noeud 0).
On ajoute un "1" pour avoir un fils
On ajoute un "0" pour avoir un frere
On obtient alors un tableau :
0 -> ""
1 -> "1"
2 -> "10"
3 -> "101"
4 -> "100"
5 -> "1000"
6 -> "1011"
7 -> "1010"
8 -> "10000"
Si tu veux tous les fils issue du noeud 2 il suffit de rechercher dans la base de données les noeud ayant pour arborescence : "101%" (% remplacant n'importe kel nombre de 0 et 1) On retrouve bien 3 6 et 7.
Voila pour mon idée.
Marsh Posté le 23-01-2006 à 18:04:31
tu as donc un tableau comme celui ci en base :
|
Marsh Posté le 23-01-2006 à 18:05:41
Il dit qu'il voit pas ce que ça change au problème du monsieur.
Marsh Posté le 23-01-2006 à 18:06:09
...et en plus il est pas binaire, son arbre.
Marsh Posté le 23-01-2006 à 18:07:23
Bah une requete SQL ... et pas de traitement ... et t'as tous les resultats ...
Si tu comprends pas prend des notes en relisant
Marsh Posté le 23-01-2006 à 18:09:00
afbilou > Ce qui veut dire : 10 éléments maximum dans le niveau suivant pour un noeud donné si on prend des nombres décimaux, 16 pour de l'hexadécimal, 26 si on prend que les lettres et 36 si on prend les lettres et les chiffres.
Qui te dit qu'il ne peut pas avoir 200 ou 300 descendants direct pour un noeud donnée? Tu ferais alors comment pour les nomer, tu coderais ton arborescence en UTF-8 pour avoir assez de caractéres disponibles?
Et si t'as un trés grand nombre de niveaux différents, tu te retrouverais avec des indices de plusieurs disaines ou centaines de caractére, ca me semble pas trés économique au niveau mémoire.
Alors c'est sur, ton systéme est plus rapide que ce qu'on lui proposait, mais c'est un systéme limité par son organisation même.
Marsh Posté le 23-01-2006 à 18:12:28
afbilou a écrit : Bah une requete SQL ... et pas de traitement ... et t'as tous les resultats ... |
Tu ne fais que déplacer le problème...là il va être emmerdé (et ça va être autrement plus chiant) au niveau de l'insertion d'un nouvel élément dans sa table.
En plus tu ne sais pas combien de fils un élément peut avoir, ni quelle profondeur peut avoir l'arbre. Bref, c'est mal.
Marsh Posté le 23-01-2006 à 18:14:06
à noter, sous oracle tu as les instructions connect by/start with pour ce genre de sport...je ne sais aps si mysql propose un truc proche...
Marsh Posté le 23-01-2006 à 18:14:31
S'il y a 300 elements ... et qu'il stocke un "1" ou un "0" sous forme de chaine de caractere (donc 1 octet par chiffre) ... dans le pire des cas il se retrouve de toute facon avec une occupation memoire de la base de données de 300*300 = 90ko ... c'est franchement ridicule point de vu mémoire ...
Marsh Posté le 23-01-2006 à 18:15:49
afbilou a écrit : S'il y a 300 elements ... et qu'il stocke un "1" ou un "0" sous forme de chaine de caractere (donc 1 octet par chiffre) ... dans le pire des cas il se retrouve de toute facon avec une occupation memoire de la base de données de 300*300 = 90ko ... c'est franchement ridicule point de vu mémoire ... |
...et il stocke ça dans un blob?
...et il fait comment la différence entre 1 16 1 et 1 1 6 1? Tu rajoutes des séparateurs?
Marsh Posté le 23-01-2006 à 18:17:30
(et alors là où c'est le pur bonheur c'est le jour où tu décides de supprimer un noeud...bonjour l'angoisse...)
Marsh Posté le 23-01-2006 à 18:20:51
L'insertion d'un nouvel element ne pose pas non plus de probleme ...
Si tu veux inserer un fils au nnoeud 0 (donc en tant que frere de 8) suffit de chercher les nombre ayant en arbo la forme "10*" (1 suivi d'un nombre quelconque de 0) ... puis de prendre le plus eleve des nombres !
tu obtiens l'arbo du noeud 8 et tu refais un insert de ton nouveau noeud avec pour arbo, l'arbo de 8 concatenée avec un "0".
Donc deux requetes.
Marsh Posté le 23-01-2006 à 18:23:31
afbilou a écrit : L'insertion d'un nouvel element ne pose pas non plus de probleme ... |
et si tu as a->b->c et que tu veux a->d->b->c?
...et ainsi de suite sur des cas plus gros...pour ajouter un pauvre élément tu vas modifier les 3/4 des enregistrements de ta table, avec des opérations de manipulation de chaines de caractères, qui sont plutot lourdes?
Marsh Posté le 23-01-2006 à 18:24:32
La suppression pose pas de probleme o_o
Faut pas se sentir obliger de reorganiser toutes les suites de "10100101010" pour combler les trous ... de trous y en auras mais ca gene en rien
Marsh Posté le 23-01-2006 à 18:26:13
afbilou a écrit : La suppression pose pas de probleme o_o |
Si tu en supprimes un, qui a des fils, puis que tu en ajoutes un à son ex-pere tu risques de refiler au nouveau tous les fils de celui qui est supprimé, mais sinon tout va bien...
Marsh Posté le 23-01-2006 à 18:26:53
'fin bref, stocker des infos complexes dans une chaine de caractères dans une base de données, c'est de la connerie pure et simple.
Marsh Posté le 23-01-2006 à 18:27:23
Nan mais son arboresence est binaire ... dossier et sous dossiers avec des fichiers surement dedans. (Il le dit dans son premier post)
C debile de vouloir inserer un element EXACTEMENT entre deux autres ... si tu veux inserer un element tu l'inseres en bout de chaine.
Marsh Posté le 23-01-2006 à 18:29:39
afbilou a écrit : Nan mais son arboresence est binaire ... dossier et sous dossiers avec des fichiers surement dedans. (Il le dit dans son premier post) |
Et s'il veut déplacer un dossier et son contenu, alors?
Ton truc ne tient absolument pas la route, oublie.
Marsh Posté le 23-01-2006 à 18:44:20
Je vois ce que veut dire afbilou, et c'est vrai que je trouve l'idée séduisante, pour un certains type d'application. Dans mon cas ça m'obligerait à tout recoder, et encore, vu qu'il y a en effet des déplacement, et que cette table n'est que l'arbo des "dossiers" et que j'ai une autre table pour la liste des "contenus", ça risque d'être assez galère.
Par contre je retiens la méthode, on ne sait jamais, ça peut servir.
Sinon voilà comme j'ai procédé :
Code :
|
Et ça marche nickel
Marsh Posté le 24-01-2006 à 14:50:59
Bon en fait ça ne marchait pas si bien que ça, j'ai du compliquer un peu le code, maintenant ça marche pour de bon.
Mais je pense recoder une bonne partie du site et suivre un schéma du style de celui d'afbilou.
Mais plutôt que de faire du "binaire" qui n'irait pas bien pour ce que je veux faire, je pense que je vais plutot faire un truc dans le genre là :
|
Ce n'est qu'une suggestion pour le moment et il va falloir que je fasse plusieurs tests pour voir si ça me convient, mais d'après ce que j'ai dans la tête je crois que oui.
Marsh Posté le 24-01-2006 à 14:52:59
Je te le déconseille fortement, pour les diverses raisons évoquées plus haut...mais c'est ton choix.
Marsh Posté le 24-01-2006 à 15:09:33
Je pense au contraire que c'est un procédé interessant.
Par exemple, si je veux supprimer le dossier (0,2,1), s'il n'est pas vide, il faudra que je puisse avoir une liste des dossiers dans lesquels je peux mettre le contenu. Donc je sélectionnerais tous les dossier ne commençant pas par (0,2,1...)
Idem si je veux déplacer le dossier (0,2,1,3) vers le dossier (0,1). Il me suffira de lire le dernier sous-dossier de (0,1) (dans mon exemple : 0,1,2) et d'incrémenter le dernier chiffre (donc 0,1,3)
Je trouve ça parfait pour ce que je veux faire.
De plus, je n'aurais plus qu'une seule table, car les liens présents dans ces dossiers auront la même arbo. Je rajouterais juste un champ à la table nommé "type" par exemple, avec 0 = dossier, 1 = lien
Marsh Posté le 24-01-2006 à 15:11:48
ReplyMarsh Posté le 24-01-2006 à 15:14:44
skeye a écrit : Si tu veux... |
Pourrais tu m'expliquer ton point de vue sur ce qui te semble ne pas aller ?
Autant quand je lis tes messages concernant l'arbre binaire, j'arrive à peu près comprendre ... mais avec un arbre comme le miens je ne vois pas le problème.
Donc ça m'arrangerais de savoir ce qui cloche avant de commencer
Merci
Marsh Posté le 24-01-2006 à 15:24:14
Ce qui cloche, c'est que tu vas stocker une structure arborescente dans une chaine de caractères à la con...
C'est pas fait pour ça, ça va être lent, modifier un élément t'oblige à intervenir sur tous ses fils, et tu as toutes les chances de faire des conneries à l'implémentation...Bref, c'est une idée qui a l'air géniale mais est finalement stupide, à mon avis.
Marsh Posté le 24-01-2006 à 15:27:57
2 caractéres minimum par niveau, et minimum trois caractéres du niveau 10 au niveau 99. Si ta combinaison dépasse 255 caractéres, (niveau 88 maximum mais surement bien avant vu que t'auras surement plus de 10 branches et feuilles dans certains niveau pour un neoud donné) il te faut passer à une colone de type TEXT ce qui te fera perdre encore plus de place dans la base de donnée. En comparaison, avec des indices numériques, il siffit de 4 octets par ligne pour 65535 dossiers et fichiers et 8 octects par lignes suffisent pour 4 milliards de références. Et là, je compte la palce prise par l'id propre à chaque élément et celle prise par la référence à son pére.
Pour une grosse arborescence, tu risques de dépasser le méga là où avec ton ancienne méthode, tu serais peut être à peine entrein de friser les 10 Ko.
Et je te parle pas non plus de la perte de temps induite par une recherche de type like qui peut être pire qu'une reconstruction d'arborescence en php d'autant plus qu'en général un site web dynamique c'est 90% de puissance demandé à mysql et 10% de puisance utilisé par php.
Marsh Posté le 24-01-2006 à 15:39:40
En effet, je n'avais pas vu tout àa sous cet angle
Je n'arrive pas à m'en sortir et ça m'enerve !
Ca fait 1 semaine que je suis sur ce système d'arbo, et j'ai du mal à obtenir quelque chose qui me convient.
Je trouve trop compliquée ma manière de récupérer tous les enfants à partir d'un dossier donné.
Si j'ai les ID suivante (dossiers et sous dossier) :
4 -> 6 -> 8 -> 24 -> 12 -> 2 -> 7
(donc 7 etant un enfant de 2 lui meme enfant de 12 etc...)
Si l'utilisateur supprimer 4 il a 2 solutions, soit déplacer son contenu (donc là pas de problème, j'ai juste à changer l'ID Parent de 6, c'est tout.
Mais s'il choisi de supprimer tout le contenu, c'est déjà moins simple.
A partir de 4 il faut que je sache que je dois supprimer 6, 8, 24, 12, 2 et 7 (et surtout pas 1,3,48 etc...)
C'est ça qui m'embête. Alors que je pensais que ce serait simple ça ne l'est pas du tout.
Il faut donc une fonction suppression, qui supprime 4 et qui va chercher tous les ID ayant pour parent 4, pour chacun de ces ID il faut relancer la fonction en cherchant tous les ID ayant un parentId identique à chacun d'eux etc... Ca fait beaucoup de requete SQL s'il y a 50 dossiers à virer (ce qui sera surement rare voire inexistant)
Marsh Posté le 24-01-2006 à 16:26:26
Regarde si tu ne peux pas t'en sortir avec les contraintes SQL.
Certaines bases de données et mysql avec pour certains type de table savent gérer les dépendances et les supressions en cascade.
C'est peut être la solution pour toi pour la supression.
Sinon, il te faudra faire une fonction récursive (une fonction qui s'apelle elle même) afin de suprimer tous les décendant d'un dossier.
Marsh Posté le 24-01-2006 à 16:36:53
La fonction recursive est faite, mais c'est vrai que ça ne me plait pas trop. Par contre cette histoire de dépendance et de suppression en cascade me dit vaguement quelque chose, mais je ne suis pas assez familiarisé avec les SGBD pour m'en rappeler.
Je vais faire une recherche, ça serait super.
Merci beaucoup
Marsh Posté le 24-01-2006 à 17:13:21
Bon apparement ce n'est pas possible.
Il faut une table A avec un champ ID par exemple, et on peut créer une table B avec un champ B.ParentId qui serait lié à A.ID, si A.ID est supprimé tous les champs B.parentId le sont aussi.
Mais ça ne marche pas avec 1 seule table.on ne peux pas lier A.parentId avec A.ID
Marsh Posté le 24-01-2006 à 17:34:16
J'y suis enfin arrivé.
En fait si on ne considère que 2 colonne ID et PARENTID, avec une clause ON CASCADE DELETE, il fallait que j'insère d'abord un premier dossier ayant comme id ET parentid : 0
Maintenant ça marche Si je vire un parent, tous ses enfants sont supprimés aussi
Il ne me reste plus qu'à trouver si on peut en selectionnant 1 parent, selectionner tous ses enfants.
Marsh Posté le 24-01-2006 à 19:12:03
Il ne me semble pas que les dépendances puissent être utilisé afin de retrouver les enfants d'un noeud pendant une requette de type select.
Marsh Posté le 24-01-2006 à 20:02:56
C'est bien dommage ça ... pourtant cette relation existe bien quelque part. Elle peut être utilisée pour la suppression mais pas pour la selection ... ce n'est pas logique
Dommage
Je vais continuer à me renseigner, sur un autre topic on m'a dit que c'était possible avec les jointure, mais je ne m'y connais pas trop en jointure, alors j'ai demandé de l'aide
Marsh Posté le 24-01-2006 à 20:05:54
Comme mentionné plus haut, Oracle sait le faire avec
select...connect by...start with...
Il faudrait voir si mysql a un équivalent, mais j'en doute.
Marsh Posté le 24-01-2006 à 20:16:00
skeye a écrit : Comme mentionné plus haut, Oracle sait le faire avec |
Il n'y a pas d'quivalent. Ils nous promettent ça depuis la version 4.1 de MySQL
On en est à la version 5 et toujours pas de trace de cette fonction
Marsh Posté le 25-01-2006 à 01:22:37
et pour le problème d'arborescence, que pensez-vous de ça : http://sqlpro.developpez.com/cours/arborescence/ (2. Représentation intervallaire des arborescense).
Cette méthode me semble bien performante pour une arborescence avec de nombreux niveaux ou de nombreuses feuilles.
Vous en pensez quoi ?
Marsh Posté le 23-01-2006 à 15:41:47
Bonjour à tous,
Je vais essayer d'exposer mon problème le plus clairement possible.
Considérons la table MySQL suivante :
| ID | NAME | PARENT |
|----|------|--------|
| 1 | A | 0 |
| 2 | B | 0 |
| 3 | C | 2 |
| 4 | D | 0 |
| 5 | E | 0 |
| 6 | F | 3 |
| 7 | G | 2 |
| 8 | H | 0 |
Quel est selon vous le moyen le plus rapide et/ou le plus simple pour récupérer les ID d'une même arborescence.
On voit dans cette table, que l'ID 3 à pour parent l'ID 2, tout comme l'ID 7.
On voit également que l'id 6 à pour parent l'ID 3 (et par conséquent l'ID2 aussi)
J'aimerais pouvoir récupérer l'ensemble des ID "appartenant" par exemple à l'ID 2 (donc les ID 3, 6 et 7).
Je pense à une fonction de ce genre :
$allids = array();
function getTree($id) {
global $allids;
$query = 'SELECT parent FROM matable WHERE parentid=' . $id;
$result = mysql_query...
while($row = mysql_fetch_assoc...) {
$allids[] = $ids[] = $row['parent'];
}
foreach($ids as $currentId) {
getTree($currentId);
}
}
Comme ça au final j'ai toutes les Ids dans le tableau $allids.
Mais j'ai peur que ça fasse un peu lourd, et que si l'arborescence est complexe (beaucoup de dossiers et de sous-dossiers) ça balance des centaines de requêtes SQL ...
Donc je me demandais s'il n'existait pas un moyen dans MySQL (genre avec les jointures ou autre) de récupérer ainsi ces "imbrications" multiples?
Merci
---------------
Gamertag: CoteBlack YeLL