I'm learning MongoDB and am considering moving a very data-heavy (MySQL) app of mine to it. I've worked hard to improve performance of the MySQL side.
With roughly 90k records in each database, I've run the same query in MySQL and MongoDB. I've read up on MongoDB indexes and since they work very similarly, I've added the same "main" index to MongoDB as we use in MySQL.
However, Mongo is almost three times slower. I've heard a ton about how mongo is generally a lot faster, and even if it's not, it shouldn't be three times slower.
Is there something I'm missing?
This query in MongoDB returns 1000 records in 0.085 seconds:
db.prismData.find(
{
"x":{
"$gt":306,
"$lt":366
},
"y":{
"$gt":35,
"$lt":95
},
"z":{
"$gt":122,
"$lt":182
},
"epoch":{
"$gte":1396226195
},
"world":"world"
})
.sort( { "epoch" : -1 , "x" : 1 , "z" : 1 , "y" : 1 , "id" : -1} )
.limit(1000);
The explain for the above query:
{
"cursor" : "BtreeCursor world_1_x_1_z_1_y_1_epoch_1_action_1",
"isMultiKey" : false,
"n" : 1000,
"nscannedObjects" : 7773,
"nscanned" : 8041,
"nscannedObjectsAllPlans" : 7881,
"nscannedAllPlans" : 8149,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 84,
"indexBounds" : {
"world" : [
[
"world",
"world"
]
],
"x" : [
[
306,
366
]
],
"z" : [
[
122,
182
]
],
"y" : [
[
35,
95
]
],
"action" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "removed"
}
MySQL runs the entire in query, returns 1000 records in 0.03 seconds.
SELECT id,
epoch,
action_id,
player,
world_id,
x,
y,
z,
block_id,
block_subid,
old_block_id,
old_block_subid,
DATA
FROM prism_data
INNER JOIN prism_players p ON p.player_id = prism_data.player_id
LEFT JOIN prism_data_extra ex ON ex.data_id = prism_data.id
WHERE world_id =
(SELECT w.world_id
FROM prism_worlds w
WHERE w.world = 'world')
AND (prism_data.x BETWEEN 427 AND 487)
AND (prism_data.y BETWEEN 36 AND 96)
AND (prism_data.z BETWEEN -14 AND 46)
AND prism_data.epoch >= 1396225265
ORDER BY prism_data.epoch DESC,
x ASC,
z ASC,
y ASC,
id DESC LIMIT 1000;
An explain for this sql:
+----+-------------+------------+--------+----------------+----------+---------+----------------------------------+-------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+----------------+----------+---------+----------------------------------+-------+----------------------------------------------------+
| 1 | PRIMARY | prism_data | ref | epoch,location | location | 4 | const | 43925 | Using index condition; Using where; Using filesort |
| 1 | PRIMARY | p | eq_ref | PRIMARY | PRIMARY | 4 | prism_daily.prism_data.player_id | 1 | NULL |
| 1 | PRIMARY | ex | ref | data_id | data_id | 4 | prism_daily.prism_data.id | 1 | NULL |
| 2 | SUBQUERY | w | const | world | world | 767 | const | 1 | Using index |
+----+-------------+------------+--------+----------------+----------+---------+----------------------------------+-------+----------------------------------------------------+
The only difference in schema is that some repetitive data like people names, and event names are being stored in the document rather than normalized out using foreign keys in mysql. Based on what I've read this is not really needed in mongo, unless there's more of a many-to-many relationship.