【问题标题】:Mariadb(MySQL):Query slow when using sub queryMariadb(MySQL):使用子查询时查询慢
【发布时间】:2018-01-24 10:25:44
【问题描述】:

原sql:

select * from A
join B on A.aid = b.aid
...(some join)
limit 0,1000

它会在 1 秒内返回结果, 但是当使用子查询时,它变得非常慢(以分钟计):

select * from
(
select * from A
join B on A.aid = b.aid
...(some join)
) tmp
limit 0,1000

当我用解释执行时,它有一个额外的行:

select_type: PRIMARY
table: <derived2>
type: ALL
possible_keys: null
key_len: null
rows: 1504940
Extra: Using temporary; Using filesort

MySQL版本:5.6

ps。我需要以子查询的方式使用查询,因为它发生在另一个应用程序读取的视图中。

【问题讨论】:

    标签: mysql sql mariadb


    【解决方案1】:

    使用连接的第一种方法要快得多。其次,将为每一行执行查询。不过,一些数据库将嵌套查询优化为连接。

    Join vs. sub-query

    文章MySQL performance: INNER JOIN vs. sub-select

    我发现在我的表上使用“虚拟表”而不是 ROW 子查询要快得多。似乎行子查询没有优化,“虚拟表”上的连接被优化。

    以下是用于教育目的的查询和返回的“EXPLAIN”。

    -- 使用 ROW 子查询查询

    EXPLAIN
    SELECT 
    * 
    FROM 
    region
    WHERE 
    ROW (PDB,CHAIN) IN (
    SELECT 
    region.PDB, 
    region.CHAIN
    FROM 
    region LEFT JOIN split_domain USING (SUNID)
    WHERE
    split_domain.SUNID IS NULL
    GROUP BY
    PDB, CHAIN
    HAVING
    COUNT(*)>1
    )
    LIMIT 
    10
    ;
    
    +----+--------------------+--------------+--------+---------------+---------+---------+------------------------+-------+--------------------------------------+
    | id | select_type        | table        | type   | possible_keys | key     | key_len | ref                    | rows  | Extra                                |
    +----+--------------------+--------------+--------+---------------+---------+---------+------------------------+-------+--------------------------------------+
    |  1 | PRIMARY            | region       | ALL    | NULL          | NULL    |    NULL | NULL                   | 57362 | Using where                          |
    |  2 | DEPENDENT SUBQUERY | region       | ALL    | NULL          | NULL    |    NULL | NULL                   | 57362 | Using temporary; Using filesort      |
    |  2 | DEPENDENT SUBQUERY | split_domain | eq_ref | PRIMARY       | PRIMARY |       3 | scop_1_65.region.SUNID |     1 | Using where; Using index; Not exists |
    +----+--------------------+--------------+--------+---------------+---------+---------+------------------------+-------+--------------------------------------+
    3 rows in set (0.04 sec)
    

    我无法从上述内容中得到任何结果(花费的时间太长)- 也许限制条款没有生效?

    -- 使用joined virtual table查询

    EXPLAIN
    SELECT 
    * 
    FROM 
    region
    INNER JOIN (
    SELECT 
    region.PDB, 
    region.CHAIN
    FROM 
    region LEFT JOIN split_domain USING (SUNID)
    WHERE
    split_domain.SUNID IS NULL
    GROUP BY
    PDB, CHAIN
    HAVING
    COUNT(*)>1
    ) AS x
    ON
    region.PDB = x.PDB 
    AND
    region.CHAIN = x.CHAIN
    LIMIT 
    10
    ;
    
    +----+-------------+--------------+--------+---------------------+-----------+---------+------------------------+-------+--------------------------------------+
    | id | select_type | table        | type   | possible_keys       | key       | key_len | ref                    | rows  | Extra                                |
    +----+-------------+--------------+--------+---------------------+-----------+---------+------------------------+-------+--------------------------------------+
    |  1 | PRIMARY     | <derived2>   | ALL    | NULL                | NULL      |    NULL | NULL                   |  8624 |                                      |
    |  1 | PRIMARY     | region       | ref    | PDB,CHAIN,pdb_chain | pdb_chain |       5 | x.PDB,x.CHAIN          |     1 |                                      |
    |  2 | DERIVED     | region       | ALL    | NULL                | NULL      |    NULL | NULL                   | 57362 | Using temporary; Using filesort      |
    |  2 | DERIVED     | split_domain | eq_ref | PRIMARY             | PRIMARY   |       3 | scop_1_65.region.SUNID |     1 | Using where; Using index; Not exists |
    +----+-------------+--------------+--------+---------------------+-----------+---------+------------------------+-------+--------------------------------------+
    4 rows in set (1.02 sec)
    

    以上返回... 大约 1 秒内 10 个结果 大约 1 秒内 100 个结果 1000 个结果大约需要 1.5 秒 2秒左右完成(20437)

    前一个查询不会在 5 分钟内返回(即使限制为 10)。

    我希望这对任何设计(或试图优化)复杂子查询的人有用,并且数据的精确细节对于传达此处显示的结果不是必需的。

    【讨论】:

      【解决方案2】:

      IN ( SELECT ... ) 因优化不佳而臭名昭著。在最近的版本中,它变得越来越好。

      FROM ( SELECT ... ) 
      JOIN ( SELECT ... ) ON ...
      

      过去性能很差,因为它没有ON 的索引。在 5.6 中,优化器摸不着头脑并决定什么索引可能是好的,然后创建这样的索引(参见 EXPLAIN 中的“自动键”)来提供帮助。

      使用SELECT ( ... ) LIMIT ...(如您的示例)包装查询需要完成内部查询,并构建一个可能很大(1504940 行?)的临时表。所有这些剥离 1000 行之前。当然优化器可能能够识别该模式,但我认为“既然外部 SELECT 没有添加任何有用的东西,为什么要这样做?”。那么优化人员为什么要浪费时间优化这些呢。

      另一个困扰很多人的情况,他们问“为什么我删除ORDER BY后它运行得这么快?”:

      SELECT ...
          ORDER BY ...
          LIMIT ...
      

      更令人困惑的是,某些变体的运行速度并不快。这里的关键因素是是否有一个复合索引可以处理所有WHEREORDER BY

      【讨论】:

      • 外部SELECT 被另一个应用程序读取的视图使用,该应用程序只识别表(或视图)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-23
      • 2012-12-15
      • 2018-08-19
      • 2019-09-29
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      相关资源
      最近更新 更多