Reputation: 160
I have a database that has a bunch of market orders for a game. My intent with the DB is to buy low and sell high so what I do is search for any product that I can make money off of. I enter a starting point and a end point and then check the DB for products that are for sale at the starting location and also check the end point for any buy orders that match and have a profit.
Right now I have about 750k listings and it takes about 8 seconds to process the query. It took less time when I had less rows. I will probably have over a 5 million entries once the database is full and I need to figure how how to speed up my query. I know when I take out the HAVING and ORDER BY, it takes about .25/s to query. Is there another way to do this in mySQL or should I find a way to do it in PHP? Any help would be appreciated!
Here is my query:
SELECT DISTINCT
f.orderID as fOrderID,
f.typeID as fTypeId,
f.solarSystemID as fSystemId,
f.regionID as fRegionId,
f.price as fPrice,
f.volRemaining as fVolRemain,
f.bid as fBid,
f.reportedTime as fReportedTime,
t.orderID as tOrderID,
t.typeID as tTypeId,
t.solarSystemID as tSystemId,
t.regionID as tRegionId,
t.price as tPrice,
t.volRemaining as tVolRemain,
t.bid as tBid,
if(((f.volRemaining < t.volRemaining)),
((f.volRemaining * t.price) - (f.price * f.volRemaining)),
((t.volRemaining * t.Price) - (f.price * t.volRemaining))) as profit,
t.reportedTime as tReporedtTime
FROM marketData as f
JOIN marketData as t on t.typeID = f.typeID
WHERE f.regionID = 10000001
AND t.regionID = 10000030
AND f.bid = 0
AND t.bid = 1
GROUP BY f.orderID
HAVING profit > 1000000
ORDER BY profit DESC
LIMIT 100
MarketDB Layout(doesn't include 9 additional columns that I'm not using right now):
prim-unique indexed
+-------------------------------------------------------+
| orderID | regionID | stationID | typeID | bid | price |
+-------------------------------------------------------+
| 12345 | 223344 | 334455 | 13 | 0 | 22.43 |
| 12543 | 298474 | 348993 | 13 | 1 | 24.55 |
| 24574 | 273646 | 392273 | 13 | 0 | 19.32 |
+-------------------------------------------------------+
EDITED: ADDED EXPLAIN:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE f ALL typeID NULL NULL NULL 761338 Using where; Using temporary; Using filesort
1 SIMPLE t ref typeID typeID 8 market.f.typeID 76 Using where
Upvotes: 2
Views: 794
Reputation: 833
It looks like the table should have 2 indexes. One index that includes (regionID,bid,typeID), probably in that order, and a second index that just has (typeID). The first index will be used to quickly scan f for records that match the criteria and retrieve the typeID (it's in the index). The second index, will be used on t for the join. I'm not sure why it doesn't use the larger index to include the where clause at the same time, but it could change with a later version of MySQL.
Depending on your actual data patterns, you might be able to tweak the first index a little more by creating multiple variations of it at the same time, that just try the 6 different possible orders, and run an explain plan to see which index is used. Then simply drop the unused indexes.
Note 1: Having the two indexes will slow down your inserts and deletes on the table, but I would expect the speed of this join query to be a bigger issue, especially without the indexes.
Note 2: Reducing the number of columns in the table will also help slightly, but does not address the scaling issue with a join.
Upvotes: 2