I see on sites that they sometimes have a statistic showing how many views an article or downloads a file had over the last week. I think download.com does something like this. I was wondering how they go about doing this. Are they actually keeping track of every days downloads or am I missing something really basic?
Are they doing something like having three rows called total_downloads, last_week_downloads, this_week_downloads. Then every week, copying the value of this_week_downloads to last_week_downloads and then resetting this_week_downloads to 0?
There are a couple of ways to do it, depending on what your trying to get out of the stats.
One way is to include a visits column on your table, then just increase that number by 1 each time that article's page is loaded.
This however isn't very good for giving the past weeks number of views. You can do this in 2 ways:
1) another column in your table doing the same as visits, but run a cron job to put it back to 0 every week.
2) create another table which holds article_id, ip_address and timestamp, you would insert a record each time someone visits the article, storing their IP address (allowing you to roughly get page views and unique page views), and of course the timestamp allows you to query for only a sub-set of those records. Note: using this method you could store more information for stats, but it does require a lot more server resources.
The most basic way you can do this is associate a MySQL field alongside your article on the database and just increment it.
Assuming you we're retreiving article 123 from your database you would have something like this on your code:
<?php
// this would increment the number of views
$sql = "UPDATE table SET count_field=count_field+1 WHERE id=123";
...
?>
Related
I have a question about making "Highscore-Lists".
Lets say I have an online game with 1.000.000 active users. Each user has points from 0 to X. Now, I want to show a ranking-list. It would be insane to show all million entries in one page so it is divided into Y pages (100 entries each page => 10.000 pages).
I am not really sure how to solve it.
1. The easiest way to do that would be loading all 1m entries
in one SELECT, get the result and find current user with a for loop and show that specific page. (but all other 999.900 entries will be saved in RAM eventhough its not showing up). For a page change I could just use the result data with no second database call. (So I don't care about point changes during that time)
SELECT UserName, UserID, Points FROM UserAccount ORDER BY Points;
2. My second idea was, to load each page individually but than I do not know
2.1 if it is really better performance
2.2 how to get the right start page because I only have the points of the user but not really his place
So how could I solve that problem. I dont really know what mysql can handle. Are more small calls better then one huge call.
Can I even save huge result data?
Second solution would update all changed points with each page change, though but i care more about performance then always uptodate list-data.
Thank you for your help!
Markus
Use pagination. In SQL it's a "limit" clause:
SELECT UserName, UserID, Points FROM UserAccount ORDER BY Points LIMIT 0, 20;
The above query will return only the first 20 rows of the original selection.
You can pass page parameters via get, like this: highscore.php?page=1 or ?page=2 and so on.
Hello again Stackoverflow!
I'm currently working on custom forumsoftware and one of the things you like to see on a forum is a viewcounter.
All the approaches for a viewcounter that I found would just select the topic from the database, retrieve the number from a "views" column, add one and update it.
But here's my thought: If, lets say 400, people at the exact same time open a topic, the MySQL database probably won´t count all views because it takes time for the queries to complete, and so the last person (of the 400) might overwrites the first persons (of the 400) view.
Ofcourse one could argue that on a normal site this is never going to happen, but if you have ~7 people opening that topic at the exact same second and the server is struggleing at that moment, you could have the same problem.
Is there any other good approach to count views?
EDIT
Woah, could the one who voted down specify why?
I ment by "Retrieving the number of views and adding one" that I would use SELECT to retrieve the number, add one using PHP (note the tags) and updating it using UPDATE. I had no idea of the other methods specified below, that's why I asked.
If, lets say 400, people at the exact same time open a topic, the MySQL database apparently would count all the views because this is exactly what databases were invented for.
All the approaches for a viewcounter that you have found are wrong. To update a field you don't need to retrieve it, but just already update:
UPDATE forum SET views + 1 WHERE id = ?
So something like that will work:
UPDATE tbl SET cnt = cnt+1 WHERE ...
UPDATE is guaranteed to be atomic. That means no one will be able to alter cnt between the time it is read and the time it is replaced. If you have several concurrent UPDATE for the same row (InnoDB) or table (MyISAM) they have to wait their turn to update the date.
See Is incrementing a field in MySQL atomic?
and http://dev.mysql.com/doc/refman/5.1/en/ansi-diff-transactions.html
My client has a table that tracks total views for each of his articles. The problem is they want me to break the view count into days. I can easily enough query the db and grab the view counts, but I'm unsure of how to grab each days view count (for each article of course).
In case I'm not being clear (which is usually the case I've been told) I have a field in a table that collects all views on each article with no regard to date or time. If the article was viewed, the row is plus one'd. Look at the record a year from now and the view count shows 2,000. That's it.
What I want to do is capture each days view count for each article and plunk that into its own table but I CANNOT impact said view count field/record. This way, the client can view each days view count on each article. Any idea on the best approach?
I hope that all made sense!!
If I were you I would make a new table for views and insert a new record on each view and when was it viewed, then I would select all the views that are dated today and count them and that would give me the number of times the article was viewed today and it would still keep the total count
Something like:
INSERT INTO `daily_views` SET `views` =
SELECT COUNT(*) FROM `views_table`
WHERE `date` BETWEEN '2013-06-10'
AND '2013-06-11'
AND `post_id` = 1
, `post_id` = 1;
Start at New Year Eve. Each day take the count and store it in a separate table. On the next day subtract current count with the stored one - this is yesterday's count - store the difference on another table together with the date. So, clear or not?
I have a table article with many articles. I want to track the number of viewers for each article. Here's my idea, of how I plan to do it.
I've a table viewers with rows: id, ip, date, article_id.
article_id is a FOREIGN FIELD referring to the id of the article. So, when a user open up an article, his/her IP address is stored in the table.
Is this a decent approach? It is for a personal site and not a very big website.
EDIT: I want to print the number of view on each article page.
It depends on how frequently you need to display number of viewer. Your general query will be:
select count(*) from viewers
where article_id='10'
With time, your viewers table will grow. Say it have million records after 1 year or two. Now if you are showing number of viewers on each article page or displaying articles with most viewers, it will start impacting on performance even though foreign key is indexed. However that will happen after you added hundreds of articles with each having thousands of viewers.
A better optimized solution may be to keep number of viewers in article table and use that to display results. Existing Viewers table is also necessary to ensure there is no duplicate entry (Same user reading an article ten times must be marked as single entry not ten).
Use a Tool like Google Analytics. This will do the job much more elaborated and you're up and running in minutes, there's more about unique visitors than IP addresses!
If you want to have an on premise solution, look at PIWIK, which is PHP framework for exactly this puprose.
In this design,There is a one problem if the same user open it again and again then either you have to put check before insert the entry or you insert the same ip address multiple time but different time stamp.
Most of the popular sites consider one ip address as one view even if that client or user open that article several times.
I can think of solution.
your approach with single check. if the same client has opened it again don't insert it.
or group by Id when you retrieve the counter.
It depends on what you want to store in your database. If you want to know exactly how many unique users visited this particular article (including date and ip) this is reasonable way do to this. But if you need only a number to show you can alter article table and include new column with visit_counter and store cookie to prevent incrementing counter on same user.
try something like this
// insert
$query = mysqli_query("REPLACE INTO viewers (ip) VALUES ('" . ip2long($_SERVER['REMOTE_ADDR']) . "')");
// retrieve
list($pageviews) = mysqli_fetch_row(mysqli_query("SELECT COUNT(ip) FROM viewers"));
echo $pageviews;
Read : REPLACE INTO
Yes, this is good aproach if you create some kind of cache for displaying how many views each article had. It's not optimal to count views each time user open website.
You can do it in SQL Server. There is something like materialized view. ( https://code.google.com/p/flexviews/ )
select article_id, count(*) as views from viewers group by article_id
Or you can cache it in files and refresh every X time.
To store users who viewed article I suggest using AJAX. When user open website, another 'thread' will call website to add his as viewer. Even if your db is slow, it will not slow down website loading, also web spiders will not be counted.
Platform: PHP5, MySQL
I have a web site that displays articles that are sorted into categories. I would like to track the number of views for each article. Then, in the side bar, display the top 5 articles viewed articles for the current day, within the past meek, and within the last month. What do you think would be the best way to do that? One row in database for each view (article_id, timestamp)? What would be the least amount of work for the server?
Thanks, joe
This can become a tricky problem. If you just store raw hits, your table will grow rapidly and crunching the numbers becomes more time consuming. So, one way to deal with this is to create aggregate tables and crunch the numbers using a cron job.
For example, you could have the following tables
hit_count: article_id, timestamp
hit_count_daily: day, year, article_id, hit_count
hit_count_weekly: week, year, article_id, hit_count
hit_count_monthly: month, year, article_id, hit_count
hit_count_yearly: year, article_id, hit_count
You then process the data in the hit_count table, add it to the aggregate tables, and then remove the data from the hit_count table.
You also need to think about what happens if someone refreshes the page or if Google crawls the article. Do you want to count those as hits?
To keep crawlers from triggering hits, you could use some Javascript on the page to communicate back to your server and register the hit. This way, a normal browser will trigger the hit but a crawler will not.
You could also offload this task to another service, like Chartbeat or Clicky
How about:
Add this to php.ini
auto_append_file = /server_root/footer.php
footer.php contains a silent routine to write the SQL data.