Gestion des relations => schéma de la BDD

Gestion des relations => schéma de la BDD - SQL/NoSQL - Programmation

Marsh Posté le 23-03-2020 à 18:09:52    

Je dois ajouter dans ma base de donnée une notion de relation entre les utilisateurs (pour le moment on va faire simple ami ou pas).
 
Je ne sais pas trop comment faire mon schéma de base car dans les 2 cas je vais avoir pas mal de jointure à faire, et je ne suis pas sur de ce qui est le plus performant...
 
Hypothèse 1 :  une table représentant la relation avec sa réciprocité

Code :
  1. user_friends : id_user_a statut_user_a date_user_a id_user_b statut_user_b date_user_b
  2. id_user_{a,b}  = ma clé dans la table user
  3. date_user_{a,b}  = date de la dernière modification de statut effectué par l'utilisateur
  4. statut_user_{a,b} = waiting / accepted / refused
  5. avec une règle dans mon code pour lors d'insertion maintenir que id_user_a < id_user_b


Dans ce cas, quand on demande quelqu’un ({id1}) en ami mais que celui-ci  ({id2}) n'as pas encore accepté, on se retrouves avec une ligne comme celle là :

Code :
  1. | {id1} | accepted  | 2020-03-23 | {id2} | waiting | NULL |


Ce qui me donnerait des requêtes pour trouver l'email des amis de l'utilisateur {ID} du genre :

Code :
  1. SELECT uf.*, a.email AS email1, b.email AS email2
  2. FROM user_friends uf
  3. INNER JOIN user a ON a.id_user = uf.id_user_a
  4. INNER JOIN user b ON b.id_user = uf.id_user_b
  5. WHERE uf.id_user_a = {ID} OR uf.id_user_b = {ID}


Du coups des résultats assez brut avec forcément pas mal de process en php derrière pour trier si ce qui nous intéresse vient de a ou de b, si le statut est bien validé ou non, etc...
Sachant que derrière, suivant les affichages je serais ptet amener a faire d'autre requêtes jointe par rapport au user (avatar, badges, etc.)
 
Hypothèse 2 :  une table représentant la relation que du point de vue de la personne

Code :
  1. user_friends : id_user statut date friend_id


Cette fois, quand on demande quelqu’un en ami mais que celui-ci n'as pas encore accepté on se retrouves avec deux lignes :

Code :
  1. | {id1} | accepted  | 2020-03-23 | {id2} |
  2. | {id2} | waiting | 2020-03-23 | {id1} |


Ce qui cette fois me donnerait des requêtes de ce genre :

Code :
  1. SELECT uf.*, f.email, fs.statut AS friend_statut, fs.date AS friend_date
  2. FROM user_friends uf
  3. INNER JOIN user f ON f.id_user = uf.friend_id
  4. INNER JOIN user_friends fs ON fs.id_user = friend_id
  5. WHERE uf.id_user_a = {ID}


Ce que j'aime dans cette version c'est que le résultat SQL est tout de suite bien plus clair et exploitable que la version 1, mais en terme de ressource j'ai l'impression que c'est plus gourmand non ?
Et je n'aimes pas trop l'idée d'avoir 2 lignes dans une même table ?
 
Je serais curieux d'avoir d'autres avis...


Message édité par mechkurt le 23-03-2020 à 18:56:36

---------------
D3
Reply

Marsh Posté le 23-03-2020 à 18:09:52   

Reply

Marsh Posté le 24-03-2020 à 11:18:28    

J'aime pas réfléchir en termes techniques. D'un point de vue fonctionnel, on veut la liste des demande d'ami émises par une personne. Une demande concerne deux personnes, et a un statut: l'acceptation ou non par la personne cible.
 
Je ferais donc une table avec quelque chose comme ta solution 1 mais sans l'état "accepted " pour id1, car on se doute que si il demande quelqu'un en ami, il est d'accord.

Reply

Marsh Posté le 24-03-2020 à 12:00:50    

Ben oui mais en faite dans 1 ans N°1 vas ptet changer d'avis sur son amitié et donc changer son état...
 
