JeuWeb - Crée ton jeu par navigateur
Boucle UPDATE, RAND - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Boucle UPDATE, RAND (/showthread.php?tid=7787)

Pages : 1 2 3 4


RE: Boucle UPDATE, RAND - Xenos - 28-03-2017

Et t'as vraiment des milliers/millions de lignes, ou c'est juste la spéculation de "j'aurai 10k joueurs qui feront 1k villes"? T'auras toujours le temps d'améliorer la procédure plus tard.


RE: Boucle UPDATE, RAND - MeTaLLiQuE - 28-03-2017

Aux milliers de lignes, ca arrivera très vite... ce n'est pas de la spéculation Smile

Le million ca sera pour dans un moment quand même ^^


RE: Boucle UPDATE, RAND - Keltaïnen - 28-03-2017

(28-03-2017, 04:24 PM)Xenos a écrit : Non, tout dépend de la taille du buffer du serveur (et donc, de sa RAM). MySQL gère très bien les gros UPDATE de l'ordre du million de lignes, si on ne rate pas les index et qu'on lui fourni la RAM nécessaire.

Oula, qu'est-ce qui te fait affirmer ça ???
Quand on bosse sur des volumes en millions en général on n'utilise plus trop MySQL (ou au moins on se pose la question) mais là je pense qu'il y a des contraintes économiques puisqu'on est souvent dans des jeux amateurs ici. Du coup le volume mémoire (RAM) pour charger ne serait-ce que 1 million de données en mémoire (parce que c'est ce que fait ta méthode du INSERT) a intérêt à être conséquent pour ne pas pénaliser le reste de l'application et du coup cela reviendrait cher pour un jeu amateur.

L'indexation (dont il faudra aussi prévoir le stockage d'ailleurs) n'intervient qu'au niveau de l'update puisque tu fais une lecture full de la table et un insert derrière donc ce n'est pas ça qui va réduire le temps de traitement. Mais, même là, il faut un update full donc l'index n'optimise que la jointure (ça durerait des jours sans cet index à cause du produit cartésien).

@Metallique : d'ailleurs ça me fait penser que si tu as la possibilité de découper ton traitement pour ne pas exécuter tous les joueurs au même moment, ça peut peut-être être pas mal car tu seras confronté au temps d'écriture disque aussi sur les volumes que tu vas atteindre.


RE: Boucle UPDATE, RAND - Xenos - 28-03-2017

