tags:

views:

46

answers:

3

I need to keep track of number of "hits" on a particular item in a DB. The thing is that the "hits" should stay unique with a user ID, so if a user hits the item 3 times, it should still count for a hit of 1.

Also, I need to display the total number of hits for a particular item.

Is there a better way than to store each hits for each items by each users in a separate table? Would keeping the user ID in a string separated by commas a better and efficient way?

+1  A: 

No, keeping information separated by commas in a database is almost never better and is almost always much, much, much worse than the alternative.

Do you need to keep each individual hit (is there additional information attached to it), or just the count per user? If the first is true, use a table with thing_id and user_id columns (plus columns for the other attributes that apply to the "hit"). If the second is true, use a table with thing_id, user_id, and hit_count columns and use an UPDATE command like:

UPDATE hit_count_table SET hit_count = hit_count + 1
   WHERE user_id = :userid AND thing_id = :thingid;
Larry Lustig
Well in fact I don't need to keep track of the "total number of hits", only "unique hits by users", so I guess that it would only be a table with thing_id and user_id .. Each hits will have to "insert the hit" and "fail gracefully if already exists" I guess :) Thanks
I think supermogx wants "unique visitors count" not "hits per user", which is what you are recording with that UPDATE statement.
benzado
@benzado : exactly ;)
Sorry, that's clear from your question; I just didn't read carefully enough. benzado's solution, above, is correct but remember that you'll often get errors back from the INSERT if it's a re-hit. Depending on your application structure and the degree to which you expect re-hits, you might want load the list of hit "things" when you load the user information and avoid those unnecessary UPDATEs by checking the list before updating the database.
Larry Lustig
@Larry, depending on the database engine, you should be able to specify `ON CONFLICT IGNORE` or something like it to avoid extraneous errors. Either way you should probably edit your answer, since supermogx has accepted it.
benzado
A: 

If you have a set number of items, and the number is small, you could probably get away with keeping a separate "Hit" table for each item.

If you have a lot of items (or an unbounded number of items), I'd probably just have one table to track hits across all items. If you end up with a lot of hit records, you may need to rethink the design, so that you can quickly lookup users, and decide whether you need to insert a hit record.

Overall, you have several options, and they all have performance and convenience tradeoffs. I'd just pick one that you like, and go with it. You'll find out what's good and bad, and you can chalk it up to experience!

You should never store things in a database as "CSV" strings - this is a complete nightmare to query.

Andy White
+1  A: 

Create a new table hits with columns thing_id and user_id. Add a UNIQUE index on thing_id and user_id. Then you can update the table with this query:

INSERT INTO hits (user_id, thing_id) VALUES (?, ?)

Because of the index, that will either add a row or do nothing (if you can you should specify ON CONFLICT IGNORE or equivalent when you define the table, that will avoid errors). You can get the hit count with this query:

SELECT COUNT(*) FROM hits WHERE thing_id = ?
benzado