PHP/MYSQL Database Logic Query - php

Trying not to reinvent the wheel here so thought 'i'd ask you guys;
There is an existing database for a computer game that records - map name, time it took to finish the map, the difficulty level, id of person. This database is used to record best finish times for each player. So the player can type a certain command and it shows the best finish times for a particular map.
Now i would like to create a ranking system that rewards the player points for finishing the maps based on the difficulty level, e.g completing it on easy rewards the player 1 point, 2 points for medium ,etc. This ranking system will show the top players with most points.
My question is, would it be better to use the current database and use PHP to accomplish the new ranking system
or
create a new database to accomplish it?
In either case, a simple logic example would be appreciated.

I think it is best to just use your already existing database. What do you mean logic example?

Could you try this:
SELECT *, (count(*) * difficulty) AS total
FROM `map`
GROUP BY user_id
ORDER BY total DESC
LIMIT 10
difficulty is a table field, which is 1 for easy, 2 for medium, etc.

As Kyle said use your current database/table and let php/ SQL do the work. I would do something
select player,
Map,
Count(*)
From mytable
Group by player, map
That should give you a count of player completes by map. Test this though. After you get the count you can loop through your counts and based on map multiply by the points awarded.

Related

Generating statistics using PHP and SQL

I run a SQL database with some user information.
On the main page, I would like to throw some statistics about the database, and what I thought was easy at first, showed to be complicated for me (I'm a newbie).
To give a pratical example of what I'm trying to achieve, I will use a real situation to exemplify:
On my CLIENTS table, all of my clients are from different countries (represented by a country code). One of the statistics I'm trying to show, is WHAT COUNTRY HAS MORE CLIENTS.
Is there a simple way to find this kind of information? I understand I can simply count how many occurences of certain country I have on the TABLE, but I would need to compare with every country to check which on hosts more clients.
I guess that sums up my question.
EDIT: I came up with a solution but I'm just not sure if it's best, using PHP. I did a loop test for each country checking the number of clients, and compared to the one before. If the count was higher, I updated the $higher_country var, if not, I just moved to next country. Would that be my only option?
You can do something like...
SELECT country_id, count(country_id) as nmbr
FROM clients
group by country_id
order by nmbr desc
limit 1
This counts up the number of a specific value and orders it in reverse order (so highest first) and just picks the first record.

After reaching a large MySQL DB (say 1 mil rows) does providing LIMIT help optimizations?

I'm using PHP 7, MySQL and a small custom-built forum and a query for grabbing 7 columns with 2 SQL join statements into a "latest post" page. When the time comes that I hit 1 million rows will the limit 30 stop at 30 rows or will it have to sort the entire DB each run?
The reason I'm asking is I'm trying to wrap my head around how to paginate this custom forum I've built and if that pagination will be "ok" once it has to (theoretically) read through a million rows?
EDIT: My current query is a limit 30, sort desc.
EDIT2: Currently I'm getting about 500-600 posts give or take 50 a day. It's quickly adding up so I'm trying to monitor this before I get 1 million. That being said I'm only looking up one table right now, tblTopics and topic_id, topic_name, and topic_author (a fk). Then I'm doing another another lookup after that with the topic itself's foreign keys, topic_rating, and topic_category. The original lookup is where I have the sort and limit.
Sort is applied on the complete set, limit is applied after the sort, so adding a limit to an ORDER BY query does not make it a lot faster.
It depends.
SELECT ... FROM tbl ORDER BY x LIMIT 30;
INDEX(x)
will probably use the index and stop after 30 rows, not 1 million.
SELECT ... FROM tbl GROUP BY zz ORDER BY x LIMIT 30;
will scan all million rows, do the grouping, write to a tmp table, sort that tmp table, and only then deliver 30 rows.
SELECT ... FROM tbl WHERE yy = 123 ORDER BY x LIMIT 30;
INDEX(yy)
will probably prefer INDEX(yy), and it is hard to say how efficient it will be.
SELECT ... FROM tbl WHERE yy = 123 ORDER BY x LIMIT 30;
INDEX(yy, x)
will be very efficient -- not only can it use the index for filtering, but also for the ORDER BY and the LIMIT. Only 30 rows will be touched.
SELECT ... FROM tbl LIMIT 30;
is of dubious use. You will get some 30 rows, but who knows which 30? But it will be fast.
Well, this is still not answering you question. Your question involves a JOIN. Can you guess how much more complex the question becomes with JOIN involved?
If you would like to discuss your specific query, please provide the query and SHOW CREATE TABLE for each table and how many rows in each table.
If you are joining a 1-row table to a million row table, the 1-row table probably does not add any complexity.
If you are joining two million-row tables together without any indexes, then you are looking at a trillion intermediate 'rows' to work with!
Oh, and then you will want the 'second' 30 rows? That adds another dimension of complexity. I could spend a few more paragraphs on what can go wrong with OFFSET.
If this forum is somewhat open-ended where anyone can post "topics" and be the originating author, you probably want at a minimum a topics table with a PKID, Name, Author as you have, but also date added and most recent post and also count of posts against it. Too many times people build web sites that want counters all over the place and try to do aggregates, or the most recent, etc. Come to mention the most recent post, hold the ID of the most recent post too so you don't have to find the max date, then get the join base on that.
Then secondary table would be the details associated for a given post.
Then, via a trigger on your detail table for whatever you are posting against, you can do an update to the parent topic id and stamp it with count +1, most recent date of now, and the last ID with the ID of the newest record just created.
So now, joining to get that most recent context entry is a simple join and not overly complex.
Index on your topics table on the most recent post date so you are now getting ex: the most recent 30 topics, not necessarily the most recent 30 posts, such as 3 posts have a bunch of hits and account for all 30. Get 30 distinct topics, then let user see the details as they select the topic of interest. Your query at the top level is never going against the underlying details.
Obviously brief on true context of your website, but hopefully suggestions make sense for you to run with.

Ranking in Symfony/Doctrine

I have 3 entities in Symfony. Candidate, School, Game a candidate is assigned to one school and can start games. The games entity contains the score (of that) game. So far so good, here comes the tricky part:
I have to display to the candidates, what rank they have currently, as well as the top 10 players.
I know, I could use a native query for mysql and do something like proposed here: https://stackoverflow.com/a/3333697/2989952
But then, to get the rank of the candidate I'd have to load all entries from the db and loop throu them in PHP (or with Doctrines Criteria). Is there a better way to get the rank? I could also add a column point's or something in the candidate entity and update that after every game and then just sort by that column, still I'd have to loop throu all entries again in PHP.
Thanks for your help.
For the second part 'How to rank top 10 players' i would use index from loop with this query.
$gameRepository->findBy([],['score'=>'desc'],10);
For the first part.This looks promising and can be transfered into DQL easily.

Get users current position the best way

I am making a ranking app and are getting the users position in the ranking this way:
$sql = "SELECT fk_player_id FROM ".$prefix."_publicpoints
WHERE date BETWEEN '2013-01-01' AND '2013-12-31'
GROUP BY fk_player_id
HAVING SUM(points) > 235";
This is working as is should but are having one downfall. The query can get quite heavy if I have a ranking with 500.000 users. Then it have to run through all the users which have higher points than 235. Lets say that 235 give a posistion as # 345.879. Thats alot of rows... How can I do this in a better way? Atleast when I call the db?
Hoping 4 help and thanks in advance :-)
3 possible solutions that may (or may or may not combine them together depending on the situation
Add indices to the ranking columns
pre-compute the ranks only when it changes
pre-compute the ranks with a cron job - it should not matter if it is 10 minutes late.
If it is a generic ranking page, you can pre-render the page either with a template engine and cache it
you may be able to optimize your mysql performance as well either with more ram or configuring the caching of queries & temp tables

MySQL - creating an SQL Algorithm to determine random 'popular' content

I'm looking to create an SQL query (in MySQL) that will display 6 random, yet popular entries in my web application.
My database has the following tables:
favorites
submissions
submissions_tags
tags
users
submissions_tags and tags are cross-referencing tables that give each submission a certain number of tags.
submissions contains boolean featured, int downloads, and int views, all three of which I'd like to use to weight this query with.
The favorites table is again a cross-reference table with the fields submission_id and user_id. Counting the number of times each submission has been favorited would be good to weigh the results with.
So basically I want to select 6 random rows weighted with these four variables - featured, downloads, views, and favorite count. Each time the user refreshes the page, I want a new random 6 to be selected. So maybe the query could limit it to 12 most-recent but only pluck 6 random results out to show. Is that a sensible idea in terms of processing etc.?
So my question is, how can I go about writing this query? Where should I begin? I am using PHP/CodeIgniter to drive this site with. Is it possible to get the entire lot in one query, or will I have to use multiple queries to do this? Or, do I need to simplify my ideas?
Thanks,
Jack
I've implemented something similar to this before. The route I took was to have a script run on the server every XX minutes to fill a table with a pool of items (say 20-30 items). Then the query to use in your application would be randomly pick 5 or so from that table.
Just need to setup an algorithm to select those 20-30 items. #Emmerman's is similar to what I used before to calculate a popularity_number where I took weights of multiple associations to the item (views, downloads, etc) to get an overall number. We also used an age to make sure the pool of items stayed up-to-date. You'll have to tinker with the algorithm over time to make sure the relevant items are being populated.
The idea is to calc some popularity which can be for e.g.
popularity = featured*W1 + downloads*W2 + views*W3 + fcount*W4
Where W1-W4 are constant weights.
Then add some random number to popularity and sort for it.

Categories