提高两个大型表的MySQL连接速度
我必须在MySQL查询中连接到大型表,这需要非常长的时间——大约180秒。有没有优化合并的技巧 我的表有10个字段。我在查询中只使用了4-所有字符串。表有大约600000行,结果应该有大约50行 使用的四行是:标题、变量、位置、日期 我的问题是:提高两个大型表的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
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
MyTABLEt2on(t1.Location,t1.Date)=('Location1','Date1')
联合
从
MyTABLE
t1 JOIN
MyTABLEt2on(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);