Mariadb(MySQL):使用子查询

时间:2018-01-24 10:25:44

标签: mysql sql mariadb

原始sql:

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

它会以1s的形式返回结果, 但是当使用子查询时,它变得非常慢(几分钟):

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

当我使用explain执行时,它还有一行:

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

MySQL版本:5.6

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

2 个答案:

答案 0 :(得分:1)

第一种方法,加入,速度要快得多。第二,将对每一行执行查询。有些数据库会将嵌套查询优化为连接。

Join vs. sub-query

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

我发现使用虚拟桌面&#39;而不是ROW子查询在我的桌子上很多更快。行子查询似乎没有得到优化,其中通过“虚拟表”进行连接。优化。

以下是查询和&#39; EXPLAIN&#39;返回用于教育目的。

- 使用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)

我无法从上面得到任何结果(花费太长时间) - 也许极限条款没有开始?

- 使用联合虚拟表进行查询

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)

以上回报...... 10结果约1秒 100结果约1秒 1000结果约1.5秒 全套(20437)约2秒

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

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

答案 1 :(得分:0)

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

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

以前对性能很糟糕,因为它没有ON的索引。在5.6中,优化器抓住了它的头并确定了什么索引可能是好的,然后创建这样的(参见&#34;自动键&#34;在EXPLAIN中)来帮助。

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

另一种情况会让很多人感到困扰,他们会问:&#34;当我删除ORDER BY时,为什么运行速度会快得多?&#34;:

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

要添加到拼图中,某些变体的运行速度不会更快。这里的关键因素是是否有一个复合索引可以处理WHERE ORDER BY所有