Reputation: 437
I've been on shared hosting for a long time and have been running the same queries for months without a problem. All of the sudden I get an email from my host saying they put a block on my database because "The database was found to be consuming an inordinate amount of processor time". What I don't understand is why now? So anyways I thought maybe I need to go VPS. Trying to get my site up on a VPS and immediately it the whole site has an out of memory limit error and has crashed. For a while the connection was timing out while going to the site at all.
None of my tables are very large nothing more than 10,000 rows. Here are some things my original host sent me:
DB_USER: my_user -- TOTAL_CONNECTIONS: 37 -- CONNECTED_TIME: 4906 --
CPU_TIME: 1920 -- TABLE_ROW_READS: 79999077 -- SELECT_COMMANDS: 214 --
UPDATE_COMMANDS: -- BUSY_TIME: 4879 -- BYTES_SENT: 252225 --
BYTES_RECEIVED: 105418 -- WAIT_TIME (IO): 2959
Table row reads 79,999,077?? Seriously how does that work. My tables are all small. I don't get a lot of traffic. Maybe 100-150 people a day. But that doesn't seem to matter because the site completely died right when I put it up on the new server. Here is a query that was in the email saying my database is down. Is it really only this one query that's killing me? It's been up for literally months without a problem:
SELECT `Person`.`first_name`, `Person`.`last_name`,`Person`.`id`,`Upload`.`path`,`TeacherBiography`.`final_biography`, `TeacherPhilosophy`.`final_philosophy`
FROM `my_database`.`people` AS `Person`
LEFT JOIN `my_database`.`teacher_drive_cities` AS `TeacherDriveCity`
ON (`TeacherDriveCity`.`person_id` = `Person`.`id`)
LEFT JOIN `my_database`.`instruments_people` AS `InstrumentsPerson`
ON (`InstrumentsPerson`.`person_id` = `Person`.`id`)
LEFT JOIN `my_database`.`instruments` AS `Instrument`
ON (`Instrument`.`id` = `InstrumentsPerson`.`instrument_id`)
LEFT JOIN `my_database`.`teachers` AS `Teacher`
ON (`Teacher`.`person_id` = `Person`.`id`)
LEFT JOIN `my_database`.`uploads` AS `Upload`
ON (`Upload`.`person_id` = `Person`.`id`)
LEFT JOIN `my_database`.`teacher_biographies` AS `TeacherBiography`
ON (`TeacherBiography`.`person_id` = `Person`.`id`)
LEFT JOIN `my_database`.`teacher_philosophies` AS `TeacherPhilosophy`
ON (`TeacherPhilosophy`.`person_id` = `Person`.`id`)
WHERE `TeacherDriveCit! y`.`city` = 'Dana Point'
AND `TeacherDriveCity`.`state` = 'ca'
AND `Instrument`.`instrument` = 'saxophone'
AND `Teacher`.`status` = 6
AND `Upload`.`description` = 'profile_picture'
AND `TeacherBiography`.`final_biography` IS NOT NULL
AND `TeacherPhilosophy`.`final_philosophy` IS NOT NULL
GROUP BY `Person`.`id`
ORDER BY RAND() ASC
LIMIT 3
I've heard order by rand() is slow, but I didn't think it would crash the entire server in one call. Am I missing something here? Any help would be appreciated! My sites been down for 24 hours and I live off the income from it. Thanks!
Edit: Here is the explain on the query:
1 SIMPLE TeacherBiography ALL NULL NULL NULL NULL 41 Using where; Using temporary; Using filesort
1 SIMPLE TeacherPhilosophy ALL NULL NULL NULL NULL 41 Using where; Using join buffer
1 SIMPLE Upload ALL NULL NULL NULL NULL 166 Using where; Using join buffer
1 SIMPLE Teacher ALL NULL NULL NULL NULL 381 Using where; Using join buffer
1 SIMPLE InstrumentsPerson ALL NULL NULL NULL NULL 647 Using join buffer
1 SIMPLE Instrument eq_ref PRIMARY PRIMARY 4 yml_yml.InstrumentsPerson.instrument_id 1 Using where
1 SIMPLE Person eq_ref PRIMARY PRIMARY 4 yml_yml.TeacherPhilosophy.person_id 1 Using where
1 SIMPLE TeacherDriveCity ALL NULL NULL NULL NULL 7489 Using where; Using join buffer
I know it's not formatted so you can read it easy... I don't know how to make it a table and what not here. Sorry!
Upvotes: 0
Views: 532
Reputation: 5399
There are a lot of things that could be affecting your query, using EXPLAIN
should reveal the issues that have the most impact on performance.
But here are a few general guidelines:
LEFT JOIN
and then filter on concrete values on the WHERE
clause? Using outer joins will increment the number of rows that would later be filtered and discarded by the conditions on the WHERE
clause.Person.id
if then you order randomly? The grouping forces a sort operation that most probably requires a temporary table due to the table joins.Now think also about this:
The way databases process joins in general is by combining all rows from each table and then discard the combinations that don't fulfill the join condition. That's why it's very important to have indexes on the join fields, because that way the combination uses the index keys and not a temporary table with all fields from both tables. That's also a reason not to use a LEFT JOIN
and then later discard row combinations (in the WHERE
clause) that could have been discarded earlier.
To get an idea of what this query is doing, and why it's affecting performance so badly calculate:
Total rows to filter = Number of rows in table Person
* Number of rows in table TeacherDriveCity
* Number of rows in table Instrument
* Number of rows in table Teacher
* Number of rows in table Upload
* Number of rows in table TeacherBiography
* Number of rows in table TeacherPhilosophy
I'm pretty sure that would be a very big number.
EXPLAIN
interpretation
From the posted EXPLAIN
results it's very bad:
ALL
values under join type
mean that MySQL is doing a full table scan, that is it must read all the rows on table. This is very, very bad.NULL
under possible_keys
for most of the join conditions. This is another reason for MySQL to do table scans, it must look through all the joined rows to filter the needed rows.I would say that the worst part is filtering by city
and state
. Without joins a simple look up in the TeacherDriveCity
by those two fields would require MySQL to look at potentially 7489 rows. Not to mention that both fields hold character strings.
Quick Fix
Add indexes on all columns used in JOIN
and WHERE
clauses. But consider not using outer (LEFT
) joins on tables other that TeacherBiography
and TeacherPhilosophy
.
Upvotes: 1