原始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。我需要以子查询方式使用查询,因为它发生在另一个应用程序读取的视图中。
答案 0 :(得分:1)
第一种方法,加入,速度要快得多。第二,将对每一行执行查询。有些数据库会将嵌套查询优化为连接。
文章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
的所有。