MySQL嵌套查询速度

时间:2013-07-23 19:46:10

标签: mysql performance postgresql

我来自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

4 个答案:

答案 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