为两个大表增加MySQL JOIN的速度

时间:2010-01-06 09:06:43

标签: mysql

我必须在MySQL查询中加入大表,这需要很长时间 - 大约180秒。有没有优化合并的提示?

我的桌子有10个字段。我只在查询中使用4 - 所有字符串。表有大约600,000行,结果应该有大约50行。

使用的四行是:标题,变量,位置,日期

这是我的问题:

SELECT DISTINCT t1.Title, t1.Variables FROM `MyTABLE` t1 JOIN `MyTABLE` t2  
USING (Title,  Variables) 
WHERE (t1.Location, t1.Date) = ('Location1', 'Date1') 
AND (t2.Location, t2.Date) = ('Location2', 'Date2')

8 个答案:

答案 0 :(得分:8)

像其他人指出的那样,你需要适当的索引。对于此特定查询,您可以从以下索引中受益:

Location, Date)或(Date, Location)(对于WHERE子句) 和 (Title, Variables)或(Variables, Title)(针对join条件,ON条款)

确切地知道位置,日期,标题和变量列的大小(即数据类型)会很有帮助,因为大索引可能比小索引慢。

最后,只是一个提示:我不会像你那样使用花哨的比较结构。

USING (Title,  Variables) 

可能没问题,但我肯定会检查是否

(t1.Location, t1.Date) = ('Location1', 'Date1') 

(t2.Location, t2.Forecast_date) = ('Location2', 'Date2')

表现得像你期望的那样。所以我肯定会在其上运行EXPLAIN,并将输出与“常规”旧式比较进行比较,如下所示:

    t1.Location      = 'Location1'
AND t1.Date          = 'Date1'
AND t2.Location      = 'Location2'
AND t2.Forecast_date = 'Date2'

你可能会在逻辑上争论,它是一样的,它应该没关系 - 你是对的。但话说回来,MySQL的优化器并不是很聪明,并且总是存在错误的可能性,特别是对于没有经常使用的功能。我认为这是一个特色。所以我至少会尝试解析并查看这些替代符号是否被评估相同。

但是BenoKrapo指出,做这样的事情会不容易:

SELECT Title, Variables 
FROM   MyTABLE
WHERE  Location = 'Location1' AND Date = 'Date1' 
OR     Location = 'Location2' AND Date = 'Date2'
GROUP BY Title, Variables
HAVING COUNT(*) >= 2

编辑:我将HAVING COUNT(*) = 2更改为HAVING COUNT(*) >= 2。见评论(再次感谢,BenoKrapo)

编辑:发布此答案后的几天,我发现Facebook的MySQL架构师Mark Callaghan的这篇文章:http://www.facebook.com/note.php?note_id=243134480932 从本质上讲,他描述了由于MySQL优化器错误,类似但不同的“智能”比较如何提供极差的性能。所以我的观点是,当你受苦时尝试不用语法,你可能遇到了一个错误。

答案 1 :(得分:2)

是。根据针对所涉及的表运行的查询创建适当的索引。

答案 2 :(得分:2)

您可以使用“EXPLAIN”预先添加SQL语句,然后重新运行它,这可能是因为您正在加入的列上缺少索引。

还尝试使用STRAIGHT_JOIN并提及左侧大小较慢的表,右侧较大的表提示MySQL选择第一个表。

答案 3 :(得分:1)

确保您匹配的字段已编入索引。 匹配数值也比字符串快。

但是编写

并不简单
SELECT DISTINCT 
  Title, 
  Variables 
FROM `MyTABLE`
WHERE 
  Location = 'Location1' AND Date = 'Date1' 
  OR
  Location = 'Location2' AND Date = 'Date2'

答案 4 :(得分:1)

这可能有点作弊,但实际上我发现在查询之后在PHP中将两个查询连接在一起更容易。这只能起作用,因为我选择了两个不同的变量。

$query = "SELECT DISTINCT Title, Variables FROM 
MyTABLE WHERE Location='Location1' AND Variable='Variable1'";

$result = mysql_result($query);
while ($row = mysql_array_assoc($result)) {
    $Title = $row['Title'];
    $Variables = $row['Variables'];
    $Array_result1[$Title] = $Variables;
}


$query = "SELECT DISTINCT Title, Variables FROM 
MyTABLE WHERE Location='Location2' AND Variable='Variable2'";

$result = mysql_result($query);
while ($row = mysql_array_assoc($result)) {
    $Title = $row['Title'];
    $Variables = $row['Variables'];
    $Array_result2[$Title] = $Variables;
}

$Array_result = array_intersect($Array_result1, $Array_result2);

我喜欢只使用一个MySQL查询来合并这两个查询的想法,但这要快得多。

答案 5 :(得分:0)

如果没有表格和查询的描述,我们可以提供帮助。

有几件事可以决定加入的速度。

  • 数据库引擎:您使用的是InnoDB还是MyISAM?或者也许还有其他引擎?有些在查找时比其他更快,这会影响连接。
  • 索引:是否已将相应的匹配列编入索引?
  • 分区索引:也许您可以通过索引对表进行分区以使其更快?

另外,请查看EXPLAIN query,它将查看mysql执行它所需的所有步骤。它可以帮助你。

答案 6 :(得分:0)

尝试在where子句中的列上使用复合索引,并尝试将所有其他列放入包含列中的select中,这将节省传统的查找成本。

答案 7 :(得分:0)

我使用union运算符进行了两次单独的连接和组合结果。我及时得到了很好的改善。 SELECT t1.Title, t1.Variables FROM {MyTable的{1}} {MyTable的{1}} {MyTable的{1}} {MyTable的{1}}

确保两个查询的列数相同,每列的数据类型相同。另外,检查select子句的顺序。