我来自Postgres背景并尝试将我的应用程序转换为MySQL。我有一个查询在Postgres上非常快,在MySQL上非常慢。在做了一些分析之后,我确定了速度差异剧烈的一个原因是嵌套查询。以下伪查询在Postgres上花费170毫秒,在MySQL上花费5.5秒。
SELECT * FROM (
SELECT id FROM a INNER JOIN b
) AS first LIMIT 10
在MySQL和Postgres上,以下查询的速度相同(小于10毫秒)
SELECT id FROM a INNER JOIN b LIMIT 10
我在两个数据库上都有完全相同的表,索引和数据,所以我真的不知道为什么这么慢。
非常感谢任何见解。
由于
修改
以下是我需要这样做的一个具体示例。我需要得到最大值的总和。为了做到这一点,我需要一个子选择,如下面的查询所示。
SELECT SUM(a) AS a
FROM (
SELECT table2.b, MAX(table1.a) AS a
FROM table1
INNER JOIN table2 ON table2.abc_id = table1.abc_id
AND table1.read_datetime >= table2.issuance_datetime
AND table1.read_datetime < COALESCE(table2.unassignment_datetime, DATE('9999-01-01'))
WHERE table1.read_datetime BETWEEN '2012-01-01 10:30:01' AND '2013-07-18 03:03:42' AND table2.c = 0
GROUP BY table2.id, b
) AS first
GROUP BY b
LIMIT 10
同样,这个查询在MySQL上需要14秒,在Postgres上需要238毫秒。以下是MySQL解释的输出:
id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,PRIMARY,<derived2>,ALL,\N,\N,\N,\N,25584,Using temporary; Using filesort
2,DERIVED,table2,index,PRIMARY,index_table2_on_b,index_table2_on_d,index_table2_on_issuance_datetime,index_table2_on_unassignment_datetime,index_table2_on_e,PRIMARY,4,\N,25584,Using where
2,DERIVED,tz,ref,index_table1_on_d,index_table1_on_read_datetime,index_table1_on_d_and_read_datetime,index_table1_on_4,4,db.table2.dosimeter_id,1,Using where
答案 0 :(得分:2)
Jon,回答你的评论,这是一个例子:
drop table if exists temp_preliminary_table;
create temporary table temp_preliminary_table
SELECT table2.b, MAX(table1.a) AS a
FROM table1
INNER JOIN table2 ON table2.abc_id = table1.abc_id
AND table1.read_datetime >= table2.issuance_datetime
AND table1.read_datetime < COALESCE(table2.unassignment_datetime, DATE('9999-01-01'))
WHERE table1.read_datetime BETWEEN '2012-01-01 10:30:01' AND '2013-07-18 03:03:42' AND table2.c = 0
GROUP BY table2.id, b;
-- I suggest you add indexes to this temp table
alter table temp_preliminary_table
add index idx_b(b); -- Add as many indexes as you need
-- Now perform your query on this temp_table
SELECT SUM(a) AS a
FROM temp_preliminary_table
GROUP BY b
LIMIT 10;
这只是一个示例,分三步拆分您的查询。
您需要记住,MySQL中的临时表仅对创建它们的连接可见,因此任何其他连接都不会看到由另一个连接创建的临时表(无论好坏)。
这种“分而治之”的做法让我感到很头疼。我希望它可以帮助你。
答案 1 :(得分:1)
在嵌套查询中,MySQL在应用限制之前执行整个连接,而postgresql足够聪明,可以确定只需要加入任何10个元组。
答案 2 :(得分:0)
如果我错了,请纠正我,但为什么不尝试:
SELECT * FROM INNER JOIN b LIMIT 10;
答案 3 :(得分:0)
鉴于table2.id是主键,这个带有内部查询限制的查询在功能上与你的查询相同,其中限制在外部查询中,这就是Postgresql规划器所发现的。
SELECT table2.b, MAX(table1.a) AS a
FROM table1
INNER JOIN table2 ON table2.abc_id = table1.abc_id
AND table1.read_datetime >= table2.issuance_datetime
AND table1.read_datetime < COALESCE(table2.unassignment_datetime, DATE('9999-01-01'))
WHERE table1.read_datetime BETWEEN '2012-01-01 10:30:01' AND '2013-07-18 03:03:42' AND table2.c = 0
GROUP BY table2.id, b
order by a desc
LIMIT 10