...mais il faudra que la relation existe encore chez N°2 (en mode N°1 vous a rejeté, c'est cruel hein ^^).
 
La question se posera peut-être de supprimer la relation quand les 2 seront en refused pour alléger la table, mais ça peut quand même être pratique de voir "ses anciens amis"


---------------
D3
Reply

Marsh Posté le 24-03-2020 à 12:13:20    

L'état passera de ACCEPTED a REJETE_DEMANDEUR non?

Reply

Marsh Posté le 24-03-2020 à 13:34:03    

Hum, oui je supposes que ça pourrait, mais en fait distinguer les états de chaque user me semble pertinent pacqu'au cour du temps, une "amitié" peu évoluer des 2 cotés : oui,oui / oui,non / non,oui / non,non...
 
Enfin c'est comme ça que je vois les choses mais je suis ptet a cote de la plaque...
 
...d’où mon post ?


---------------
D3
Reply

Marsh Posté le 25-03-2020 à 11:15:43    

La première solution me paraît plus adaptée pour gérer des relations symétriques. Dans ce cas, il y a effectivement le statut du user 1 qui est de trop. Cette solution permet aussi de savoir plus facilement qui a initié la relation si on fait sauter la règle id1 < id2 qui n'a pas de sens et n'apporte rien à mon avis (dans ta requête d'extraction, tu es obligé de faire un OR sur les 2 ID).
 
Mais tu as indiqué que le demandeur pouvait finalement refuser la relation. Et c'est vrai, les relations humaines ne sont pas symétriques. Du coup, la solution 2 me paraît plus adaptée pour gérer l'évolution des relations dans le temps. Et si tu ajoute un ID de relation incrémental, Tu pourras aussi savoir qui a initié la relation puisque cet ID sera < l'ID de la 2ème relation.
 
Edit : pour la date, je te recommande de mettre date/heure. Ca te permettra de mesurer plus finement le temps écoulé entre la demande et la réponse. S'il est court, on peut penser que le 2ème user en avait très envie de cette relation. S'il est long, soit la personne n'était pas très pressée, soit elle n'était pas dispo pour répondre. Ca permet de faire du big data. ;)


Message édité par rufo le 25-03-2020 à 11:22:13

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 25-03-2020 à 15:38:26    

Pour le moment; je suis partis sur le modèle 1 avec lequel je suis "intuitivement" plus à l'aise...
Au lieu d'avoir un statut a et un statut b on pourrait effectivement avoir un meta statut a et b résumant toutes les combinaisons mais le jour ou on voudra trouver les gens en attente de réponse de {id1] la requête sera plus compliqué (en hypothèse 1, en 2 on est bon).
Pour le champs date, je suis partis sur  yyyy-mm-dd pacque pour le moment perf >> stats, mais on est pas encore en prod donc j'interrogerais le client sur la pertinence de l'information (et comme il n'a aucune idée de l’optimisation des données on prendra surement un DATETIME complet ! ^^).


---------------
D3
Reply

Marsh Posté le 25-03-2020 à 16:16:39    

Je préfère la v2 d'assez loin, perso, surtout si tu veux éventuellement pouvoir conserver un historique complet des demandes/acceptations/refus/changements d'avis (auquel cas il faut ajouter un id spécifique à cette table et autoriser les (id1, id2) non uniques).


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 25-03-2020 à 17:10:10    

C'est une option auquel j'ai pensé, mais j'ai peur de me retrouver avec user * user * 1.5 lignes (stats au doigt mouillé) et donc une table qui a elle seul me fait ramer le serveur entier...
 
...bon quand on en sera la on aura surement une forme de cache mais quand même, pas convaincus par le rapport utilité / cout machine.
 
Je notes néanmoins ton intérêt pour la 2 !


---------------
D3
Reply

Marsh Posté le 25-03-2020 à 17:12:53    

mechkurt a écrit :

C'est une option auquel j'ai pensé, mais j'ai peur de me retrouver avec user * user * 1.5 lignes (stats au doigt mouillé) et donc une table qui a elle seul me fait ramer le serveur entier...
 
...bon quand on en sera la on aura surement une forme de cache mais quand même, pas convaincus par le rapport utilité / cout machine.
 
Je notes néanmoins ton intérêt pour la 2 !


 
C'est quoi le volume en users envisagé?


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 25-03-2020 à 17:12:53   

Reply

Marsh Posté le 25-03-2020 à 17:20:15    

Si on en croit mon client, Facebook...
 
..moi j'en sais rien mais j'aimerais bien pouvoir me dire que la V1 va tenir avec 100 000 comptes actif et une centaine simultané...
 
Sachant que rapidement faudra mettre en cache toutes les requêtes possible (contenu, menu, user ayant une session active, etc.), et que c'est typiquement le chose qui n'aura pas besoin d'être "live" sauf éventuellement sur la page dédié à la gestion.


---------------
D3
Reply

Marsh Posté le 25-03-2020 à 17:28:27    

mechkurt a écrit :

Si on en croit mon client, Facebook...

 

..moi j'en sais rien mais j'aimerais bien pouvoir me dire que la V1 va tenir avec 100 000 comptes actif et une centaine simultané...

 

Sachant que rapidement faudra mettre en cache toutes les requêtes possible (contenu, menu, user ayant une session active, etc.), et que c'est typiquement le chose qui n'aura pas besoin d'être "live" sauf éventuellement sur la page dédié à la gestion.


facebook, mais avec tous les utilisateurs amis avec tout le monde si j'en crois ton calcul? :D

 

Dans tous les cas, en phase de conception ne te focalise pas sur des problèmes de perfs supposées, commence par la version la plus "propre" possible. Il sera bien temps de s'occuper des perfs quand le truc sera suffisamment proche de la prod pour regarder ce qu'il se passe en chargeant un max de données fictives...:D


Message édité par skeye le 25-03-2020 à 17:28:44

---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 25-03-2020 à 18:00:19    

Oui le user * user est un tantinet discutable avec le recul ! ^^
 
Et je suis sans doute dans l'optimisation prématuré, mais y'a tellement de truc à faire sur ce projet, si je pouvais éviter de les faire 2 fois...
 
Et pour mon problème, j'aurais dut faire un sondage en faite, pacque la je suis toujours aussi perdu, enfin y'a un début de biais pour la 2ème (Skeye Flo850 et 1/2 Rufo).


---------------
D3
Reply

Marsh Posté le 25-03-2020 à 19:01:04    

Moi, je suis pour la solution 2 du fait que les relations humaines ne sont pas symétriques. C'est mon avis définitif. Je disais simplement que la solution 1 se défendait si on était dans un cas de relation symétrique.
 
La taille de l'appli : Facebook ? :heink: Ton client, il se la raconterait pas un peu ? Quand on voit comment rament les solutions alternatives de réseaux sociaux  (genre, Diaspora qui n'est pas centralisée), ça me paraît peu crédible.
 
Au passage, t'as pris quel SGBD ? Sur du MySQL, pour ta table des relations, je t'aurais recommandé le partitionnement mais si ton client voit les choses en grand comme ça, j'aurais tendance à dire que t'es parti sur une BD NoSQL pour faciliter la montée en puissance, non ?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 26-03-2020 à 10:20:11    

rufo a écrit :

Moi, je suis pour la solution 2 du fait que les relations humaines ne sont pas symétriques. C'est mon avis définitif. Je disais simplement que la solution 1 se défendait si on était dans un cas de relation symétrique.


Ben le cas 1 gère tout aussi bien l'asymetrie, sinon je ne l'aurais même pas envisagé, j'ai un état pour chaque user dans ma ligne !
J'aurais put avoir un seul état "commun" avec toutes les combinaisons possible mais ça me semblait bien plus compliqué pour un gain perf sans doute relativement modeste...
 

rufo a écrit :

La taille de l'appli : Facebook ? :heink: Ton client, il se la raconterait pas un peu ? Quand on voit comment rament les solutions alternatives de réseaux sociaux  (genre, Diaspora qui n'est pas centralisée), ça me paraît peu crédible.


