TourDeJeu, le réseau des jeux en ligne alternatifs : jeux web multijoueurs, jeux par forum. En savoir +

Flux RSS des discussions du forum : pour les joueurs, et pour les créateurs et MJ
  Reply to this topicStart new topicStart Poll

> Organisation Du Code
manakeo
Ecrit le : Dimanche 15 Octobre 2006 à 15h54
Quote Post


Pro
*

Groupe : Membre
Messages : 119


Bonjour à tous les programmeurs,

J'aurais une petite question au niveau organisation du code.

Est-il préférable d'avoir différentes tables du style:

tableNourriture / tableBoisson / tableMatiere / tableVetement / tableObjet


ou alors une seule table : tableCOmplete


Alors les deux ont des avantages et des inconvenients, j'arrive pas à me décider.
Par exemple dans son inventaire, pour afficher la liste des objets que l'on possède, il faudra faire une requete select dans chaque table, alors qu'avec une seul, une requete suffit.

si certain programmeurs ont une méthodes préférables, ou meme un autre...

voilou smile.gif


--------------------
MJ : Jeu par forum / pbem de Hard Science Fiction : Station Alpha

PMEmail PosterUsers Website
Top
Dal'Yth
Ecrit le : Dimanche 15 Octobre 2006 à 17h19
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


A première vue :
Je pense que les objets doivent être mis à part car ils ne sont pas tout le temps sur un joueur, ils peuvent être au sol, dans une maison, ...
Par contre des trucs comme boissons et nourritures tu pourrais peut être les regrouper.


Mais je ne connais pas ton jeu, donc je te conseille :
- de voir quand tu appelle ces tables
- comment et en quelle quantité (=> critères de sélection)
- quels vont être les critères de sélection : si tu appelle souvent les objets et les vêtements en fonction de la personne qui les porte, il vaut mieux une table commune. Par contre si tu affiche plus souvent les objets en fonction de leur position, une table séparée objet est plus pratique.
Réfléchi aussi au champ index que tu vas utiliser, ça peut t'aider à choisir.

Cela dit, c'est vrai qu'il n'y a pas de solution parfaite, comme tu l'a remarqué il y a des avantages et des inconvénients à chaque solution, il faut pourtant choisir.

J'espère avoir pu t'aider un peu smile.gif
PMEmail PosterUsers Website
Top
nygma
Ecrit le : Dimanche 15 Octobre 2006 à 21h24
Quote Post


Pro
*

Groupe : Membre
Messages : 129


perso, j'ai mis tous les objets dans une seule table.
chaque objet appartient à une famille d'objet.
chaque famille d'objet possède une instance spécifique dans des tables plus 'spécialisées'... (armes, sortilèges liés, lumières, etc...)


les objets pouvant être au sol, sur des persos, ou dans un autre objet etc... j'ai des tables de jointure pour les suivre.

franchement, je te conseille de regrouper tout ce qui a un traitement commun. Y'a rien de pire que de faire du code en double.
PMEmail PosterUsers Website
Top
Vantik
Ecrit le : Dimanche 15 Octobre 2006 à 22h45
Quote Post


Kid
*

Groupe : Membre
Messages : 44


Idem je pense que tout mettre dans la même table et d'ensuite faire des jointures serait le plus pratique.

Maintenant ça peux dépendre de ce que tu veux faire précisement, mais à mon avis dans la majorité des cas, une table unique est préférable.

A toi de voir wink.gif.
PMEmail Poster
Top
manakeo
Ecrit le : Dimanche 15 Octobre 2006 à 22h56
Quote Post


Pro
*

Groupe : Membre
Messages : 119


Merci pour vos réponse.

Le problème est qu'au bout de plusieurs milliers d'objet, la table sera lourde. ^^
Ce qui me fait douter est d'un point de vue "attribut". Chaque type d'objet a ses attributs comme: poids / attaque / defense / luminosité etc etc. Pour la pluspart des objets, ces attributs n'intervienne pas.

