tags:

views:

745

answers:

8

What is the best way to implement the page view counter like the ones they have here on the site where each question has a "Views" counter?

Factoring in Performance and Scalability issues.

+3  A: 

An efficient way may be : Store your counters in the Application object, you may persist it to file/DB periodically and on application close.

François
+1  A: 

The counter i optimized works like this:

UPDATE page_views SET counter = counter + 1 WHERE page_id = x
if (affected_rows == 0 ) {
   INSERT INTO page_views (page_id, counter) VALUES (x, 1)
}

This way you run 2 query for the first view, the other views require only 1 query.

Bob Fanger
One of the challenges here is either a) the potential for serialization or b) a race condition - depends on your transaction isolation level.
stephbu
Right, one of the worries we have is possibly a race condition. Should this be done asynchronously ?
TimLeung
@stephbu : for your b) it's more a non-critical race conditions because increasing of +1 doesn't change if a query is done in same time... +1 +1 or +1 +1 equal always +2.
Daok
you could of course insert a row for every new page and set the counter to 0
Bob Fanger
@daok like I pointed out it depends on where your transaction boundaries are and how tolerant of race conditions you can be.
stephbu
@stephbu this wont be a problem for the question the user asked.
Daok
@daok I'm not sure I agree there - he asked to factor in scalability - serializing all the calls by experience is not very scalable. You'd need to pair it with other solutions e.g. async updates to enable to workaround the serialization.
stephbu
I think I do not follow you with your serializing... What are you talking about?
Daok
A: 

You can implement an IHttpHandler to do that.

Zote
A: 

I'm a fan of @Guillaume's style of implementation. I use a transparent GIF handler and in-memory queues to batch-up sets of changes that are then periodically flushed using a seperate thread created in global.asax.

The handler implements IHttpHandler, processes the request parameters e.g. page id, language etc., updates the queue, then response.writes the transparent GIF.

By moving persistent changes to a seperate thread than the user-request you also deal much better with potential serialization issues from running multiple servers etc.

Of course you could just pay someone else to do the work too e.g. with transparent gifs.

stephbu
A: 

For me the best way is to have a field in the question table and update it when the question is accessed

UPDATE Questions SET views = views + 1 WHERE QuestionID = x

Application Object: IMO is not scalable because the may end with lots of memory consumption as more questions are accessed.
Page_views table: no need to, you have to do a costly join after

Eduardo Molteni
@Eduardo being practical even with 10m pages - you're still only talking about at most 10m ints - I think I burn through 50Mb just cracking open the CLR ;) Memory is cheap - serialization isn't.
stephbu
+7  A: 

I've made two observations on the stackoverflow views counter:

  • There's a link element in the header that handles triggering the count update. For this question, the markup looks like this:
    <link href="/questions/246919/increment-view-count" type="text/css" rel="stylesheet" />
    I imagine you could hit that url to update the viewcount without ever actually viewing the page, but I haven't tried it.

  • I had a uservoice ticket, where the response from Jeff indicated that views are not incremented from the same ip twice in a row.

Joel Coehoorn
Thanks for the observation :)
TimLeung
fyi for those reading this later - I'm pretty sure they've changed this since the original post.
Joel Coehoorn
A: 

Instead of making a database call everytime the database is hit, I would increment a counter using a cache object and depending on how many visits you get to your site every day you have send the page hits to the database every 100th hit to the site. This is waay faster then updating the database on every single hit.

Or another solution is analyzing the IIS log file and updating hits every 30min through a windows service. This is what I have implemented and it work wonders.

Luke101
A: 

IMO, I think nebys answer has too much overhead

Luke101