A moi aussi j'ai un peu de mal à croire au succès du projet (en tout cas à cette échelle), après on n'est pas non plus exactement en concurrence avec Facebook, plutôt une espèce de complémentarité mais je ne peux pas trop en dire...
Pour le moment on part que sur 2 langues (fr + en) donc les millions d'utilisateurs, ce ne sera pas pour tout de suite ! ^^
 

rufo a écrit :

Au passage, t'as pris quel SGBD ? Sur du MySQL, pour ta table des relations, je t'aurais recommandé le partitionnement mais si ton client voit les choses en grand comme ça, j'aurais tendance à dire que t'es parti sur une BD NoSQL pour faciliter la montée en puissance, non ?


Ah ben moi je ne sais faire que du Mysql, on fera la première montée en charge avec un serveur dédié un peu musclé, puis 2 (avec 1 dédié à la BDD), et après je penses qu'a ce niveau, ils auront les moyens d'embaucher "les gens qui savent" ! ^^


---------------
D3
Reply

Marsh Posté le 26-03-2020 à 13:38:36    

Si tu es sur MySQL, je te recommande de tuner le fichier de conf pour augmenter la taille de certaines variables de conf :o
Les gains peuvent être importants.
 
Autre argument pour a solution 2 : le OR dans une requête SQL, ça peut te flinguer les perfs. Mieux vaut privilégier les requêtes à base de AND que de OR ou IN (qui est en fait un OR). Par ailleurs, si la solution 2 permet de faire moins de traitement côté PHP, y'a pas à hésiter pour faciliter la montée en puissance. De plus, dans le cas où vous passeriez sur une BD NoSQL distribuée, les algos de big data (mapreduce par ex) seront plus adapté à la solution 2.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 26-03-2020 à 13:52:36    

rufo a écrit :

Si tu es sur MySQL, je te recommande de tuner le fichier de conf pour augmenter la taille de certaines variables de conf :o
Les gains peuvent être importants.
 
Autre argument pour a solution 2 : le OR dans une requête SQL, ça peut te flinguer les perfs. Mieux vaut privilégier les requêtes à base de AND que de OR ou IN (qui est en fait un OR). Par ailleurs, si la solution 2 permet de faire moins de traitement côté PHP, y'a pas à hésiter pour faciliter la montée en puissance. De plus, dans le cas où vous passeriez sur une BD NoSQL distribuée, les algos de big data (mapreduce par ex) seront plus adapté à la solution 2.


Pour le moment et en phase de test on est sur du mutualisé, mais dès qu'on aura passer un certain nombre d'inscrits, on prendra un dédié et je ferais un peu de mysqltuner.pl ^^
 
En tout cas, tes arguments sur les JOIN moins couteux que les OR m'ont convaincu, je vais réorienter mon développement sur l’hypothèse 2...


Message édité par mechkurt le 26-03-2020 à 14:11:13

---------------
D3
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed