我有一个数据库~800k记录显示购票。所有表都是InnoDB。慢查询是:
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;
此查询来自PDO,因此引用了p.person
。 JOIN
和WHERE
中使用的所有列都已编制索引。 p.event
是受e.id
限制的外键,而gk.issuedto
和p.person
是受限于未提及的表person.id
的外键。所有这些都是INT
。表e
很小 - 只有10行。表p
约为500,000行,此时gk
为空。
此查询在个人详细信息页面上运行。我们希望获得所有活动的列表,然后如果有参与行参与,如果有一个金钥匙行,那么他们的金钥匙。
慢查询日志给出:
Query_time: 12.391201 Lock_time: 0.000093 Rows_sent: 2 Rows_examined: 466104
EXPLAIN SELECT
给出:
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
| 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 | 4 | msadb.e.id | 727 | Using where |
| 1 | SIMPLE | gk | ref | issuedto | issuedto | 4 | msadb.p.person | 1 | |
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
对于给定的p.person
,此查询在首次运行时运行7~12秒,然后将<0.05s。删除OR p.person IS NULL
不会缩短查询时间。当p
的大小从~20k增加到~500k(导入旧数据)时,此查询会减慢。
有没有人对如何提高性能有任何建议?记住总体目标是检索所有事件的列表,然后如果有参与行他们的参与,如果有一个金钥匙行,那么他们的金钥匙。如果多个查询效率更高,我可以做到。
答案 0 :(得分:1)
如果您可以取消p.person IS NULL
,请尝试以下操作,看看是否有帮助:
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
答案 1 :(得分:0)
对于笑脸...将关键字“STRAIGHT_JOIN”添加到您的选择...
SELECT STRAIGHT_JOIN ... rest of query...
答案 2 :(得分:0)
我不确定您拥有多少索引和表格架构,但请尝试避免在默认情况下使用空值,这会大大减慢您的查询速度。
答案 3 :(得分:0)
我会尝试在参与时添加或修改索引,因此索引由两个列组成,即事件和人。
(编辑)
我的理由是,如果查询优化器不是真正的聪明,它会将事件索引用于参与,但由于你的事件很少,将扫描大量具有该事件的分区,寻找记录( s)具有where子句中的person值。通过将人员标记为参与事件索引,它为查询优化器提供了可以使用的功能,以避免使用该事件扫描所有这些参与。
答案 4 :(得分:0)
如果你正在为一个特定的人进行查找,我猜你是因为你有人ID过滤器。我会尝试反转查询,因此您首先搜索人员表,然后进行联合以及为您提供所有事件的附加查询。
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
这显然意味着你有一个重复的事件,以防第一个查询匹配,但这很容易通过在整个事物周围包装一个选择,或者可能通过使用变量并在第一个查询中选择e.id来解决并在第二个查询中使用该变量(不确定这是否可行,但尚未测试,但不知道为什么不这样做)。