提高两个大型表的MySQL连接速度

提高两个大型表的MySQL连接速度,mysql,Mysql,我必须在MySQL查询中连接到大型表,这需要非常长的时间——大约180秒。有没有优化合并的技巧 我的表有10个字段。我在查询中只使用了4-所有字符串。表有大约600000行,结果应该有大约50行 使用的四行是:标题、变量、位置、日期 我的问题是: SELECT DISTINCT t1.Title, t1.Variables FROM `MyTABLE` t1 JOIN `MyTABLE` t2 USING (Title, Variables) WHERE (t1.Location, t1

我必须在MySQL查询中连接到大型表,这需要非常长的时间——大约180秒。有没有优化合并的技巧

我的表有10个字段。我在查询中只使用了4-所有字符串。表有大约600000行,结果应该有大约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')

对。根据针对相关表运行的查询创建适当的索引。

确保对匹配的字段进行索引。 匹配数值也比字符串更快

但如果只是写,不是更简单吗

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

您是否可以在SQL语句前面加上“EXPLAIN”,然后重新运行它,这可能是因为要连接的列缺少索引


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

如果没有表和查询的描述,我们几乎无法提供帮助

有几种因素可以决定连接的速度

  • 数据库引擎:您使用的是InnoDB还是MyISAM?或者其他引擎?有些查找速度比其他查找速度快,这会影响连接
  • 索引:是否对相应的匹配列进行了索引
  • 分区索引:也许您可以按索引对表进行分区以使其更快

另外,查看
EXPLAIN query
,它将查看mysql执行查询所采取的所有步骤。它可以极大地帮助您。

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

正如其他人指出的,您需要适当的索引。对于此特定查询,您可以受益于以下索引:

Location,Date
)或(
Date,Location
)(用于
WHERE
子句) 及 (
Title,Variables
)或(
Variables,Title
)(对于
join
条件,
ON
子句)

确切地知道location、Date、Title和Variables列的大小(即数据类型)会很有帮助,因为大索引可能比小索引慢

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

USING (Title,  Variables) 
也许可以,但我一定会检查一下

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

你的行为和你期望的一样。因此,我肯定会在上面运行
EXPLAIN
,并将输出与“常规”老式比较进行比较,如下所示:

    t1.Location      = 'Location1'
AND t1.Date          = 'Date1'
AND t2.Location      = 'Location2'
AND t2.Forecast_date = 'Date2'
你可能会争辩说,从逻辑上讲,这是一样的,也不重要——你是对的。但话说回来,MySQL的优化器不是很聪明,而且总是有可能出现bug,特别是那些没有被大量使用的特性。我认为这就是这样一个特点。因此,我至少会尝试解释一下,看看这些替代符号的计算结果是否相同

但贝诺克拉波指出,像这样做不是更容易吗:

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那里找到了这篇帖子:
本质上,他描述了类似但不同的“智能”比较是如何由于MySQL优化器错误而带来糟糕的性能的。所以我的观点是,当你遇到困难时,试着解开你的语法,你可能碰到了一个bug。

这可能有点作弊,但我发现在查询之后,用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查询来合并两个查询的想法,但这要快得多。

我使用union操作符进行了两个单独的连接并合并了结果。我在时间上有了很大的进步。
MyTABLE

t1 JOIN
MyTABLE
t2on(t1.Location,t1.Date)=('Location1','Date1')
联合
从
MyTABLE

t1 JOIN
MyTABLE
t2on(t2.Location,t2.Date)=('Location2','Date2')


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

对于初学者,在查询之前使用索引suse“EXPLAIN”生成MySQL将使用的查询计划,这将有助于调查。在我的查询中,我已经在WHERE逻辑中使用的字段上建立了索引。还有什么我能做的吗?阅读EXPLAIN的输出,并在此基础上添加索引。另外,看看哪个表更小(这很幼稚,但仍然如此),然后使用直接连接告诉MySQL按顺序(从左到右)读取表,例如:EXPLAIN从tb2直接连接tb1中选择tb1.X,其中。。。。此外,默认情况下会发生内部联接(笛卡尔积),这可能是您想要的,但您可能会看到是否可以有外部联接。不过,他使用的是自联接。根据定义,它们的大小完全相同。至于内部连接是笛卡尔积:这是胡说八道。如果您有一个合适的索引可以用来解析连接操作(在本例中,一个具有(Title,Variables))MySQL的索引肯定不会计算笛卡尔积,但它将使用嵌套循环连接。最后,一个外部连接很可能会让事情变得更糟。几乎…你必须确保有两行返回…但事实上我监督了这一点。在我的回复中向你推荐。谢谢你的报价。事实上,我错过了来自连接的基数约束。但是Having count(*)应该大于或等于2,而不是等于。
$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);