Ce qui me permet de l'affirmer, c'est qu'un test sur mon poste local d'un UPDATE sur 1M de lignes (RAND()) prend une poignée de secondes (5.506) et que les serveurs mutus d'OVH (pour l'exemple, et quand ils marchent!) sont souvent 2 à 3x plus rapide que mon poste.
C'est surtout l'affirmation arbitraire de "10000 lignes" que je voulais contrer.
L'index intervient aussi au niveau d'un INSERT, quand ce dernier doit être mis à jour (d'où le fait qu'ajouter des index partout n'est pas nécessairement efficace).

Après, si tu n'as pas de moyens, que tu veux rester sur MySQL, et que tu veux stocker le détail de chaque personnage de la population du joueur, alors je pense que tu as un soucis dans l'objectif général du jeu ou dans ton modèle.


RE: Boucle UPDATE, RAND - Xenos - 28-03-2017

Double-post, tant pis... Mais en réfléchissant un peu sur le chemin de la maison, ceci sera bien plus efficace (65k/6s chez moi, sachant que la 1ere procédure proposée en faisait en fait 65k/20s):


SET PROFILING := 1;
-- Ca, c'est pour mon initialisation
DROP TABLE IF EXISTS `integers`;
CREATE TABLE integers (
n INT UNSIGNED NOT NULL,
PRIMARY KEY (`n`)
) ENGINE=InnoDB;

INSERT INTO integers (n) VALUES (0),(1),(2),(3)/*,(4),(5)*/;
INSERT INTO integers (n) (SELECT i.n+(SELECT COUNT(*) FROM integers)*j.n FROM integers AS i INNER JOIN integers AS j WHERE j.n > 0);
INSERT INTO integers (n) (SELECT i.n+(SELECT COUNT(*) FROM integers)*j.n FROM integers AS i INNER JOIN integers AS j WHERE j.n > 0);
INSERT INTO integers (n) (SELECT i.n+(SELECT COUNT(*) FROM integers)*j.n FROM integers AS i INNER JOIN integers AS j WHERE j.n > 0);
SELECT MAX(n) FROM integers;

-- Ca, c'est la nouvelle table de population (colonnes en plus)
DROP TABLE IF EXISTS population;
CREATE TABLE population (
id INT UNSIGNED NOT NULL,
id_joueur INT UNSIGNED NOT NULL,
moral DOUBLE DEFAULT 0,
eat DOUBLE DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `idx_id_joueur` (`id_joueur`)
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `resources`;
CREATE TABLE resources (
id_joueur INT UNSIGNED NOT NULL,
quantite DOUBLE DEFAULT 0,
PRIMARY KEY(`id_joueur`)
) ENGINE=InnoDB;

INSERT INTO population (id, id_joueur) (SELECT n, CEIL(1000*RAND()) FROM integers);
INSERT INTO resources (id_joueur, quantite) (SELECT n, RAND()*100000 FROM integers WHERE n BETWEEN 1 AND 1000);

-- Fin de l'initialisation
-- Début du vrai algo

-- Là, c'est à toi de fixer l'algo disant combien de ressources veut la population
UPDATE population SET eat = RAND()*1000;

UPDATE population p
INNER JOIN resources r ON r.id_joueur = p.id_joueur
SET p.moral = IF(r.quantite >= p.eat, p.moral + 20, p.moral - 20),
r.quantite = IF(r.quantite >= p.eat, r.quantite - p.eat, r.quantite);

SHOW PROFILES;
SET PROFILING := 0;

Note que pour 400k populations, il faut 70 secondes, c'est pas franchement top niveau complexité, mais au moins, cela n'explose pas.

Après, ça illustre ce que je disais sur les procédures: il sera toujours temps, plus tard, de trouver mieux (ou de monter en puissance, ou de changer de SGBD au pire). Vu la masse de calcul que tu demandes, de toute façon, je doute que le moindre système soit capable de le faire en un claquement de doigts (hors système bricolés maison, qui chargent tout en RAM ou autre).


RE: Boucle UPDATE, RAND - MeTaLLiQuE - 28-03-2017

(28-03-2017, 06:35 PM)Xenos a écrit : Après, si tu n'as pas de moyens, que tu veux rester sur MySQL, et que tu veux stocker le détail de chaque personnage de la population du joueur, alors je pense que tu as un soucis dans l'objectif général du jeu ou dans ton modèle.

C'est-à-dire ? Aller sur un autre SGDB ?


RE: Boucle UPDATE, RAND - Xenos - 28-03-2017

Il parait que Oracle est plus véloce que MySQL, et que son optimzeur est plus aboutit. Je ne sais pas si c'est vrai. j'ai aussi déjà entendu que "ouais, MariaDB/PostGre c'est carrément mieux, prends ça", je ne suis pas sûr que ce soit vrai...

Sinon, petit test sur un mutualisé OVH: 65k populations, moins d'1s (genre 800ms, bon, c'est mesuré au pif, mais c'est l'ordre de grandeur). Quoi qu'il en soit, tu ne feras jamais mieux en sortant les données pour les traiter dans le PHP.
ECLERD v0 est fait comme cela (sortir les infos de la BDD, calculer en PHP, mettre à jour), conséquence: 5 minutes de temps de calcul total pour simuler l'avancement du temps sur la planète. Que j'ai donc découpé par batch, lancé au hasard (d'où le fait que certaines pages prennent 10 secondes). J'ai fait quelques essais en local avec l'autre approche (procédures stockées), et je tombe à 3-4 secondes (en gros, car je n'ai pas repris toutes les règles du jeu). Sachant qu'en local sur cette nouvelle mouture, j'ai 100x plus de cases dans la carte.

& pour rappel, quand je dis "65k populations", c'est "65k mises à jour". Si tu te limites uniquement au joueur qui visite la page, ce sera instantané. Avec un CRON régulier si besoin (t'en n'auras sûrement pas besoin mais bon).


RE: Boucle UPDATE, RAND - MeTaLLiQuE - 28-03-2017

Mais pour envisager du PosteGre, faudrait avoir déjà une grosse quantité de données car, pense pas qu'il soit optimisé pour des petites quantités de données... après MariaDB pas regardé... à voir...

Le script est lancé à minuit pour tous les joueurs. Ce qui mettra énormément de temps pour traiter tous les joueurs... Je vais essayer avant de tester les procédures stockées, de mettre l'ID de la ligne dans un array et utiliser le INSERT INTO ON DUPLICATE KEY à la fin, voir ce que ca donne...

EDIT : Sinon, pour éviter de mettre un RAND(), je crée une colonne "priorité" qui sera mis à jour chaque jour et au moins, là il n'y aucun qu'une seule requête avec un ORDER BY priority ASC LIMIT x ...


RE: Boucle UPDATE, RAND - Ter Rowan - 29-03-2017

(28-03-2017, 03:13 PM)Keltaïnen a écrit : Je viens de tester sur un MySQL 5.7, le RAND() est maintenant appliqué individuellement sur chaque ligne lors d'un update donc on se casse les pieds pour rien, à ce niveau là du moins.

chuis trop une star Wink


RE: Boucle UPDATE, RAND - Ter Rowan - 29-03-2017

Et sinon, j'ai quand même du mal à comprendre l'intérêt GP d'avoir pour un joueur plusieurs centaines / milliers de personnages individualisés.

Pourquoi ne pas tout simplement créer des catégories :

serf / en forme / bon moral / 10
serf / en forme / mauvais moral / 5
serf / pas en forme / bon moral / 8
serf / pas en forme / mauvais moral / 4
bourgeois / en forme / bon moral / 4

la ça fait 12 enregistrements par joueur, quand même plus simple coté volumétrie

ca fait déjà pas mal de  valeurs à connaitre pour le joueur et de toute façon quel joueur va aller chercher le personnage 3452 pour lui faire faire quelque chose ?

Eventuellement, transformer une unité de la masse en "héros" individuel si besoin mais pas traiter toute la population individuellement