Se connecter
Se connecter

ou
Créer un compte

ou
Agrandir
Les Mains dans le Cambouis
Bidouille & Développement Informatique

Le pub des programmeurs

  • 1 927 réponses
  • 117 participants
  • 124 530 vues
  • 130 followers
Sujet de la discussion Le pub des programmeurs
Salut :coucou: y a des programeurs sur AF si oui vous bossez sous quoi ?
Afficher le sujet de la discussion
1881
Ha non l'index a 4 colonnes je suis d'accord c'est pas beau, là c'est sans doute plus un problème de besoin pas bien identifié comme a souligné Krisfrom.
1882
Citation de krisfrom78 :
Perso, identifier ton besoins en partant direct sur les CREATE TABLE ça me semble un peu compliqué.
Avant de modéliser, et pour notre (en tout cas la mienne) compréhension de ton objectif, je pense qu'il faudrait commencer par poser quelques questions basiques en mode texte du type :
- Un client peut-il avoir plusieurs fournisseurs ?
- Un fournisseur peut-il avoir plusieurs clients ?
- Un fournisseur à t'il plusieurs adresses ?
- etc...

ça permet d'identifier les relations 1,1 / 1,N / N,N pour ensuite construire un modèle relationnel...


- Une personne peut être ami avec plusieurs personnes.

Du coup je voyais le truc comme ca: A est ami avec B = Une relation (A, B) + relation inverse (B, A) et les informations de cette relation stockées dans une autre table.
1883
Oui là tu as deux tables : personne, relation.

Avec : relation(A,B) = relation(B,A)
1884
Après l'index a 4 colonnes je sais pas pourquoi j'ai fait ca, j'imaginais qu'il fallait faire en sorte qu'une `relationship_infos` soit bien lié à deux autre `relationship`.

Mais si un id suffit alors ca me va. Je ne connais pas bien les bonne pratiques en fait.

Pour la relation inverse je me basais sur différents posts sur dba.stackexchange et sur ce post notamment sur Quora:
Citation :
How does Facebook maintain a list of friends for each user? Does it maintain a separate table for each user?

Citation :
I work in Serwis społecznościowy nk.pl - platforma komunikacji dla wszystkich internautów - nk.pl which used to be the largest social network in Poland, and I can tell you one thing: such relations need to be stored "in both ways". Others have suggested here, that you can use a single table `friendship` with two columns `user_a`, `user_b` and maintain single row for each frendship. This is a very bad idea for scalability and simplicity of code. As you can see in Marcus Matos answer it quickly leads to massive UNIONS and complicated "ifology" in JOINs as each edge must be double checked in both directions. Moreover this makes sharding (spliting the database across many machines) almost impossible.
What we do instead is add two edges: for example if user #17 adds user #36 to her friends list, we perform two INSERTs for (17,36) and (36,17).
This way list of friends of a single user can be retrieved with a single, simple select.
Also, we shard the database using `shard_number=user_a MOD number_of_shards` which lets us retrieve whole friends list in a single query to a single machine.
It also makes "friends-of-friends" and "common-friends" problems a bit easier, but frankly, even Serwis społecznościowy nk.pl - platforma komunikacji dla wszystkich internautów - nk.pl has more than 4 bilion edges, and handling this in real time is a bit tricky, so we actually have batch jobs which run at night, so that propositions of people you might know are cached and available in the morning.

To make my point more convincing: we've actually used the approach with single friendship = single row, for two years IIRC, and it was a mess!

One more thing: you can make sure that you always perform the two INSERTs in the same order you perform two DELETEs (for example by using lexicographic ordering) and then if there is some integrity problem (one database has a row, but the symmetric row is missing) you can easily tell what was the last operation that failed and restore the consistent state.
For example if you see that there is (36,17) row, but (17,36) is missing, then it must mean, that there was DELETE (17,36), DELETE (36,17) transaction which failed in the middle.


Après j'ai aussi vu ce post qui a une approche différente: https://www.alibabacloud.com/blog/social-friend-relationship-system-practice-in-postgresql---accelerating-queries-of-positive-and-negative-relationships_595043

[ Dernière édition du message le 21/02/2020 à 14:44:33 ]

1885
Perso, pou rce genre de choses, je passe en NoSql et je stocke une liste de chaque cote avec les connexions. Tant que tu n'as pas des milliers de liens, ca peut passer.
1886
Qu'est-ce que ca apporte en vrai, le nosql par rapport a un sgbdr ? J'ai encore du mal a m'en rendre compte

Pour mon app je suis passe de mysql a mongodb. Parce que je traite que des donnees en json et que mongodb enregistre littéralement en json et que j'ai besoin de rajouter a la volée de nouvelles propriétés sans me prendre la tête avec des migrations. Mais aussi parce que c'est hype, mongodb.

Le chien aboie mais n'invente pas le fil à décongeler le beurre.

Les 6l6, des lampes qui nous éclairaient

