Author Topic: Common Mistakes to AVOID!  (Read 2416 times)

Offline codestryke

  • Administrator
  • Level 33
  • *****
  • Posts: 589
  • Reputation: +22/-0
    • View Profile
    • eXtremeCast Games
Common Mistakes to AVOID!
« on: September 24, 2006, 01:31:34 PM »
So I've been tinkering with the Gamer-Fusion 2.5 code (GF is an off shoot of the ExoFusion code). There is some good code in there but there is a LOT of code in that engine that is very poorly written and is indicative of the kind of coding you see when you get some of these "open source" games.

So lets look at some of the biggest mistakes and correct them with clean optimized code :)

throughout the game there are calls such as this:
Code: [Select]
$nump = @mysql_num_rows(mysql_query("select * from players"));

What this line is doing is getting the number of players the game has. The problem is it's loading the entire player table into memory and getting the number of rows. Say you had 25 fields in your player table and 1,000 players. Every time this code gets called you are loading ALL those fields and ALL those records into memory!!!! The line above was getting called in the footer.php file so on every page hit it was doing this. If you had 25 players online with 1,000 players in the database your performance would go down the tubes and your server would start to "lag".

Better way of doing it would be:
Code: [Select]
$nump = @mysql_fetch_array(mysql_query("select COUNT(*) from players"));

The above line is about 1000% faster with using almost very little memory or processing power! mySQL is highly optimized when using the COUNT(*) and it doesn't actually look at the records but instead looks at the header where the number of records is already stored ;)

-----------------------------------------------

Lets say you are not using a template system but instead using print/echo statements. First of all DON'T USE PRINT. Use echo, it's faster, see the PHP documentation as to why it's faster.

A common thing to do is to open a table and display the data in the table....
Code: [Select]
$psel = mysql_query("select * from players");
$ctime = time();
while ($pl = mysql_fetch_array($psel)) {
$span = ($ctime - $pl[lpv]);
if ($span <= 180) {
if ($pl[rank] == Admin) {
echo "!$pl[tag]<A href=view.php?view=$pl[id]>$pl[user]</a> ($pl[id])<br>";
} else {
echo "$pl[tag]<A href=view.php?view=$pl[id]>$pl[user]</a> ($pl[id])<br>";
}
$numo = ($numo + 1);
}
}

The above code is used to display all the player's that are currently online (another very common function). There are a number of huge performance problems with the above code so lets get to optimizing :)

First item is, once again, we are loading ALL the fields from the player table but the code is only using 4. Only load in the fields you are going to use!!!! It then gets the current time and starts looping though all the players and anyone who has hit a page in the last 180 seconds gets displayed. This is unnecessary as a good query will do the same thing and do it much faster (mySQL can process data WAY faster then PHP can!).

So lets first rewrite the query to only bring us what we need:
Code: [Select]
$psel = mysql_query("SELECT id, user, tag, rank FROM players WHERE lpv >= UNIX_TIMESTAMP()-180");

There so now we will get a record set back with only the fields we need and those that have hit a page in the last 180 which we assume are online. Wait though there is more to optimize!!!

As the loop is going though the records it's echo'ing out the results. This again is a huge performance constraint. You can (and most people do) just turn on output buffering to make it faster but it's still poor code design. Instead of echo'ing the results out line by line it should put the results in a variable and echo the entire result in one swoop!

The HIGHLY optimized version:
Code: [Select]
$numo = 0;
$online = "";
$psel = mysql_query("SELECT id, user, tag, rank FROM players WHERE lpv >= UNIX_TIMESTAMP()-180");
while( $pl = mysql_fetch_array($psel) ) {
if ($pl['rank'] == 'Admin') {
$online .= "!$pl[tag]<A href=view.php?view=$pl[id]>$pl[user]</a> ($pl[id])<br>";
}
else {
$online .= "$pl[tag]<A href=view.php?view=$pl[id]>$pl[user]</a> ($pl[id])<br>";
}
$numo = ($numo + 1);
}
echo $online;

I don't have any performance bench marks but I would say the above optimized version is a good 200-300% faster then the original and will hold up better under high usage without affecting server performance ;)



Hope ya all enjoyed this and found it useful ;)

Creating online addictions, one game at a time:

Offline 420laner666

  • Level 13
  • *
  • Posts: 102
  • Reputation: +3/-6
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #1 on: September 24, 2006, 01:36:03 PM »
kool this looks gd thanks man

Offline Zeggy

  • Global Moderator
  • Level 35
  • *****
  • Posts: 1,187
  • Reputation: +13/-4
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #2 on: September 27, 2006, 10:27:45 AM »
Nice tips about the COUNT(), never knew that :P

Offline Sava

  • Level 13
  • *
  • Posts: 101
  • Reputation: +3/-15
  • It's just me
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #3 on: September 28, 2006, 02:47:46 PM »
cool but I guess I kinda knew those ... by sight I guess :D

Offline dvd871

  • Level 21
  • *
  • Posts: 238
  • Reputation: +7/-0
    • View Profile
    • Dominion Siege
Re: Common Mistakes to AVOID!
« Reply #4 on: October 12, 2006, 03:18:30 PM »
Thats a good thing to point out codestryke, only select the data from the database that you need.  Keep a minimal approach to your design.  Another thing I would recommend having, even just for deveolpment purposes, is a query counter.
Code: [Select]
$db_q = array();
$db_q['queries']=0;

