2011-05-20 3 views
0

Je réalise un projet où je suis un suivi des utilisateurs sur un site Web, je connecte chaque hit sur le site. Chaque fois qu'ils frappent une URL, je vais le créer dans la base de données, et le marquer avec quelques balises.Tri et calcul par date dans la requête jointe

Chaque URL est appelée «ressource» dans ma base de données et une ressource peut être associée à plusieurs tags. Un visiteur est connecté aux ressources lorsqu'il visite une URL, et lorsqu'un utilisateur rencontre une ressource, je lui connecte également la date.

La chose que je veux faire est de trouver les ressources avec les balises correctes, qui ont été observées ce mois-ci ou aujourd'hui pour un exemple.

La requête Je suis en train de construire est ici:

SELECT r.resource_id, r.resource_url 
FROM resource r 
JOIN visitor_resource vt ON vt.resource_id = r.resource_id 
JOIN resource_tags rt ON rt.resource_id = vt.resource_id 
JOIN tags t ON t.tag_id = rt.tag_id AND t.tag_name = '42' 
GROUP BY r.resource_id 

Pour vous donner une idée de la structure que vous pouvez voir ici: tracking database structure http://kaspergrubbe.dk/db-overview.png

Donc, fondamentalement, je vais devoir compter combien de visitor_resources il est dans un mois donné en regardant visitor_resources.last_visited pour le mois dernier, et obtenez les 5 ressources les plus visitées.

Comment aborder cela? La requête ci-dessus semble également très lente sans la mise en cache des requêtes, je suppose que c'est parce que t.tag_name n'est pas un index, et c'est un varchar, mais est-ce qu'il y a une accélération du processus autre que l'ajout de cet index?

Merci.

+0

Si vous ne stockez que la date last_visited, cela ne vous indiquera pas réellement combien de fois une ressource a été visitée. Un visiteur pourrait aller à une ressource plus d'une fois dans le même mois, je suppose. Peut-être que c'est correct et que vous vous souciez seulement des visiteurs uniques, mais je pensais que je devrais le signaler. –

+0

Merci d'avoir souligné cela, mais c'est par conception :) –

Répondre

1

Vous avez omis tous les critères en fonction de la date, vous devriez donc l'ajouter et voir comment les performances changent. Aussi, si vous cherchez un compte, vous devriez ajouter cela aussi. Je pense que mySQL supporte la clause LIMIT (par opposition à TOP), ajoutez donc cela pour le limiter aux 5 ressources les plus visitées. Avec tout ensemble, il sera probablement ressembler à quelque chose comme ceci:

SELECT 
    r.resource_id, 
    r.resource_url, 
    COUNT(*) 
FROM 
    Visitor_Resources VR 
INNER JOIN Resources R ON R.resource_id = VR.resource_id 
INNER JOIN Resource_Tags RT ON RT.resource_id = R.resource_id 
INNER JOIN Tags T ON 
    T.tag_id = RT.tag_id AND 
    T.tag_name = '42' 
WHERE 
    VR.last_visited BETWEEN <start of month> AND <end of month> 
GROUP BY 
    r.resource_id, 
    r.resource_url 
ORDER BY 
    COUNT(*) DESC 
LIMIT 5 

Désolé, je ne fais pas beaucoup de mySQL ces jours-ci, donc je ne sais pas ce que les paramètres de la date de début et de fin ressembleraient dans le dernière ligne.

À moins que votre table Tags ne soit très grande, un index n'aura probablement pas beaucoup d'importance. Un index sur le Visitor_Resources.last_visited pourrait être une bonne idée cependant.

En outre, j'ai changé les noms de vos tables dans la requête pour être plus cohérent. Personnellement j'aime les noms pluriels, mais les singuliers sont ok aussi. Peu importe ce que vous choisissez, choisissez-en un et respectez-le.

+0

Ajout d'un index à visitor_resource.last_visited a pris une demi-heure, mais la requête a couru en 5 secondes par rapport à l'initiale de 50 secondes. Merci! –

+0

.. et 5 secondes est suffisant en raison de la mise en cache :-) –

-1

Kasper,

Tout d'abord vous devez ajuster votre JOIN. Il n'est pas nécessaire de dire JOIN ON sur chaque ligne:

ie. 
     LEFT JOIN(
     groups, sign 
     )ON(
     user.user_id = groups.userID AND 
     groups.group_id = sign.groupID 

Essayez quelque chose comme ça pour les jointures.

Ajoutez ensuite un ORDER BY à la clause.

ORDER BY last_visited DESC LIMIT 5; 

Ce triera votre table de date, et de prendre les plus récentes 5 entrées dont jamais la colonne que vous spécifiez.

Espérons que cela aide.