子查询执行时间:本地主机 = 2 秒/服务器 = 98+ 秒
SubQuery execution time : localhost = 2 seconds / server = 98+ seconds
我可以请求一些关于子查询的帮助吗?
当我 运行 在本地 XAMP mySQL 数据库上查询时,查询需要 2 秒才能完成。然而,在我的网络服务器上使用相同的数据库,相同的查询需要 98 秒加上 return 相同的结果。
当我说相同时,记录是从 HeidiSQL 导出和插入的,所以我确定数据集没问题。数据库 DDL,也是从 HeidiSQL 创建的,但我猜我可能错过了创建数据库的精确副本的一些关键步骤。
我也使用 Heidi 的导出功能创建了一个 fiddle。尽管我应该指出查询在 fiddle 上的执行速度比现实生活中快得多。
我正在执行的查询是……
SELECT d.dayID, d.dayDate, d.item, w.Idx, w.word, w.wordID, w.asize, w.span
FROM words w
INNER JOIN days d ON w.dayID = d.dayID
WHERE w.word IN (
SELECT w1.word
FROM words w1
INNER JOIN days d1 ON w1.dayID = d1.dayID
WHERE d1.dayDate = '2012-02-27'
AND d1.Item = 'a'
AND w1.span = 24
AND w1.asize = 6
)
AND w.span = 24
AND w.asize = 6
GROUP BY d.dayDate, d.item
Order by d.dayDate, w.asize DESC, w.Idx;
它的目的是 return 天数和 table 天的项目列表,其中单词 table 中有重复的单词。
上面的查询会 return 结果类似于…
dayID dayDate item Idx word wordID asize span
1974 2012-11-22 B 3 item b 1367339 6 24
4370 2015-03-10 B 1 item b 3024989 6 24
使用 phpMyAdmin,我为单词字段添加了一个索引,这使时间从 98 秒减少到 46 秒。但是,当然,46 秒也太长了吧?
其他需要注意的地方,table字在现实中包含了大约300万条记录。其他查询(非子查询) 运行 一眨眼。我想我只是不擅长子查询。
请问谁能给我指出正确的方向,以确定为什么在服务器上执行查询需要这么长时间?
作为一般规则,在处理复杂或大的子查询时应避免使用 IN
。这是因为 IN
条件必须为数据源中的每一行 计算一次 。因此,如果您的数据源有 1000 行并且 IN
条件有 1000 个元素,则执行将如下所示:
- 对于第 1 行,运行 子查询并检查该值是否在子查询结果中
- 对于第 2 行,运行 子查询并检查该值是否在子查询结果中
- ...
- 等等
(不用说,如果子查询很复杂,那将是一个巨大的性能损失)
因此,您可以采取一些措施来加快速度:
- 不使用
IN
,而是使用 JOIN
- 不使用子查询,而是创建一个临时的 table,添加适当的索引,然后使用
JOIN
我将处理选项 2。如果需要,您可以用完整的子查询替换临时 table。
那么,让我们创建一个临时文件 table:
drop table if exists temp_words;
create temporary table temp_words
SELECT w1.word
FROM words w1
INNER JOIN days d1 ON w1.dayID = d1.dayID
WHERE d1.dayDate = '2012-02-27'
AND d1.Item = 'a'
AND w1.span = 24
AND w1.asize = 6;
alter table temp_words
add index w(word);
现在,不再使用 IN
,而是使用 JOIN
:
SELECT d.dayID, d.dayDate, d.item, w.Idx, w.word, w.wordID, w.asize, w.span
FROM words w
INNER JOIN days d
ON w.dayID = d.dayID
INNER JOIN temp_words as w1 -- Replace 'temp_words' with your subquery
-- if you don't want to use a temp table
ON w.word = w1.word
WHERE w.span = 24
AND w.asize = 6
GROUP BY d.dayDate, d.item
Order by d.dayDate, w.asize DESC, w.Idx;
我想您会发现使用 JOIN
而不是 IN
会大大提高性能。
关于温度你必须知道的事情 tables:
- 它们的行为与普通 tables 一样,因此您可以像使用其他任何东西一样使用它们 table:您可以插入、更新和删除行,可以添加索引或更改以您想要(或需要)的任何方式使用它们,如果它们不再有用,您可以丢弃它们。
- 它们仅对创建它们的连接可见。这意味着两个连接可以创建具有相同名称(但可能具有不同结构)的临时 table,并且每个连接都可以使用它自己的 "copy".
- 一旦连接关闭或终止,它们就会被删除,因此如果您关闭或终止连接,您将不得不重新创建它们。
我可以请求一些关于子查询的帮助吗?
当我 运行 在本地 XAMP mySQL 数据库上查询时,查询需要 2 秒才能完成。然而,在我的网络服务器上使用相同的数据库,相同的查询需要 98 秒加上 return 相同的结果。
当我说相同时,记录是从 HeidiSQL 导出和插入的,所以我确定数据集没问题。数据库 DDL,也是从 HeidiSQL 创建的,但我猜我可能错过了创建数据库的精确副本的一些关键步骤。
我也使用 Heidi 的导出功能创建了一个 fiddle。尽管我应该指出查询在 fiddle 上的执行速度比现实生活中快得多。
我正在执行的查询是……
SELECT d.dayID, d.dayDate, d.item, w.Idx, w.word, w.wordID, w.asize, w.span
FROM words w
INNER JOIN days d ON w.dayID = d.dayID
WHERE w.word IN (
SELECT w1.word
FROM words w1
INNER JOIN days d1 ON w1.dayID = d1.dayID
WHERE d1.dayDate = '2012-02-27'
AND d1.Item = 'a'
AND w1.span = 24
AND w1.asize = 6
)
AND w.span = 24
AND w.asize = 6
GROUP BY d.dayDate, d.item
Order by d.dayDate, w.asize DESC, w.Idx;
它的目的是 return 天数和 table 天的项目列表,其中单词 table 中有重复的单词。
上面的查询会 return 结果类似于…
dayID dayDate item Idx word wordID asize span
1974 2012-11-22 B 3 item b 1367339 6 24
4370 2015-03-10 B 1 item b 3024989 6 24
使用 phpMyAdmin,我为单词字段添加了一个索引,这使时间从 98 秒减少到 46 秒。但是,当然,46 秒也太长了吧?
其他需要注意的地方,table字在现实中包含了大约300万条记录。其他查询(非子查询) 运行 一眨眼。我想我只是不擅长子查询。
请问谁能给我指出正确的方向,以确定为什么在服务器上执行查询需要这么长时间?
作为一般规则,在处理复杂或大的子查询时应避免使用 IN
。这是因为 IN
条件必须为数据源中的每一行 计算一次 。因此,如果您的数据源有 1000 行并且 IN
条件有 1000 个元素,则执行将如下所示:
- 对于第 1 行,运行 子查询并检查该值是否在子查询结果中
- 对于第 2 行,运行 子查询并检查该值是否在子查询结果中
- ...
- 等等
(不用说,如果子查询很复杂,那将是一个巨大的性能损失)
因此,您可以采取一些措施来加快速度:
- 不使用
IN
,而是使用JOIN
- 不使用子查询,而是创建一个临时的 table,添加适当的索引,然后使用
JOIN
我将处理选项 2。如果需要,您可以用完整的子查询替换临时 table。
那么,让我们创建一个临时文件 table:
drop table if exists temp_words;
create temporary table temp_words
SELECT w1.word
FROM words w1
INNER JOIN days d1 ON w1.dayID = d1.dayID
WHERE d1.dayDate = '2012-02-27'
AND d1.Item = 'a'
AND w1.span = 24
AND w1.asize = 6;
alter table temp_words
add index w(word);
现在,不再使用 IN
,而是使用 JOIN
:
SELECT d.dayID, d.dayDate, d.item, w.Idx, w.word, w.wordID, w.asize, w.span
FROM words w
INNER JOIN days d
ON w.dayID = d.dayID
INNER JOIN temp_words as w1 -- Replace 'temp_words' with your subquery
-- if you don't want to use a temp table
ON w.word = w1.word
WHERE w.span = 24
AND w.asize = 6
GROUP BY d.dayDate, d.item
Order by d.dayDate, w.asize DESC, w.Idx;
我想您会发现使用 JOIN
而不是 IN
会大大提高性能。
关于温度你必须知道的事情 tables:
- 它们的行为与普通 tables 一样,因此您可以像使用其他任何东西一样使用它们 table:您可以插入、更新和删除行,可以添加索引或更改以您想要(或需要)的任何方式使用它们,如果它们不再有用,您可以丢弃它们。
- 它们仅对创建它们的连接可见。这意味着两个连接可以创建具有相同名称(但可能具有不同结构)的临时 table,并且每个连接都可以使用它自己的 "copy".
- 一旦连接关闭或终止,它们就会被删除,因此如果您关闭或终止连接,您将不得不重新创建它们。