function db_query($sql){
    global $db_q;
    $db_q['queries']++;
    $q = mysql_query($sql);
    if (!$q) {
        return array();
    }
    unset($db_q['affected_rows']);
    $db_q['affected_rows'] = mysql_affected_rows();
    return $q;
}

Now just use db_query instead of mysql_query and your query count will be stored in $db_q['queries'].

Offline ScriptStealer

  • Level 7
  • *
  • Posts: 33
  • Reputation: +0/-0
    • View Profile
    • iNFO Tyrant
Re: Common Mistakes to AVOID!
« Reply #5 on: October 30, 2006, 04:46:29 AM »
Nice work. Gonna need that later on! I wanna give you karma but I still don't know how...haha. Hope I can learn soon...
« Last Edit: October 30, 2006, 04:48:12 AM by ScriptStealer »
What if Peter Piper didn't pick a pepper?
What if the woodchuck couldn't chuck wood?
What if the chicken didn't cross the road?

The answer to all of life's mysteries lies here...The Most Worthless Website in Existence! http://www.clickmeandy

Offline Zeggy

  • Global Moderator
  • Level 35
  • *****
  • Posts: 1,187
  • Reputation: +13/-4
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #6 on: October 30, 2006, 06:37:37 AM »
I sort of disabled karma for everybody below 150 posts because some people were abusing the system :/

Offline Mgccl

  • Level 7
  • *
  • Posts: 33
  • Reputation: +1/-0
    • View Profile
    • WebDevLogs
Re: Common Mistakes to AVOID!
« Reply #7 on: November 09, 2006, 10:04:58 PM »
can't it be faster and use less mem if you use
mysql_fetch_assoc?
and where can you find Gamer-fusion and exofusion?

Offline Pug307

  • Level 21
  • *
  • Posts: 244
  • Reputation: +6/-1
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #8 on: November 10, 2006, 09:10:31 AM »
Both Gamer-fusion and exofusion are in the vault of the forums. Im not sure what you have to do to be able to get in there now though. Zeg will be able to advise you a little bit better on this one.



Offline etali

  • Level 4
  • *
  • Posts: 10
  • Reputation: +0/-0
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #9 on: November 10, 2006, 10:21:22 AM »
Some good tips there - the number of sites I see with 'custom coded' CMS-es where the kind of mistakes you've mentioned are made is pretty disgraceful - putting that kind of coding into a game (where theres even more load on the server than just an occasional page view) would be pretty nasty.

Offline Zeggy

  • Global Moderator
  • Level 35
  • *****
  • Posts: 1,187
  • Reputation: +13/-4
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #10 on: November 10, 2006, 10:22:56 AM »
To get access to the scripts vault, you need to make 100 posts.
I'm thinking of lowering that requirement though, so sit tight :)
I'm asking the forum staff on this one.
(So if any mods see this, please go to the staff chat at the bottom of the forum to read my topic :))

Offline codestryke

  • Administrator
  • Level 33
  • *****
  • Posts: 589
  • Reputation: +22/-0
    • View Profile
    • eXtremeCast Games
Re: Common Mistakes to AVOID!
« Reply #11 on: November 10, 2006, 04:42:36 PM »
can't it be faster and use less mem if you use
mysql_fetch_assoc?
and where can you find Gamer-fusion and exofusion?

Depends ADODB comes with a C compiled version of the class and auto-detects if it can use it or the PHP class. If it uses the C version then it's the same as the built in mysql commands, but still uses a bit more memory. If it uses the classes written in PHP then yes you do have both speed and a memory overhead.

Times like these though you have to make a choice, do you want to go with raw commands and be stuck with mySQL or take a little hit and uses something that can be used with more then one type of database. Yes most hosts have mySQL installed and right now mySQL is the toast of the town. However mySQL is not the end all be all in databases, something could happen, you may need to go to a host that for some reason only allows X database like Postgres or something. Use ADO and you many need to rewrite a query or two.. Go with raw mySQL commands and you have to re-write every db call in you game.

Personally, I code for the maximum compatibility or cross over I can. All my CRON jobs are written in PERL because every unix box has PERL access (a lot of hosts that provide Microsoft Servers have PERL installed). So writing those automated scripts in PERL gives me the ability to jump ship to another platform if the price per megabit is cheaper then what I pay now. I've been with the same hosting company now for 4 years and am pretty happy but that doesn't prevent me from being lazy cuz I already had to rewrite 2 games to support a new platform!

I love making games and I love when people play them and get all caught up in them.. However I also do this for a profit and to do it as such I can't be content with 100 signups and 1-10 ppl online at once. I do over 10k signups with 100-200 ppl online at any given time because thats the kind of volume you need to push if you want to make money from online games.

Creating online addictions, one game at a time:

Offline greendots

  • Level 3
  • *
  • Posts: 8
  • Reputation: +0/-0
    • View Profile
Re: Common Mistakes to AVOID!
« Reply #12 on: May 15, 2008, 02:52:12 AM »
Count (*) is not slow.   A MYISAM table always knows how many records their are in each table.  This query is always quickly excecuted unless the table is not ISAM.  This will only be the case if you have specificly created a different table type, as mysql creates myisam tables by default.

 


SimplePortal 2.3.3 © 2008-2010, SimplePortal