1887
Citation de miles1981 :
Perso, pou rce genre de choses, je passe en NoSql et je stocke une liste de chaque cote avec les connexions. Tant que tu n'as pas des milliers de liens, ca peut passer.


Oui mais tu dois bien stocker les informations sur ces connexions quelque part?
1888
Citation :
Others have suggested here, that you can use a single table `friendship` with two columns `user_a`, `user_b` and maintain single row for each frendship. This is a very bad idea for scalability and simplicity of code.


Effectivement, la bonne solution n’est pas forcément la même pour mille personnes ou plus d’un million.
1889
Après quelques petites recherche en me basant sur le post du blog aliabacloud, je suis arrivé à un truc complètement différent:

CREATE TABLE account(
    id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    friends_id INTEGER[]
);

CREATE TABLE relationships_informations(
    id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    uids INTEGER[]
);
CREATE INDEX users_id ON relationships_informations USING GIN (uids);


On a deux tables:
- "account" avec l'id du compte plus un array d'entier contenant la liste d'id des amis "friends_id"
- "relationships_informations" pour les infos d'une relation entre X et Y, avec un id et un array d'entier pour stocker les id des deux account qui sont copaing.
- On créé un index sur le tableau d'entier.

Exemple:

-- account(id=A, friends_id =(A.friends_id + B))
-- account(id=B, friends_id =(B.friends_id + A))
-- relationships_informations(id, uids=int[A.id, B.id], foo=bar, baz=spam)


On a Deux comptes: A et B
A devient ami avec B.

Donc on ajoute B dans la liste d'amis de A: "account(id=A, friends_id=(A.friends_id + B))"
Puis on ajoute A dans la liste d'amis de B: "account(id=B, friends_id=(B.friends_id + A))"

Enfin on crée une "relationships_info": "relationships_informations(id, uids=int[A.id, B.id], foo=bar, baz=spam)" Avec un array d'entier contenant l'id des deux accounts + toutes les données sur la relation.

Conclusion:
Du coup j'ai plus de tables relation + relation inversé.

Pour récupérer les listes d'amis:
- Je peux facilement récupérer la liste de mes amis.
- Ou la liste des amis de mes amis en concaténant ces listes puis en faisant un uniq(sort(liste_damis_de_mes_amis)), idem pour amis des amis de mes amis et ainsi de suite.

Pour récupérer les infos sur les relations:
- Pour une relation il me suffit de faire un select et de vérifier que la colonne "uids" contient bien mes deux ids.
- Pour plusieurs relations avec l'id d'une personne je peux faire un select dans la table "relationships_infos" sur la colonne "uids" en vérifiant qu'elle contient bien mon id.
- Idem avec l'id de plusieurs personnes en utilisant un "ANY" ou un truc du genre(je ne sais pas si ca existe en SQL).

Après je ne sais pas si je peux créer un type d'array qui doit contenir obligatoirement deux entier différents.
Ce qui éviterait que des données foireuse soient rentrées genre un array de 0,1,3 ou plus d'items.

J'ai vu qu'on pouvait faire un "CREATE UNIQUE INDEX" mais j'imagine que sur une colonne de type array ca doit pas être possible.

Après j'imagine qu'il vaut mieux faire un sort() de chaque array avant enregistrement, pour éviter les doublons du type [1,2], [2,1].

Peut-être qu'un autre type serait envisageable sur la table relationships_infos, je sais pas.

[ Dernière édition du message le 21/02/2020 à 16:32:13 ]

1890
Citation de deozza :
Qu'est-ce que ca apporte en vrai, le nosql par rapport a un sgbdr ? J'ai encore du mal a m'en rendre compte

Pour mon app je suis passe de mysql a mongodb. Parce que je traite que des donnees en json et que mongodb enregistre littéralement en json et que j'ai besoin de rajouter a la volée de nouvelles propriétés sans me prendre la tête avec des migrations. Mais aussi parce que c'est hype, mongodb.

Principalement, tu n'as pas le concept de requetes join. Donc ca change fondamentalement la maniere de voir les schemas de bdd, puisqu'il n'y a plus de schema.
Pour des donnees peu structurees, avec des trous, des listes variables, c'est le top, je trouve.
Apres, c'est aussi que les schemas de bdd, ca me sort par les trous de nez.

Citation de Truelle :
Citation de miles1981 :
Perso, pou rce genre de choses, je passe en NoSql et je stocke une liste de chaque cote avec les connexions. Tant que tu n'as pas des milliers de liens, ca peut passer.


Oui mais tu dois bien stocker les informations sur ces connexions quelque part?

Oui, dans la structure associee a la personne. Donc typiquement:

{
id:"",
name:"toto",
connections:["tata", "tutu"]
}

Apres, les problemes de synchro quand on met a jour sont pas simple non plus, mais on peut faire un batch, et si je me souviens bien les batchs font effet de transaction. Donc si tu peux faire un batch, ca va.

[ Dernière édition du message le 21/02/2020 à 16:48:18 ]