views:

274

answers:

2

Hello!

I've built a news site: - The articles are shown on the front page ordered by date. The newest one first. - The news are in the table "news" with the fields "id", "title", "text" and some other ones. - All articles are tagged with 1-5 relevant tags. - The tags are in the table "tags" with the fields "id", "tag", "article" and some other ones. - The field "article" of "tags" fits to the field "id" of "news".

Now I want to give the user the opportunity to add tags to his "favored tags list". Then the user should only see news articles which contain one of the favored tags.

Assuming the user Bob has favored the tags "barack obama", "nba", "new jersey" and "dogs". He should only see articles containing at least one of these four tags.

How could I code a PHP/MySQL script which achieves this? I think my database structure is not adequate for this purpose, is it? I would have to make DB queries like this:

"SELECT * FROM news WHERE id IN (SELECT article FROM tags WHERE tag IN ('barack obama', 'nba', 'new jersey', 'dogs'))"

This query would run for a long time, wouldn't it? There must be a database structure which is more appropriate than mine. Do you have an idea for this problem? Which DB structure do I need and what queries must I use then?

I hope you can help me. Thanks in advance!

+5  A: 

The following is by no means exhaustive/definitive, but it should get you going in the right direction.

Tables:

news
=====
id
title
text

tag
===
id
tag

tag_map
=======
tag_id
news_id

favorite_tags
=============
user_id
tag_id

Query

SELECT * 
FROM favorite_tags
JOIN tag_map ON favorite_tags.tag_id = tag_map.tag_id
JOIN news ON tag_map.news_id = news.id
WHERE favorite_tags.user_id = $userid
Frank Farmer
Thank you very much for this quick and good answer. I've got a last question: Which fields should I set an index on? I've chosen "id" as a primary in "news", "id" as a primary and "tag" as a unique in "tag", "tag_id,news_id" as a primary and "news_id" in "tag_map" and ,finally, "user_id,tag_id" as a primary and "tag_id" in "favorite_tags". Is this correct?
From a cursory look it seems about right, but, double check by populating the tables and doing 'EXPLAIN SELECT' etc.
Alex Martelli
I think you'd want indexes on tag_map.tag_id, news.id, and favorite_tags.user_id, for this query.
Frank Farmer
+1  A: 

The query's performance (whether in your sub-select approach, or Frank Farmer's more elegant join-based one) will chiefly depend on indices. Just remember that MySQL uses just one index per table, and the proper set of indices (depending on the query you want to optimize) invariably becomes pretty obvious...

Alex Martelli
Thanks, I've added a question concerning the indices to Frank Farmer's answer.