2014-07-02 36 views
2

我有以下查询(MySQL)非常慢(约15秒)。我改变了列和表的名字,所以很抱歉,如果它有任何类型的错误;原始查询正在工作,只保留这个概念,没有字面查询。两个表之间的SQL查询效率

SELECT 
id, 
b, 
(SELECT MAX(day) 
FROM all_days 
WHERE all_days.id = X.id 
) AS day 
FROM X 

请注意,all_days有超过200万行。我有3个索引:一个用于id,其他用于一天,另一个用于{id,day}

但是,如果我用UNION将查询分为N个查询,则只需约1秒钟或更少时间,结果相同:

<?php 
$ids = getIds(); // get all ID from X with a query 
$i = 0 
foreach ($ids as $id) { 
    if ($i++ > 0) { 
     $query .= " UNION "; 
    } 
    $query .= "SELECT MAX(day) 
    FROM all_days 
    WHERE all_days.id = $id"; 

} 
?> 

任何想法,我怎么能提高速度而不做联盟?

编辑(添加结构):

Table X: 
id INTEGER PRIMARY KEY 
b INTEGER -- extra info 

Table all_days: 
day_id INTEGER PRIMARY KEY 
id INTEGER FK X.id 
day DATETIME 

all_days indexes: 
id 
day 
id,day 
+1

它是不是从你清楚问题 - 有'all_days.id'上的索引吗? – Turophile

+0

请发布您的表格定义和用于完成信息的索引 – Dubas

+0

谢谢您的意见。我已经添加了结构。 – kanashin

回答

2

请有此查询一试:

SELECT 
id, 
b, 
max_day 
FROM X 
INNER JOIN 
(
    SELECT id, MAX(`day`) AS max_day 
    FROM all_days 
    GROUP BY id 
) AS max_days 
ON max_days.id = X.id 

之所以这样要快很多的,这里每ID最大(日)存储在内存中(如果太大,则存储在磁盘上的临时表中),然后连接到表X.在您的查询中,读取表X的每一行以及查询表all_days的每一行。

+0

@ user3796513你试过了吗? – Strawberry

+0

完美,谢谢。我必须了解为什么这个INNER JOIN如此高效(0.0006秒)与原始子查询相比。 – kanashin

+1

@ user3796513原因很简单,在这里每个ID最大(天)存储在磁盘上的内存或临时表,如果太大,然后连接到表X.在您的查询中,您阅读表X的每一行,并为每排您查询表all_days。你经历的速度非常慢。用'union'的方法根本没有意义,我必须说;) – fancyPants

0

在这样一个简单的情况下(假设X.id/XB是独一无二的组合),那么这可以,而不需要一个子查询来实现: -

SELECT X.id, 
     X.b, 
     MAX(all_days.day) AS day 
FROM X 
LEFT OUTER JOIN all_days 
ON all_days.id = X.id 
GROUP BY X.id, X.b 
+0

非常感谢您的评论。你的版本也在工作,但它需要大约3秒钟,而@fancyPants的花费少于0.001秒。我不知道为什么有这么多的差异。 – kanashin

+0

通常对于这样的简单查询,它会更快,因为它可以使用索引进行连接。 MySQL很难加入到子查询中(当子查询中只有少数记录时,这不是一个真正的问题),这可能会影响@fancyPants解决方案。在all_days表中覆盖id和day(按此顺序)的覆盖索引应该有效地加入。使用INNER JOIN会有所帮助,但如果X在all_days中记录不匹配,则无法应对(fancyPants解决方案无论如何都存在此问题)。你可以在桌子上以EXPLAIN的形式运行这个查询并发布结果。 – Kickstart