- Statut : non résolu
- Ce sujet contient 14 réponses, 3 participants et a été mis à jour pour la dernière fois par luciole135, le il y a 12 années et 11 mois.
-
AuteurMessages
-
18 février 2012 à 10 h 25 min #505818
Bonjour,
Ma configuration WP actuelle
– Version de WordPress :
– Version de PHP/MySQL :
– Thème utilisé :
– Extensions en place :
– Nom de l’hebergeur :
– Adresse du site :Problème(s) rencontré(s) :
Bonjour,
Pour un plugin (Statpress-visitors) que j’entretiens, j’ai besoin de faire un tri sur deux critères : c’est à dire afficher les 20 dernières visites des 20 dernières IP. Ce qui correspond à la fonction SPY (log des visites).Autant, il est facile de coder cela en PHP, autant créer une requête SQL qui renvoit uniquement ces résultats là est difficile. En effet, la clause SQL LIMIT agit sur la totalité des résultats de la requête et il n’est pas possible de faire agir en MySql le LIMIT d’abord sur les IP et ensuite un autre LIMIT sur les dernières visites.
Faire ce double tri en MySql est vraiment très difficile à réaliser.
J’ai trouvé une requête utilisant une auto jointure qui renvoit TOUTES les visites des 20 dernières IP, mais certaine IP ont beaucoup de visites et ainsi pour afficher les 20 dernières visites des 20 dernières IP, cette requête renvoit 1000 lignes pour une table de données de 150 000 lignes en 1,6 sec. Ce qui n’est pas catastrophique avec une table de données non optimisée comme elle l’est actuellement.
Là où cela devient catastrophique, c’est lorque l’on traite en PHP ces 1000 lignes renvoyées par la requête, cela prend en local 30 secondes !:fouet:PHP n’étant pas un langage compilé, le traitement d’un grand nombre de données est très lourd et très lent. Alors que MySQL est adapté au traitement d’un grand nombre de données mais ne permet pas de faire un double tri !😉
Alors, j’ai cherché une autre requête, en vain et finalement je m’oriente vers la création d’une table temporaire, cette table contenant les résultats de la requête précédente. Interroger cette table devient alors très rapide tant en MySQL qu’en PHP…
Mais apparemment, il est impossible de créer des tables de données temporaire avec WordPress, quelqu’un a-t-il une idée de comment créer malgré tout une table de données temporaire sous WordPress, même si on n’utilise pas les fonctions standard de WordPress.
La requête de création de la table temporaire en SQL est alors (id est l’index primaire de la table $table_name) :
CREATE TEMPORARY TABLE « .$table_spy. » AS (SELECT *
FROM $table_name as T1
JOIN
(SELECT max(id) as MaxId,ip
FROM $table_name
WHERE spider= »
GROUP BY ip
ORDER BY MaxId DESC LIMIT $LimitValue, $LIMIT
) as T2
ON T1.ip = T2.ip
ORDER BY MaxId DESC, id DESC;
)Si quelqu’un a une idée, merci !
18 février 2012 à 12 h 21 min #817405Pour l’instant, je ne vois pas d’autres issues que d’utiliser les fonctions PHP prévues pour interagir avec une base de données :
http://www.php.net/manual/fr/book.mysql.phpMais la fonction de connection à une base de données nécessite des paramètres comme le nom d’hôte etc, où les trouve-t-on ? Ou alors s’agit-il de variable globale définies dans wp-config.php ?
http://www.php.net/manual/fr/function.mysql-connect.php18 février 2012 à 13 h 28 min #817416Bon,
pour l’instant, j’ai créé des fonctions de connection et de déconnection à la base de données qui fonctionnent :function connect_bd()
{
$nomserveur=DB_HOST; //nom du seveur
$nombd=DB_NAME; //nom de la base de données
$login=DB_USER; //login de l’utilisateur
$pass=DB_PASSWORD; // mot de pass
$bd=mysql_connect($nomserveur, $login, $pass)or die(« Connexion échouée »);
mysql_select_db($nombd,$bd)or die(« La base ne peut pas être selectionnée »);
return $bd;
}
function deconnect_bd($bd)
{
mysql_close($bd);
$db=0;
}Ainsi que la requête qui crée cette table temporaire, j’ai du renommer le deuxième champs ip en ip1 car sinon, cela ne fonctionne pas :
$result = mysql_query(« CREATE TEMPORARY TABLE « .$table_spy. » AS (SELECT *
FROM $table_name as T1
JOIN
(SELECT max(id) as MaxId,ip as ip1
FROM $table_name
WHERE spider= »
GROUP BY ip
ORDER BY MaxId DESC LIMIT $LimitValue, $LIMIT
) as T2
ON T1.ip = T2.ip1
ORDER BY MaxId DESC, id DESC) »);J’ai pu interroger cette table temporaire, cela fonctionne…
Reste plus qu’à modifier tout le code du plugin pour utiliser cette table temporaire !18 février 2012 à 14 h 40 min #817417Il est très facile d’insérer une requête mysql à l’intérieur d’une requete
requete A = selectionner les 20 dernières ip
requete B = selectionner les 20 dernières visites where ip in requete A (suffit de mettre le texte de requete A à la place)18 février 2012 à 15 h 26 min #817406Je dois alors mal comprendre, car lorsque je fais un LIMIT 20 ip cela n’affiche que les 20 dernières visites totales.
Et quand je fais un IN requêtes A comme vous dites, cela m’indique l’erreur suivante : « votre version de MySql ne permet pas d’avoir un LIMIT dans un IN !
18 février 2012 à 15 h 32 min #817407Ah … ça c’est dommage
18 février 2012 à 15 h 45 min #817408Oui, c’est dommage, voilà l’erreur exacte « #1235 – This version of MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME subquery’
Le pire, c’est que d’après mes premiers tests, la table temporaire n’améliore pas les performances de la page, le temps passé en PHP sur 1000 lignes est remplacé par le temps de faire les 20 requêtes sur la table temporaire pour les 20 dernières ip…
Bref, c’est la galère !
18 février 2012 à 17 h 40 min #817409bon… c’est vrai que l’on ne peut pas et j’avais contourné avec un inner join et des cabrioles, mais ton idée de table secondaire me fait penser que l’on peut peut être créer une requête avec un alias et un as:
faut voir si ça marche.
requete A = selectionner les 20 dernières ip
requete B = selectionner les 20 dernières visites where ip in ( select * from (requete A) as temp)18 février 2012 à 18 h 00 min #817410Je fais les essais, merci de l’idée !
18 février 2012 à 18 h 57 min #817411Si j’écris la requête ainsi :
SELECT *
FROM wp_statpress
WHERE ip IN
((SELECT ip
FROM wp_statpress
WHERE spider= »
GROUP BY ip LIMIT 0,20
) as T)
ORDER BY ip, id DESCCela m’indique l’erreur suivante :
#1064 – You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘as T) ORDER BY ip, id DESCQuelle était votre autre façon de faire avec un INNER JOIN et des cabrioles ? On sait jamais…
18 février 2012 à 22 h 42 min #817412oula, je ne sais plus ou c’est
mais sinon, ce n’était pas exactement ce que j’avais mis pour la requête (et cette syntaxe est correcte si les champs existent)
SELECT *
FROM wp_statpress
WHERE ip
IN (
SELECT *
FROM (
SELECT ip
FROM wp_statpress
WHERE spider= »
GROUP BY ip
LIMIT 0 , 20
) AS T
)
ORDER BY ip, id DESC
LIMIT 0 , 3018 février 2012 à 23 h 24 min #817413Ah oui effectivement, en faisant comme vous le dites il n’y a pas d’erreurs MySQL, seulement, le tri n’est plus fait dans le bon ordre, certaines IP vues en août 2011 apparaissent comme postérieures à celles de 2012.
De plus les 4 premières IP qui apparaissent n’existent même pas dans la base de données, c’est vraiment étrange.
J’ai dû faire une erreur dans ma requête que voici :$sql = « SELECT *
FROM $table_name
WHERE ip
IN (SELECT *
FROM (SELECT ip
FROM $table_name
WHERE spider= »
GROUP BY ip
LIMIT $LimitValue, $LIMIT
) AS T1
)
ORDER BY ip, id DESC »;
$qry = $wpdb->get_results($sql);18 février 2012 à 23 h 32 min #817414Ah oui, j’ai pigé, c’est le ORDER BY IP qui fait que les IP sont rangées dans l’ordre croissant des IP de la plus petite IP à la plus grande !
18 février 2012 à 23 h 44 min #817415Mais même en supprimant le ORDER BY ip, je perd le rangement des visites de la plus récente à la plus vieille, je n’arrive plus à les classer dans le bon ordre.
C’est le MaxId qui me sert à les ranger dans le bon ordre dans ma première requête. Elle sont rangées selon le MaxId qui est le même pour toutes les IP identiques.
Mais je ne peux pas utiliser le IN avec deux valeurs IP et MaxId.Je crois que je suis à nouveau bloqué !
😉19 février 2012 à 11 h 48 min #817418J’ai tenté une nouvelle requête pensant numéroter chaque ligne retournée par la requête.
J’aurais voulu que pour chaque IP le numérotage parte de zéro, mais cela ne fonctionne pas, les lignes sont numérotées de 1 à 1000 s’il y en a mille indépendamment des IP.
Voilà la requête :$sql = « SELECT *, @num:=@num+1 as numero
FROM $table_name as T1
JOIN
(SELECT max(id) as MaxId, ip, @num:=0 as numero
FROM $table_name
WHERE spider= »
GROUP BY ip
ORDER BY MaxId DESC LIMIT $LimitValue, $LIMIT
) as T2
ON T1.ip = T2.ip
HAVING numero < 20
ORDER BY MaxId DESC, id DESC
";Et ainsi, il n’y a que 20 lignes au total qui sont affichées.
Je me demande s’il est possible seulement de faire un double tri en MySql sans faire un premier tri sur le premier critère et autant de tris pour le deuxième critère que de résultats dans le premier tri. -
AuteurMessages
- Vous devez être connecté pour répondre à ce sujet.