开发者

MySQL Slow Query Optimisation

I have a database ~800k records showing ticket purchases. All tables are InnoDB. The slow query is:

SELECT e.id AS id, e.name AS name, e.url AS url, p.action AS action, gk.key AS `key`
FROM event AS e
    LEFT JOIN participation AS p ON p.event=e.id
    LEFT JOIN goldenkey AS gk ON gk.issuedto=p.person
WHERE p.person='139160'
    OR p.person IS NULL;

This query is coming from PDO hence quoting of p.person. All columns used in JOINs and WHERE are indexed. p.event is foreign key constrained to e.id and gk.issuedto and p.person are foreign key constrained to an unmentioned table, person.id. All these are INTs. The table e is small - only 10 rows. Table p is ~500,000 rows and gk is empty at this time.

This query runs on a person's details page. We want to get a list of all events, then if there is a participation row their participation and if there is a golden key row then their golden key.

Slow query log gives:

Query_time: 12.391201  Lock_time: 0.000093 Rows_sent: 2  Rows_examined: 466104

EXPLAIN SELECT gives:

+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
| id | select_type | table | type | possible_keys | key      | key_len | ref            | rows | Extra       |
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
|  1 | SIMPLE      | e     | ALL  | NULL          | NULL     | NULL    | NULL           |   10 |             |
|  1 | SIMPLE      | p     | ref  | event         | event 开发者_如何学JAVA   | 4       | msadb.e.id     |  727 | Using where |
|  1 | SIMPLE      | gk    | ref  | issuedto      | issuedto | 4       | msadb.p.person |    1 |             |
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+

This query runs at 7~12 seconds on first run for a given p.person then <0.05s in future. Dropping the OR p.person IS NULL does not improve query time. This query slowed right down when the size of p was increased from ~20k to ~500k (import of old data).

Does anyone have any suggestions on how to improve performance? Remembering overall aim is to retrieve a list of all events, then if there is a participation row their participation and if there is a golden key row then their golden key. If multiple queries will be more efficient I can do that.


If you can do away with p.person IS NULL try the following and see if it helps:

SELECT e.id AS id, e.name AS name, e.url AS url, p.action AS action, gk.key AS `key`
FROM event AS e
    LEFT JOIN participation AS p ON (p.event=e.id AND p.person='139160')
    LEFT JOIN goldenkey AS gk ON gk.issuedto=p.person


For grins... Add the keyword "STRAIGHT_JOIN" to your select...

SELECT STRAIGHT_JOIN   ... rest of query...


I'm not sure how many indexes you have and schema of your table, but try avoid using null values by default, it can slow down your queries dramatically.


If you are doing a lookup for one particular person, which I'm guessing you are since you have the person id filter in there. I would try and reverse the query, so you are first searching though the person table and then making a union to and additional query which gives you all the events.

SELECT 
     e.id AS id, e.name AS name, e.url AS url, 
     p.action AS action, gk.key AS `key`
FROM person AS p
    JOIN event AS e ON p.event=e.id
    LEFT JOIN goldenkey AS gk ON gk.issuedto=p.person

UNION

SELECT
    e.id AS id, e.name AS name, e.url AS url,
    NULL, NULL
FROM event AS e 

This would obviously mean you have a duplicate event in case the first query matches, but thats easily solved by wrapping a select around the whole thing, or maybe by using a variable and selecting the e.id into that in the first query and using that variable in the second query (not sure if this will work though, haven't tested it, cant see why not though).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