I don't get it, why is ibEconomy so godawful? I just went on a performance binge this afternoon and 95% of all the issues were from this stupid application. All these choices these guys made just scratches my head so much, I don't even understand.
First off, ibEconomy is the application we use for the shop and points. Caught up? Good.
While, scouring the site for slow pages, I came across the point shop tab on profile pages. On it, there were two slow queries taking more than 0.1 seconds to execute. Following one of them was a cache refresh of 66kB of data. Strangely, this was being refreshed every single time, so I was assuming the cache, for some reason, was incorrectly assuming the data did not exist in cache and was adding it. But no, that wasn't even the case, right in the middle of the code, with no checks, this function is called
Now if that wasn't bad, which is it, this next thing just baffles me on two levels. The next slow query I saw was returning over 6000 rows, one for each member in order of who has the most points. This confused me because the point shop page doesn't even show you what you're rank is. So I found this lovely bit of code
So, here's my fix
Sorry for being extremely bitter about this, but I'm just baffled this got into their final product, these aren't even difficult problems to solve. I'm afraid how they'll handle their update once IP.Board 4.0 comes out, everything has to be rewritten for it and ibEconomy isn't a small application; it has way more features than what we use it for. We'll see how it goes, but I can say with more certainty that this application isn't going on my "must wait for update before moving to 4.0" list.
First off, ibEconomy is the application we use for the shop and points. Caught up? Good.
While, scouring the site for slow pages, I came across the point shop tab on profile pages. On it, there were two slow queries taking more than 0.1 seconds to execute. Following one of them was a cache refresh of 66kB of data. Strangely, this was being refreshed every single time, so I was assuming the cache, for some reason, was incorrectly assuming the data did not exist in cache and was adding it. But no, that wasn't even the case, right in the middle of the code, with no checks, this function is called
#make sure we have item cache $this->registry->ecoclass->acm( array('banks', 'stocks', 'lts', 'ccs', 'shopitems') );I mean, sure the comment makes sense, it's good to have cache before you try to access it, and going by the comment, you would think this function would check for cache, and if the data doesn't exist, create it. However, what acm does, is a straight up recache. Doesn't matter if you already have the data cached, you're going to recalculate it by using very expensive queries. I mean, what? What's the goddamn point of using cache if you're going to recache it every single time you load the page? We aren't even changing any data in this, we're just grabbing it. You know what should've been done? Don't even call this, if the cache is empty, it's empty. I'm assuming this was a result of some bug where the cache didn't exist, but the fix is not to recache everything!
#make sure we have item cache $cacheTypes = array('banks', 'stocks', 'lts', 'ccs', 'shopitems') ; foreach($cacheTypes as $type) { if(!isset($this->cache['ibEco_' . $type])) $this->registry->ecoclass->acm( $type ); }There, now it won't recache unless we don't have the data in cache. I'm sorry, I guess 5 lines is not as efficient or cool-looking as 1 line.
Now if that wasn't bad, which is it, this next thing just baffles me on two levels. The next slow query I saw was returning over 6000 rows, one for each member in order of who has the most points. This confused me because the point shop page doesn't even show you what you're rank is. So I found this lovely bit of code
#awfully big query just to grab 1 number (rank) $member['eco_rank'] = $this->registry->mysql_ibEconomy->rankMembers( ($this->settings['eco_worth_on']) ? 'eco_worth' : 'points', $member['member_id'] );Oh good, they know they suck and instead of trying to find a better solution, they left it in. To be fair, MySQL does not have window functions (despite being in the SQL standard since 2003) which would have made this easier, but seriously querying AND returning all members every single time you want to see your rank? Here's something! You have the person's points cached and loaded already. Use it in the query! Grab a count of people who have points more than you, and then, get this, add 1. You did it! You got the rank of a single person! You didn't waste any resources scanning every single member! But that's not the best part. $member['eco_rank'] is not used ANYWHERE after it's set. Seriously, I traced every bit of ibEconomy's code that was called after setting the rank, nothing mentioning the rank. Good job, you're incredibly incompetent.
So, here's my fix
#awfully big query just to grab 1 number (rank) //$member['eco_rank'] = $this->registry->mysql_ibEconomy->rankMembers( ($this->settings['eco_worth_on']) ? 'eco_worth' : 'points', $member['member_id'] );Doing both fixes cut the execution time down from 2 seconds to 0.5 seconds. Not only that, the cache isn't being regenerated every single time someone is trying to view their points, but rather when something changes (you know, when it makes sense to).
Sorry for being extremely bitter about this, but I'm just baffled this got into their final product, these aren't even difficult problems to solve. I'm afraid how they'll handle their update once IP.Board 4.0 comes out, everything has to be rewritten for it and ibEconomy isn't a small application; it has way more features than what we use it for. We'll see how it goes, but I can say with more certainty that this application isn't going on my "must wait for update before moving to 4.0" list.