MYSQL - Recherche d'un "SELECT" hasardeux non "équiprobable" ! - SQL/NoSQL - Programmation
Marsh Posté le 16-07-2004 à 07:58:42
ReplyMarsh Posté le 16-07-2004 à 09:05:53
Bon je vais me hasarder à donner une réponse.
Tu enregistres tes sommes dans la table:
|
et puis tu fais qqch de ce style-là:
SELECT TOP 1 cle FROM table WHERE total > RAND(60) ORDER BY total ASC
Mais je ne connais pas MySQL alors je sais pas si RAND est utilisable dans ce contexte (sinon tu le génères en PHP quand tu construis ton query) ... et le "TOP 1" ça vient de mes souvenirs de Sybase, en MySQL je crois que c'est avec "LIMIT" qu'il faut travailler.
Evidemment, maintenir le total dans la table est délicat quand tu dois modifier les valeurs... à toi de voir si ça vaut la peine.
Marsh Posté le 16-07-2004 à 09:51:53
Je vais probablement dire une grosse connerie mais bon (cai vendredi )
Etant donné que dans le ORDER BY, le rand() est réévalué à chaque fois, est ce que ce n'est pas possible de faire un calcul simple : on multiplie la valeur aléatoire obtenue par la valeur de pondération de chaque enregistrement :
... ORDER BY (rand() * (la_colonne_qui_va_bien_ou_il_y_a_le_rapport))
là où la_colonne_qui_va_bien_ou_il_y_a_le_rapport est 10/60, 20/60... dans ton exemple (oui il faut utiliser une nouvelle colonne, ou alors recalculer a chaque fois le rapport...
Marsh Posté le 16-07-2004 à 10:03:59
hop le fou a écrit : (oui il faut utiliser une nouvelle colonne, ou alors recalculer a chaque fois le rapport... |
Pour quoi faire? vu que tu divises partout par la même valeur quel est l'intéret?
Marsh Posté le 16-07-2004 à 10:08:12
skeye a écrit : Pour quoi faire? vu que tu divises partout par la même valeur quel est l'intéret? |
Bof, c'est juste pour éviter de refaire la division à chaque fois (je ne sais pas combien il y a d'enregistrement dans sa table ni si elles sont modifiées de temps en temps ou pas... donc ca dépend de son cas)
Et puis ca évite de devoir recalculer la somme (mais bon en meme temps bonjour le controle des données lors de mise à jour si ma solution...)
Marsh Posté le 16-07-2004 à 13:21:52
dividee a écrit : Bon je vais me hasarder à donner une réponse.
|
C'est PAS MAL DU TOUT
Petit génie
Le seul inconvénient de ta stratégie, c'est qu'il faudrait une autre table, et donc effectuer une fois le calcul...
Mais, c'est déjà bien mieux que ma méthode "pas terrible" dichotomique qui regarde dans quel segment on trouve !
Félicitations !!!!
je vais pinailler là dessus...
mais n'y aurait-il pas un moyen d'avoir directement les valeurs cumulées via mysql ??? je crois que OUI !
il existe une fonction...
dans ce cas, il faudrait tout simplement... l'utiliser en temps réel et faire l'inéquation intelligente que tu as écrite...
ET OUI ! c'est bien VU le coup du LIMIT
car, en effet, il faudra faire un LIMIT 1... pour être sûr d'obtenir seulement LE RESULTAT "juste après" l'inégalité... (pour n'en avoir qu'UN SEUL en effet)
bon, je médite là dessus
Marsh Posté le 16-07-2004 à 13:25:50
Tenez ! S'il y a un gars qui souhaite voir un peu la tête de ma fonction dichotomique fonctionnant avec le principe suivant :
on recherche dans quel segment on retombe [$i_min..$i_max] afin de mieux pouvoir en déterminer la valeur du "pif pondéré" obtenu !
Code :
|
Marsh Posté le 16-07-2004 à 13:42:13
Bon, j'ai médité...
Mais, en admettant qu'on mette un champs (un peu inutile) qui s'appelle [pts_cumules] (on en comprend sa définition) dans la table actuelle contenant des "pts"...
Bon... Connaissez-vous une reqûete SQL qui est capable de remettre à jour une série a=10, b=15, b=20
en pts_cumules de a : 10, pts_cumules de b : 25, etc. ?
c'est comment exactement , de ce genre là (je suppose) ?
Code :
|
bon.. vous m'avez compris... autant dire que la fonction qui va remettre à jour les [pts_cumules] doit être PHP...
alors, là... du coup, on va peut-être perdre du temps non ? car, faut recréer en php... recopier en sql...
puis, ensuite, utiliser le select avec l'inégalité (d'ailleurs, je ne sais même pas quelle méthode emploi MYSQL pour trouver un champs... je suppose que la DICHOTOMIE doit être au rendez-vous, car c'est la meilleure méthode, selon moi)
bon, salut et merci de vos réponses
Marsh Posté le 16-07-2004 à 16:15:40
ya personne ?
Marsh Posté le 16-07-2004 à 16:19:42
si mais pas de pigeons
Marsh Posté le 16-07-2004 à 16:21:37
je comprend rien... comment ça ?
Marsh Posté le 16-07-2004 à 16:22:04
allopassxp a écrit : je comprend rien... comment ça ? |
cherche un peu tout seul, non?
Marsh Posté le 16-07-2004 à 16:23:07
vous ne pensez pas que c'est déjà fait ?
c'est un problème sql...
bon, tant pis... je croyais que quelqu'un aurait eu la compétence...
j'aurais pu lui payer pour...
la fonction que j'ai mis plus haut fonctionne...
j'aurais simplement aimé la faire en SQL PUR... au moyen d'une seule requête... pour que le résultat soit hyper optimisé...
salutations
Marsh Posté le 16-07-2004 à 16:57:45
Perso j'ai pas la compétence, mais surtout le principe d'un forum, c'est déjà de virer la notion de tune, un PARTAGE de connaissance entre gens qui partagent une passion commune.
De plus, les gens ne te donneront jamais plus que des orientations, pas de solution toute faite, et c'est bien mieux comme ça d'ailleurs...
Marsh Posté le 16-07-2004 à 16:57:46
MySQL caca, donc pas sûr que ca marchera...
Mais moi j'ai ça :
|
Y'as eu peur hein ?
Bon, ma base ne contient pas de table comme la tienne, donc j'ai du émuler un peu.
En gros (et simplifié) ca donne ça :
|
Ca marche parfaitement sous Oracle 9i
Marsh Posté le 16-07-2004 à 16:59:02
PS: la thune tu l'envoies à la Croix Rouge, moi j'en ai assez comme ça.
Marsh Posté le 16-07-2004 à 17:01:12
Xav_ a écrit : De plus, les gens ne te donneront jamais plus que des orientations, pas de solution toute faite, et c'est bien mieux comme ça d'ailleurs... |
D'un autre côté, vu comme elle est ridicule la question, je vois pas comment ne pas poster la réponse directement.
Et si Allopassxp a de la thune à filer à un gars qui sait écrire 2 lignes de SQL, alors qu'il s'achète un vrai SGBD a la place, histoire de pas être bloqué par ce genre de problèmes débiles, au cas ou MySQL ne supporterait pas ce type de requête.
PS: on peut aussi écrire la requête en sortant le sous-select de la clause ORDER BY, parceque c'est vrai que c'est pas très chrétien comme façon de procéder.
Marsh Posté le 16-07-2004 à 19:08:34
Xav_ a écrit : Perso j'ai pas la compétence, mais surtout le principe d'un forum, c'est déjà de virer la notion de tune, un PARTAGE de connaissance entre gens qui partagent une passion commune. |
oui, ok... tu as raison
c'est bien mieux comme ça... faut mieux apprendre au pêcheur à mieux pêcher plutôt qu'à lui offrir un poisson gratuitement (proverbe chinoix que j'ai un peu déformé)
salutations
Marsh Posté le 16-07-2004 à 19:12:39
Arjuna a écrit : PS: la thune tu l'envoies à la Croix Rouge, moi j'en ai assez comme ça. |
quelle âme généreuse
Oui, et tu as raison... Bon, déjà, je n'ai vu nulle part une fonction mysql faite entièrement qui sélectionne un champs au hasard (avec une probabilité proportionnelle aux points)...
J'ai vu une fonction SQL (qui ne fonctionne pas en MYSQL, car on ne peut pas faire des select de select MALHEUREUSEMENT...)
Et sinon, cette fonction là, renvoit simplement une table de somme... mais, elle ne fait pas ma requête de base...
même, si on sait qu'il ne s'agit que d'une simple inégalité avec un limit... faudrait pouvoir tout faire DEUX EN UN jean-louis David (comme le shampooing)...
Non ,mais en gros... la fonction PHP que j'ai écrite et que je vous ai donnée gracieusement... marche... mais, est-elle trop lente ou pas ?
Sinon, cette fonction SQL... je l'ai examinée... oui, elle marche... mais, encore là... il faudrait, via PHP exécuter DEUX FONCTIONS SQL...
et en plus.. c'est du MYSQL... donc, voilà....
c'est de la merde hein
mais, MERCI de m'avoir aidé
salutations
Marsh Posté le 16-07-2004 à 22:48:22
OK, je n'avais pas lu la question jusqu'au bout, je viens de comprendre un peu mieu ce que tu veux faire...
Hmmm... Ca me semble assez simple tout de même...
J'ai plus Oracle sous la main, mais SQL Server 2000, je te ponds la requête qui va bien pour ce SGBD, après, à toi de faire au moins l'effort de passer à Open Ingres, qui supporte ce type de requêtes, et qui est gratuit.
Marsh Posté le 17-07-2004 à 00:01:40
Allez, zou !
Simple comme choux, à condition d'avoir un SGBD qui fait au moins semblant d'en être un.
|
Résultat du test de vérification en lançant 50 fois la requête avec les valeurs A=10, B=20, C=30, D=40 :
AAAA
BBBBBBBB
CCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDD
En bref, change de SGBD, MySQL ça pue vraiment.
Marsh Posté le 17-07-2004 à 00:04:42
Tu es au courant que les nouvelles versions de mysql (>=4.1) supportent les subqueries ?
Marsh Posté le 17-07-2004 à 00:08:45
Niveau efficacité...
J'ai lancé la requête sur une table contenant 2410 lignes - données "réelles" non indexées (du moins pas sur les champs utilisés), et ça a tourné en une petite seconde.
Sur la base de mon jeu BuzzLand en fait
|
Marsh Posté le 17-07-2004 à 00:10:10
karamilo a écrit : Tu es au courant que les nouvelles versions de mysql (>=4.1) supportent les subqueries ? |
Et toi, t'es au courant qu'aucun hébergeur de serveurs mutualisés ne propose ces versions, car non stables pour le moment ?
Marsh Posté le 17-07-2004 à 11:08:10
+1. la 4.1 est une version Alpha. aucun hébergeur sérieux ne passera sur cette version avant qu'elle passe en version de prod
Marsh Posté le 25-07-2004 à 23:16:54
merci pour vos précisions...
mais, selon vous... une fonction PHP telle que je l'ai faites (qui fonctionne) est-elle réellement plus lente que la fonction SQL (qui nécessite une nouvelle sgbd (je ne sais même pas ce que ça veut dire ces initiales lol)
salutations
Marsh Posté le 26-07-2004 à 01:41:11
SGBD : Système de Gestion de Bases de Données
Oui, une fonction PHP sera nécessairement plus lente que si c'est directement le SGBD qui s'en charge, et ce pour plusieurs raisons :
- Aussi rapide soit le PHP comparé à d'autre langages du même type (ASP ?) il n'en reste pas moins interprété, ce qui implique des performances minables
- Alors que le SGBD va récupérer uniquement la première ligne, et ne lire que quelques infos parmis les lignes, principalement dans les indexs, ta fonctionne nécessite de créer un curseur, transporter l'intégalité des lignes vers PHP, pour enfin récupérer la ligne qui te convient. Sans compter le traitement PHP, tu as déjà perdu énormément de temps lors du rapatriment des lignes depuis la base vers ton script.
- Quand bien même tu passerais parun CGI compilé qui ouvre une connexion en utilisant les libs natives du langage, et utilisant un curseur côté serveur (donc dans le SGBD) les fonctions de tri et cnie des bases de données sont basées sur des librairies dont les algos ont été écrits il y a des dizaines d'années, et optimisés à mort, en utilisant des langages particulièrement dédiés à ces traitements. En aucun cas tu arriveras à faire un programme aussi rapide.
Ceci dit, à moins que tu te prennes des milliers de hits par seconde, je doute que la différence de perfs soit vraiment notable
Marsh Posté le 26-07-2004 à 12:05:49
ok
des algorithmes de tri... alors là, je m'incline car c'est sûr qu'il en existe des algos de tri... genre, la méthode par pivot (je ne sais même plus comment ça marche, mais c'est ultra bien foutu)... la méthode dichotomique (moins performante... et c'est celle que j'utilise actuellement pour ma fonction... bien qu'il ne s'agisse pas de trier... je m'en sers pour repérer l'intervalle...)
donc, merci pour toutes ces infos... donc, mon sgbd n'est pas terrible...
mais bon, si j'installais un autre sgbd, il faudrait donc que je remodifie toutes mes fonctions sql actuelles... ?
car je suppose que ce n'est pas tout à fait le même language...
sinon, pour ce que tu m'as donné... ça marche... bien évidemment
et sinon, moi, j'utilise une sorte de "cache" qui n'exécute cette requête PHP qu'une fois MAXIMUM toutes les trente seconde... ensuite, j'utilise un INCLUDE... donc, tu l'as bien compris... pour limiter la casse d'une telle fonction dichotomique (en cas de fort hits), j'utilise un cache
salutations
Marsh Posté le 26-07-2004 à 12:09:18
Arjuna a écrit : Et toi, t'es au courant qu'aucun hébergeur de serveurs mutualisés ne propose ces versions, car non stables pour le moment ? |
et bien, j'ai mon PROPRE serveur...
mais, je n'ai pas la possibilité d'avoir des sous-requêtes
c'set sûrement une histoire sécuritaire pour empêcher les "bousillages de serveur" en cas de "mauvaises requêtes"
Marsh Posté le 26-07-2004 à 12:27:16
Si c'est ton propre serveur, tu peux tenter de mettre à jour MySQL vers la version 4.1, ça résoudra tous tes problèmes. Cependant c'est à tes risques et périles, car elle n'est pas encore réputée stable, donc tu n'es pas à l'abris d'un carsh (qui peut aller jusqu'à la perte des données). Il y a peut de chances que ça arrive, mais évidement plus qu'avec un produit fini et déjà testé en environnement réel.
Sinon, mise à part les bouts de code spéficie MySQL (LIMIT par exemple) le changement d'un SGBD vers un autre n'a normalement que très peu d'impact. C'est cependant une lourde tâche, car il faudra re-tester/valider toutes les requêtes une à une, et surtout vérifier que les optimisations que tu as fait pour MySQL sont efficaces sur le nouveau SGBD...
Marsh Posté le 26-07-2004 à 12:28:03
PS: par contre, si tu reste avec MySQL, mais une autre version, tu n'auras (normalement) aucun problème de portage, les requêtes existantes doivent continuer à fonctionner comme avant)
Marsh Posté le 26-07-2004 à 13:47:49
ok
merci
sinon, comme j'utilise un cache.. ça va encore;.. mais c'est sûr qu'avec un site fort exploité et qui nécessiterait de telles fonctions... il faudrait impérativement utiliser un nouveau sgbd à mon avis...
merci à toi !
Marsh Posté le 07-12-2004 à 00:47:29
au fait, je n'ai toujours pas réussi à créer avec ma vulguaire base sql se sélecteur hasardeux (afin d'aller bien plus vite), par contre je l'ai remplacé au moyen d'un CRON (truc qui s'exécute toutes les 30 secondes) avec ma vieille méthode de sélection hasardeuse "pondérée"...
si quelqu'un a PLUS RAPIDE, qu'il me communique sa solution
Marsh Posté le 16-07-2004 à 02:18:34
Bonjour...
Tout le monde connaît le critère de tri MYSQL : SELECT.... from..... order by RAND(...)
Mais moi, je cherche un nouveau type de sélection hasardeuse PUREMENT MYSQL (sans PHP) qui est "NON équiprobable" comme le RAND()...
Je vous explique le truc :
On n'a 3 enregistrements suivants : A=10, B=20, C=30
Le but étant que les chances d'afficher l'un de ces 3 enregistrements ne soient pas 1/3 (comme avec la fonction RAND livrée avec MYSQL)
mais que les chances de A soit : p(A) = A/(A+B+C) = 10/60 = 1/6
que celles de B soient : p(B)= B/(A+B+C), etc...
Vous comprennez que ce hasard n'est pas dans les règles de l'équiprobablité (comme on peut l'étudier en terminale S...)
Là, il s'agit d'un hasard "PONDERE"... obéissant à des règles de hasard relative avec la VALEUR de chaque champs...
ALors, bien sûr... avec une fonction dichotomique... un petit while, avec des $min et des $max... et une variable $i qui va à chaque fois au centre... et avec une table des sommes... : du genre : (pour ce cas là : ) la table $sum[1] = A, $sum[2] = A+B et $sum[3] = A+B+C
La solution algorithmique PHP est donc la suivante :
=> pour DEBUTER, il suffit donc de prendre au hasard un nombre entre 1 et A+B+C... (un bon vieux hasard... tel lorsqu'on joue au dé... sauf qu'au lieu de 6, c'est A+B+C dans cet exemple)
et ensuite, repérer dans quel "intervalle" on se trouve pour ainsi savoir quel est l'enregistrement sélectionné (selon les règles de probabilités citées plus haut)
Si on tombe par exemple, dans l'intervalle [0..A[... c'est le champs A qui est sélectionné...
Si on tombe dans l'intervalle [A..A+B[ (je fais un second crochet exclu à chaque fois (sauf pour le TOUT DERNIER INTERVALLE) pour qu'il existe à chaque fois une seule et UNIQUE solution trouvée), on a donc sélectionné le champs B... et de même si on tombe sur l'intervalle [A+B..A+B+C]... on sélectionnera, dans ce cas, le champs C
... vous comprennez donc, plus ou moins, l'algorithme PHP nécessaire pour les exigences demandées...
je suppose que ce concept mathématique applicable via une fonction PHP dichotomique toute "naturelle" (un peu difficile tout de même) n'échappe pas à la majorité des mateux ici-présents
Mais ma question est...
COMMENT faire une TELLE fonction en PURE REQUETE MYSQL ?
quelqu'un serait-il capable ?
c'est un sacré défis n'est-ce pas ?
je suis prêt à donner quelque chose (de l'argent... ou autre) à celui qui y parviendra... car moi, je suis totalement inculte en MYSQL...
mais en php, je me débrouille pas mal pour ce genre d'algorithmes...
Message édité par allopassxp le 16-07-2004 à 02:39:06