Would this be faster / more efficient?
Moderator: General Moderators
- Josh1billion
- Forum Contributor
- Posts: 316
- Joined: Tue Sep 11, 2007 3:25 pm
Would this be faster / more efficient?
For the inventory of my game, I currently have one long string (0,0,0,0,0,0,..etc) for the user's inventory where the 0's are the quantities of items they have. Example: the first entry there would be item id 0, then id 1, 2, etc... the string represents how many the user has of that particular item. I use explode() and implode() when dealing with that string (to turn it into an array and back), so basically whenever I have a file which needs to know how many of a particular item that user has, I have a function called GetInventory() which selects that string from the database for the user, and explode()s it, then returns the new array. Then for the rest of the file, I just use that array to see the quantities of items that user has.
Clearly it might slow the server down, since that string has a couple thousand "0,"s in it. I mean the array has a couple thousand indexes.
I'm considering whether I should change this to a new, similar system which would be two "string arrays," as I like to call them, instead of one. The first "string array" would be the id's of the items in the user's inventory, and the second one would hold the quantities of those items. That way, instead of having every single item in the game (whether the user has it or not) in the string, only items the user actually has would be in the strings. If the user has 0 quantity of an item, the item would not be in either string. So the two strings' lengths would vary depending on how many different types of items the user has in his/her inventory, but usually each "string array" for the new method would contain maybe 30 or 40 keys (30 or 40 different types of items).
Would this new system generally be faster, or are the two slowdowns (SELECT'ing a very large string from a database and then explode()ing it) fast enough not to worry about it?
Also, if I do choose to use the new system: I would have a "GetItemQuantity()" function which returns how many of a certain item (based on the item id #) the user has. I have two ways to go about doing this, which would be faster?:
1. Having the code to SELECT and explode both "string arrays" all inside of the function.
2. SELECTing and exploding the two string arrays before calling the function, and then passing those two arrays (or pointers to them) to the function (would this cause much function-calling overhead?).
Clearly it might slow the server down, since that string has a couple thousand "0,"s in it. I mean the array has a couple thousand indexes.
I'm considering whether I should change this to a new, similar system which would be two "string arrays," as I like to call them, instead of one. The first "string array" would be the id's of the items in the user's inventory, and the second one would hold the quantities of those items. That way, instead of having every single item in the game (whether the user has it or not) in the string, only items the user actually has would be in the strings. If the user has 0 quantity of an item, the item would not be in either string. So the two strings' lengths would vary depending on how many different types of items the user has in his/her inventory, but usually each "string array" for the new method would contain maybe 30 or 40 keys (30 or 40 different types of items).
Would this new system generally be faster, or are the two slowdowns (SELECT'ing a very large string from a database and then explode()ing it) fast enough not to worry about it?
Also, if I do choose to use the new system: I would have a "GetItemQuantity()" function which returns how many of a certain item (based on the item id #) the user has. I have two ways to go about doing this, which would be faster?:
1. Having the code to SELECT and explode both "string arrays" all inside of the function.
2. SELECTing and exploding the two string arrays before calling the function, and then passing those two arrays (or pointers to them) to the function (would this cause much function-calling overhead?).
- Josh1billion
- Forum Contributor
- Posts: 316
- Joined: Tue Sep 11, 2007 3:25 pm
- Kieran Huggins
- DevNet Master
- Posts: 3635
- Joined: Wed Dec 06, 2006 4:14 pm
- Location: Toronto, Canada
- Contact:
I'm not sure there would be much of a difference... not enough to worry about, at any rate.
Have you considered using un/serialize() ?
Might be a significant speed improvement there. Or not. Worth a try? Maybe.
Have you considered using un/serialize() ?
Might be a significant speed improvement there. Or not. Worth a try? Maybe.
- Kieran Huggins
- DevNet Master
- Posts: 3635
- Joined: Wed Dec 06, 2006 4:14 pm
- Location: Toronto, Canada
- Contact:
I sort of disagree with feyd - and am probably wrong!
My thinking is that for something along the lines of an item inventory with LOTS of items, the DB overhead of storing & pulling out several hundred rows would be overkill.
You do lose some functionality, obviously, but the recap in development time is worth it, IMO.
My thinking is that for something along the lines of an item inventory with LOTS of items, the DB overhead of storing & pulling out several hundred rows would be overkill.
You do lose some functionality, obviously, but the recap in development time is worth it, IMO.
- Josh1billion
- Forum Contributor
- Posts: 316
- Joined: Tue Sep 11, 2007 3:25 pm
I'm not sure what feyd means by normalizing (something I've never needed to research), but referring back to my original post, I have tested the two methods out now, and the result is that the new method is much faster.
Specifically, the new method is faster if the given user doesn't have too many different types of items-- i.e. the only case where the new method would be slower for that user would be if the user has at least one of nearly every type of item in the game: it would take several thousand items for the slowdown to occur. Still, the difference would be very, very small, but since it also will save space with this new system, I've decided to go through with it.
Specifically, the new method is faster if the given user doesn't have too many different types of items-- i.e. the only case where the new method would be slower for that user would be if the user has at least one of nearly every type of item in the game: it would take several thousand items for the slowdown to occur. Still, the difference would be very, very small, but since it also will save space with this new system, I've decided to go through with it.
I would normalize, if for no other reason than to formalize the relationship of the inventory to the player.
Also, it'll make sorting a part of the query. Hey, when you sort items in the game, you aren't actually sorting your arrays and re-saving them are you?
Anyhow, normalizing in this case would, I believe, require a new table for inventory items. You'd need fields for user_id, item_id, and quantity, plus a primary key (or use user_id and item_id). Then to assign an item to a player, you just insert the item id, quantity and assign it to a user by user_id.
To get an inventory list, pull from inventory list by user_id, joined to the items table for description and other statistics, costs etc. All the info you need to display returned by one query, and if you want to do a sort, you just adjust your query to sort on that parameter and you dont need to do any post processing.
I cant see a user having thousands of different items, and if inventory size is an issue, then you can always resort to the old standby of limiting how much you can carry. If inventory lists got too long, I have no doubts complains from having to search through items will become an issue faster than processing time would.
Also, it'll make sorting a part of the query. Hey, when you sort items in the game, you aren't actually sorting your arrays and re-saving them are you?
Anyhow, normalizing in this case would, I believe, require a new table for inventory items. You'd need fields for user_id, item_id, and quantity, plus a primary key (or use user_id and item_id). Then to assign an item to a player, you just insert the item id, quantity and assign it to a user by user_id.
To get an inventory list, pull from inventory list by user_id, joined to the items table for description and other statistics, costs etc. All the info you need to display returned by one query, and if you want to do a sort, you just adjust your query to sort on that parameter and you dont need to do any post processing.
I cant see a user having thousands of different items, and if inventory size is an issue, then you can always resort to the old standby of limiting how much you can carry. If inventory lists got too long, I have no doubts complains from having to search through items will become an issue faster than processing time would.
- Josh1billion
- Forum Contributor
- Posts: 316
- Joined: Tue Sep 11, 2007 3:25 pm
To be honest, I don't know what normalizing is. I've only known PHP for about three years, and used it on and off since then.
It's a little slow, but I did some testing (to clock it) and it shouldn't ever become a problem. I still put in a 15-second window between sorting (for just that person) though to ease any potential load inflicted by it.
Yes.Stryks wrote:Hey, when you sort items in the game, you aren't actually sorting your arrays and re-saving them are you?
Normalizing would mean storing in tables with a common id, and selecting only the information you need at a particular time. 
http://en.wikipedia.org/wiki/Database_normalization
EDIT| And yeah, I would agree with feyd, here.
http://en.wikipedia.org/wiki/Database_normalization
EDIT| And yeah, I would agree with feyd, here.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
- superdezign
- DevNet Master
- Posts: 4135
- Joined: Sat Jan 20, 2007 11:06 pm
You could always limit their inventory size like most games do, and then instead of having the amount of every item in the entire game stored for each user, only have the amount and type of items that each user has, up to your limit of inventory space. For speed, I agree with you on not worrying about normalizing the tables. Just serialize and unserialize the user's inventory array / object.
- Kieran Huggins
- DevNet Master
- Posts: 3635
- Joined: Wed Dec 06, 2006 4:14 pm
- Location: Toronto, Canada
- Contact:
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Would this be faster / more efficient?
Maybe you should store the inventory as a parameterized string. That way you only need to store what is actually in inventory, not a placeholder for everything possible. It would also be much more extensible. So instead of "0,0,0,0,0,0," you have "axe=1&tent=1&matches=99" or if you want to save space you could make the keys indexes into a name array array(44=>'axe', 45=>'tent', 46='matches') so you would only need to store "44=1&45=1&46=99". Use parse_str() to turn you inventory string into an array.Josh1billion wrote:For the inventory of my game, I currently have one long string (0,0,0,0,0,0,..etc)...
Clearly it might slow the server down, since that string has a couple thousand "0,"s in it. I mean the array has a couple thousand indexes.
(#10850)
This case is possibly marginal; you would expect an inventory system to be fairly predictable in the way you access the data.
However, I would go with the normalized version pretty much every time, as you dont want to get to the end of a project and think "Now, how can I access that data with the predicted dataflow reversed?".
Say you decide that you want to pull a list of players using a certain item ... or you want to get a count of how many of a specific item are in circulation ... using the normalized approach will allow you to knock out a simple query and have your data in seconds.
While I'm sure that some of the extremely talented people on this board could come up with a solution to find your data from the compacted data, why not just take a little time at the start to put the data in a format that allows maximum manipulation?
I ask that question knowing that there will probably be valid reasons quoted, but I would still wear any overhead caused to ensure that I didn't have to do a rewrite or workaround later.
But then, if you know you'll never want to access your data in this way, then there's no real reason why you wouldn't do it in the ways listed above.
However, I would go with the normalized version pretty much every time, as you dont want to get to the end of a project and think "Now, how can I access that data with the predicted dataflow reversed?".
Say you decide that you want to pull a list of players using a certain item ... or you want to get a count of how many of a specific item are in circulation ... using the normalized approach will allow you to knock out a simple query and have your data in seconds.
While I'm sure that some of the extremely talented people on this board could come up with a solution to find your data from the compacted data, why not just take a little time at the start to put the data in a format that allows maximum manipulation?
I ask that question knowing that there will probably be valid reasons quoted, but I would still wear any overhead caused to ensure that I didn't have to do a rewrite or workaround later.
But then, if you know you'll never want to access your data in this way, then there's no real reason why you wouldn't do it in the ways listed above.