Bref, je pense donc rester sur la facon dont tout a été organisé, c'est a dire avec une seule table. J'espère ne pas a avoir a changer blink.gif


--------------------
MJ : Jeu par forum / pbem de Hard Science Fiction : Station Alpha

PMEmail PosterUsers Website
Top
Grouik
Ecrit le : Lundi 16 Octobre 2006 à 01h11
Quote Post


Kid
*

Groupe : Membre
Messages : 27


Salut,


J'imagine que tu utilises une base de données relationnelle (MySQL ?).

L'avantage du relationnel, contrairement aux bases de données de l'ancien temps, est de ne pas être obligé de tout stocker dans une seule table. Le principe étant de substituer à une grosse table unique plusieurs tables reliées entre elles par des relations définies (d'où le nom de ce type de bases).

Gain de structuration, gain de temps de requêtage... le seul point où l'on y perd est sur la compléxité des requêtes (encore que ce soit relatif, on a vu plus compliqué que le SQL).

Bref, je dirais :
1. si tu maîtrises suffisamment le SQL, ton choix devrait se porter sur plusieurs tables ;
2. si tu es une grosse quiche en SQL, ton choix devrait se porter sur une seule table (comme faisait papy en son temps) ou d'apprendre un minimum de SQL et d'opter pour l'option 1.

Celà dit, il ne faut pas être dogmatique et d'autres raisons que je ne connais pas (contraintes hébergeur, volumétrie attendue, compétence de co-développeurs, ...) impliquent peut-être le choix 2.


Remarque complémentaire sur la structuration en plusieurs tables :

Imaginons que tu ais à stocker des objets dont de la nourriture, des objets manufacturés incluants des armes et des vêtements. Toutes tes tables ne seraient pas au même niveau mais reprensenterais plutôt un arbre.

OBJET (id_objet, volume, poids)

NOURRITURE (id_nourriture, id_objet, duree_conservation, valeur_nutritive)

OBJET_MANUFACTURE (id_objet_manufacture, id_objet, nom_fabriquant, date_fabrication)

ARME (id_arme, id_objet_manufacture, resistance, degats)

VETEMENT (id_vetement, id_objet_manufacture, sexe, taille)

Ainsi, pour connaître le poids de l'arme d'identifiant 42, la requête aurait la forme suivante :
CODE
SELECT O.poids
FROM ARME A, OBJET_MANUFACTURE OM, OBJET O
WHERE A.id_arme=42
  AND A.id_objet_manufacture=OM.id_objet_manufacture
  AND OM.id_objet=O.id_objet;


En bonus, c'est conceptuellement plus facile à mapper si tu utilises un langage orienté objet pour ton site.


My 2 cents...


--------------------
"Personnellement, c'est pas Dieu qui me dérange, c'est son putain de fan club..."
PMEmail Poster
Top
Sybler
Ecrit le : Lundi 16 Octobre 2006 à 04h58
Quote Post


Ouf
*

Groupe : Membre
Messages : 453


J'ai aussi opté pour placer tout les objet dans une même table, et ce après avoir au préalable essayé réellement une structure séparée pour chaque type d'item.


Grosse table d'item:
- Permet de créer des items hybrides
- Évite de faire 15 requêtes pour lister un inventaire

Table multiples
- Fait plus jolie dans des graphique de modélisation, mais en pratique c'est très bof (enfin, dans mon cas ca donné un truc très bof)


Structure approximative de ma mega table:

id
type [arme, drogue, etc]
soustype [arme_feu, arme_blanche, drogue_pillule, drogue_injecte, etc]
perso_id (null= appartiend à aucun perso)
lieu_id (null= appartiend à aucun lieu)
.....

Le champs Type, perso_id et lieu_id sont en index, et ID en primary, ce qui permet de faire des recherches rapides.

A NOTER QUE MYSQL EXÉCUTE LES "WHERE" DE DROITE À GAUCHE.

Donc une requete comme celle-ci sera très rapide:
SELECT * FROM table WHERE type='drogue' AND perso_id=108;

Et celle-ci, très lente:
SELECT * FROM table WHERE perso_id=108 AND type='drogue';


Vu que la denière doit sélectionner TOUS les items drogues du jeu pour ensuite recherher uniquement les 2-3 du personnage.


=============================================
Edit:
Question personnelle pour Mr. "Quand t'es bon en SQL tu fais 6 millions de tables"

Si chaque item à une table de base, et une table de 'personnalisation':
Base+Personnalisation=1 item personnalisé dont la base reste gérable en masse en un seul point de contrôle.

Donc, déjà la, c'est 2 tables.
Maintenant j'ai 25 types d'items.

Je fais 50 tables ?, Soit 25 requêtes à jointure pour afficher la liste d'un inventaire ?!

Continuons l'excercice...
L'item peut-être possédé par un personnage, un lieu, ou une boutique... Surement qu'on devrait aussi segmenter alors, vu que MySQL est relationnel et si puissant.

50x3 = 150 tables

cool, maintenant explique moi comment ca sera pas vraiment plus chiant à programmer ... et surtout j'aimerais bien avoir un exemple de requête de jointure monstre qui va relier 150 tables pour adopter un shéma de ... hum... ouais, quatrième dimension !

Edit2: Ca sonne peut-être méchand, mais ca l'est pas dutout smile.gif


--------------------
user posted image
PMEmail PosterUsers Website
Top
nygma
Ecrit le : Lundi 16 Octobre 2006 à 07h57
Quote Post


Pro
*

Groupe : Membre
Messages : 129


il ne faut pas faire un table par type d'item.

il faut faire une table de types d'item.

en tout et pour tout, j'ai une vingatine de tables pour gérer les objets.

(nota, je ne gère pas les liquides)


pour le détail, voir ici :
Modèle de donnée.

C'est pas la toute dernière version, mais ça donne les grandes lignes.

Les tables importantes sont : *
base_type_objets_main
items_objets_main
base_types_objets_sorts_main
items_objets_pieces
items_objets_armes
items_objets_armures
items_ouvertures
....


A noter, pour certains objets TRES spécifique, il faut mieux faire des tables à part.
[edit] précision : quand je dis à part, c'est en plus de la table commune.[/edit]
(les clés, les armes, ....)
PMEmail PosterUsers Website
Top
the-gtm
Ecrit le : Lundi 16 Octobre 2006 à 08h10
Quote Post


Pro
*

Groupe : Membre
Messages : 130


D'accord avec le principe de mettre tous les items dans une même table.
Par contre :

QUOTE
A NOTER QUE MYSQL EXÉCUTE LES "WHERE" DE DROITE À GAUCHE.

Donc une requete comme celle-ci sera très rapide:
SELECT * FROM table WHERE type='drogue' AND perso_id=108;

Et celle-ci, très lente:
SELECT * FROM table WHERE perso_id=108 AND type='drogue';


C'était peut être vrai sur les toutes premières versions mais ça fait longtemps que l'optimiseur de requêtes arrive à gérer ce genre de cas. En tout cas sur MySQL 4 il fait les deux requêtes de la même manière.
PMEmail Poster
Top
manakeo
Ecrit le : Lundi 16 Octobre 2006 à 19h10
Quote Post


Pro
*

Groupe : Membre
Messages : 119


QUOTE
OBJET (id_objet, volume, poids)

NOURRITURE (id_nourriture, id_objet, duree_conservation, valeur_nutritive)

OBJET_MANUFACTURE (id_objet_manufacture, id_objet, nom_fabriquant, date_fabrication)

ARME (id_arme, id_objet_manufacture, resistance, degats)

VETEMENT (id_vetement, id_objet_manufacture, sexe, taille)


C'est exactement ce à quoi je pensais.
J'ai uncertain niveau en anlayse, merise UML etc, mais il est vrai que la théorie et la pratique... des fois cè relou.

Il est évident que pour avoir un truc propre, clair, il faut séparer. Le soucis étant que mysl a du mal avec l'héritage.
Ce qui provient de ce système de donnée.

Objet => classe mère
le reste: héritage de la classe objet.

AVec un code orientée objet, cela peut passer je pense, mais bonjour les requetes.
De plus a chaque fois que tu ajoutes une tables, donc un type d'objet, tu dois modifier toutes tes requetes?
A mois de gerer ca en objet unsure.gif


--------------------
MJ : Jeu par forum / pbem de Hard Science Fiction : Station Alpha

PMEmail PosterUsers Website
Top
Oelita
Ecrit le : Lundi 16 Octobre 2006 à 22h57
Quote Post


Alien
*

Groupe : Admin
Messages : 1589


A un moment ou à un autre, il faudra bien distinguer le traitement de ces objets... Si vous mettez tout dans une seule table, vous aurez des propriétés vides, par exemple un objet de nourriture n'a pas de propriété de dégâts. Donc même si vous faite un seul SELECT tout simple pour l'inventaire, va falloir tout séparer ensuite au niveau traitement pour ne pas afficher de propriété dégâts pour la nourriture, non ? donc ça me parait un peu artificiel de tout vouloir regrouper pour "simplifier".
Pis si vous rajoutez une propriété sur un type d'objet, faudra modifier tout le code pour tous les objets ?
Bref, ya du pour et du contre dans les deux cas.

Sur TdJ, j'avais regroupé certains trucs car ils avaient pas mal de propriétés communes (en l'occurrence, j'avais regroupé : les news, les annonces, les commentaires de focus, les commentaires de jeux)... et j'ai fini par les séparer plus tard, car marre de gérer les filtres sur les champs de "type" pour toutes les requêtes non communes. Pis ça alourdissait aussi les temps de réponse. Bref, sur la page du MJ qui regroupe les infos de son jeu (l'équivalent de l'inventaire, donc), j'ai donc maintenant 3 requêtes distinctes pour récupérer les news passées, les annonces passées et les derniers commentaires, au lieu d'une seule, mais au niveau code PHP c'est beaucoup + clair, je trouve.


--------------------
Oëlita la Gentille Hérétique
Admin TourDeJeu
user posted image

Le moyen le plus efficace pour me contacter ? @Oelita sur Twitter
PMEmail PosterUsers Website
Top
Sybler
Ecrit le : Mercredi 18 Octobre 2006 à 03h31
Quote Post


Ouf
*

Groupe : Membre
Messages : 453


QUOTE (the-gtm @ 16 Oct 2006, 07:10 )
D'accord avec le principe de mettre tous les items dans une même table.
Par contre :

QUOTE
A NOTER QUE MYSQL EXÉCUTE LES "WHERE" DE DROITE À GAUCHE.

Donc une requete comme celle-ci sera très rapide:
SELECT * FROM table WHERE type='drogue' AND perso_id=108;

Et celle-ci, très lente:
SELECT * FROM table WHERE perso_id=108 AND type='drogue';


C'était peut être vrai sur les toutes premières versions mais ça fait longtemps que l'optimiseur de requêtes arrive à gérer ce genre de cas. En tout cas sur MySQL 4 il fait les deux requêtes de la même manière.

Article d'Avril 2006:
http://www.dublish.com/articles/10.html


Tu as quelque chose d'officiel pour appuyer tes dires (pas que je ne te fasse pas confiance, mais j'aimerais voir ca d'écrit dans une documentation plus sérieuse)


--------------------
user posted image
PMEmail PosterUsers Website
Top
Haram turval
Ecrit le : Mercredi 18 Octobre 2006 à 10h43
Quote Post


Pro
*

Groupe : Membre
Messages : 126


J'ai fait des tests et il semble se confirmer que MySQL execute les WHERE de droite à gauche
En prenant une table existante de 2000 lignes et en faisant un WHERE composé de deux éléments (un champ indexé et l'autre non ), il y a des différences de temps de traitement en fonction de la position du champ indexé dans le where.

Le temps de traitement est 10-20% plus rapide en mettant d'abord le champ indexé puis le champ non indexé dans le WHERE.

Testé sur MySQL - 4.1.11


--------------------
Tant va la cruche à l'eau qu'à la fin elle est mouillée.
PMEmail Poster
Top
the-gtm
Ecrit le : Mercredi 18 Octobre 2006 à 20h27
Quote Post


Pro
*

Groupe : Membre
Messages : 130


Je me base sur le plan des requêtes (EXPLAIN) qui indique quels sont les index utilisés.

J'ai fait un test sur MySQL 4.1.10, sur une table de 2000+ lignes, avec une requête portant sur un champs indexé, un pas indexé (la requête ramène 100 lignes) :
10 000 requêtes pour initialiser le bidule
10 000 avec le champs indexé en 1er
10 000 avec le champs indexé en 2e

J'obtiens un temps environ 1% inférieur en mettant le champs indexé en fin de requête. Etant donné que le plan des deux requêtes est le même (utiliser l'index), la différence vient pour moi du temps pris par l'optimiseur pour calculer ce plan.

Bref pas de quoi casser trois pattes à un canard mais ça ne fait pas de mal de mettre le champs indexé à la fin.
PMEmail Poster
Top
Haram turval
Ecrit le : Mercredi 18 Octobre 2006 à 22h21
Quote Post


Pro
*

Groupe : Membre
Messages : 126


Attention lors des tests, le cache peut fausser les résultats si les requêtes sont lancées en boucle les une après les autres.
Dans mon cas, en lançant les requêtes en boucle, la différence devient négligible avec le nombre car seule la première exécution montre un écart.
Il est recommandé de changer les paramètres de requête à chaque exécution pour éviter d'avoir des résultats faussés par le cache.


--------------------
Tant va la cruche à l'eau qu'à la fin elle est mouillée.
PMEmail Poster
Top
Haiken
Ecrit le : Mercredi 18 Octobre 2006 à 22h56
Quote Post


Ouf
*

Groupe : Membre
Messages : 360


... ou de demander explicitement à ne pas mettre la requête en cache : "SELECT SQL_NO_CACHE id, name FROM customer"


--------------------
PMEmail Poster
Top
the-gtm
Ecrit le : Jeudi 19 Octobre 2006 à 08h12
Quote Post


Pro
*

Groupe : Membre
Messages : 130


J'ai rajouté SQL_NO_CACHE et j'ai fait varier les paramêtres de la requête, cette fois les résultats sont inversés : c'est un peu moins de 1% plus rapide en mettant le champs indexé en 1er... Bref les deux donnent le même résultat

Le problème en ne jouant la requête qu'une fois c'est que tu comptes le temps mis par la base pour compiler et optimiser la requête. Ce temps n'est pris qu'une fois parce que la base mets en cache le plan des requêtes (je ne parle pas des résultats ici). En plus quand tu as une requête qui dure quelques millisecondes, une imprécision de +/- 1ms est très importante. En pratique, c'est difficle d'avoir un résultat fiable sur une seule requête.

Globalement ce que voulait surtout dire c'est que la base optimise les requêtes pour utiliser les index au maximum. Si la clause where comprend un champs indexé c'est presque certain que l'index sera pris. S'il y en a plusieurs ça se complique ...
Pour ceux qui veulent des précisions : la doc mysql
PMEmail Poster
Top
Haiken
Ecrit le : Jeudi 19 Octobre 2006 à 22h18
Quote Post


Ouf
*

Groupe : Membre
Messages : 360


oui attention quand même, si je ne m'abuse le plan de requêtes n'est conservé qu'avec les requêtes préparées.

Attention aussi, les requêtes préparées ne sont jamais conservées dans le cache de requêtes (ce qui est fort dommage) donc à n'utiliser qu'avec d'infinies précautions. Détails ici
(ça concerne mysqli, et aussi PDO sauf dans les toutes dernières version de PHP)


--------------------
PMEmail Poster
Top
« Sujets + anciens | Programmer | Sujets + récents »

Reply to this topicStart new topicStart Poll