SQL优化--逻辑优化--子查询优化(MySQL)

1)子查询概念:当一个查询是另一个查询的子部分时,称之为子查询(查询语句中嵌套有查询语句)。

子查询出现的位置有:

a)目标列位置:子查询如果位于目标列,则只能是标量子查询,否则数据库可能返回类似“错误:  子查询必须只能返回一个字段”的提示。

b)FROM子句位置:相关子查询出现在FROM子句中,数据库可能返回类似“在FROM子句中的子查询无法参考相同查询级别中的关系”的提示,所以相关子查询不能出现在FROM子句中;非相关子查询出现在FROM子句中,可上拉子查询到父层,在多表连接时统一考虑连接代价然后择优。

c)WHERE子句位置:出现在WHERE子句中的子查询,是一个条件表达式的一部分,而表达式可以分解为操作符和操作数;根据参与运算的不同的数据类型,操作符也不尽相同,如INT型有“>、<、=、<>”等操作,这对子查询均有一定的要求(如INT型的等值操作,要求子查询必须是标量子查询)。另外,子查询出现在WHERE子句中的格式,也有用谓词指定的一些操作,如IN、BETWEEN、EXISTS等。

d)JOIN/ON子句位置:JOIN/ON子句可以拆分为两部分,一是JOIN块类似于FROM子句,二是ON子句块类似于WHERE子句,这两部分都可以出现子查询。子查询的处理方式同FROM子句和WHERE子句。

e)GROUPBY子句位置:目标列必须和GROUPBY关联1。可将子查询写在GROUPBY位置处,但子查询用在GROUPBY处没有实用意义。

f)ORDERBY子句位置:可将子查询写在ORDERBY位置处。但ORDERBY操作是作用在整条SQL语句上的,子查询用在ORDERBY处没有实用意义。

2)子查询的分类

从对象间的关系看:

a)相关子查询。

子查询的执行依赖于外层父查询的一些属性值。子查询因依赖于父查询的参数,当父查询的参数改变时,子查询需要根据新参数值重新执行(查询优化器对相关子查询进行优化有一定意义),如:

SELECT * FROM t1 WHERE col_1 = ANY

(SELECT col_1 FROM t2 WHERE t2.col_2 = t1.col_2);

/* 子查询语句中存在父查询的t1表的col_2列 */

b)非相关子查询。

子查询的执行,不依赖于外层父查询的任何属性值。这样子查询具有独立性,可独自求解,形成一个子查询计划先于外层的查询求解,如:

SELECT * FROM t1 WHERE col_1 = ANY

(SELECT col_1 FROM t2 WHERE t2.col_2 = 10);

//子查询语句中(t2)不存在父查询(t1)的属性

从特定谓词看:

a)[NOT] IN/ALL/ANY/SOME子查询。

语义相近,表示“[取反] 存在/所有/任何/任何”,左面是操作数,右面是子查询,是最常见的子查询类型之一。

b)[NOT] EXISTS子查询。

半连接语义,表示“[取反] 存在”,没有左操作数,右面是子查询,也是最常见的子查询类型之一。

c)其他子查询。

除了上述两种外的所有子查询。

从语句的构成复杂程度看:

a)SPJ子查询。

由选择、连接、投影操作组成的查询。

b)GROUPBY子查询。

SPJ子查询加上分组、聚集操作组成的查询。

c)其他子查询。

GROUPBY子查询中加上其他子句如Top-N 、LIMIT/OFFSET、集合、排序等操作。

后两种子查询有时合称非SPJ子查询。

从结果的角度看:

a)标量子查询。

子查询返回的结果集类型是一个简单值。

b)单行单列子查询。

子查询返回的结果集类型是零条或一条单元组。相似于标量子查询,但可能返回零条元组。

c)多行单列子查询。

子查询返回的结果集类型是多条元组但只有一个简单列。

d)表子查询。

子查询返回的结果集类型是一个表(多行多列)。

3)子查询的优化方法

a)子查询合并(Subquery Coalescing)

在某些条件下(语义等价:两个查询块产生同样的结果集),多个子查询能够合并成一个子查询(合并后还是子查询,以后可以通过其他技术消除掉子查询)。这样可以把多次表扫描、多次连接减少为单次表扫描和单次连接,如:

SELECT * FROM t1 WHERE a1<10 AND (

EXISTS (SELECT a2 FROM t2 WHERE t2.a2<5 AND t2.b2=1) OR

EXISTS (SELECT a2 FROM t2 WHERE t2.a2<5 AND t2.b2=2)

);

可优化为:

SELECT * FROM t1 WHERE a1<10 AND (

EXISTS (SELECT a2 FROM t2 WHERE t2.a2<5 AND
(t2.b2=1 OR t2.b2=2)

/*两个ESISTS子句合并为一个,条件也进行了合并 */

);

b)子查询展开(Subquery Unnesting)

又称子查询反嵌套,又称为子查询上拉。把一些子查询置于外层的父查询中,作为连接关系与外层父查询并列,其实质是把某些子查询重写为等价的多表连接操作(展开后,子查询不存在了,外部查询变成了多表连接)。带来的好处是,有关的访问路径、连接方法和连接顺序可能被有效使用,使得查询语句的层次尽可能的减少。

常见的IN/ANY/SOME/ALL/EXISTS依据情况转换为半连接(SEMI JOIN)、普通类型的子查询消除等情况属于此类,如:

SELECT * FROM t1, (SELECT * FROM t2 WHERE t2.a2 >10)
v_t2

WHERE t1.a1<10 AND v_t2.a2<20;

可优化为:

SELECT * FROM t1, t2 WHERE t1.a1<10 AND t2.a2<20
AND t2.a2 >10;

/* 子查询变为了t1、t2表的连接操作,相当于把t2表从子查询中上拉了一层 */

子查询展开的条件:

a)如果子查询中出现了聚集、GROUPBY、DISTINCT子句,则子查询只能单独求解,不可以上拉到外层。

b)如果子查询只是一个简单格式的(SPJ格式)查询语句,则可以上拉子查询到外层,这样往往能提高查询效率。子查询上拉,讨论的就是这种格式,这也是子查询展开技术处理的范围。

把子查询上拉到上层查询,前提是上拉(展开)后的结果不能带来多余的元组,所以子查询展开需要遵循如下规则:

a)如果上层查询的结果没有重复(即SELECT子句中包含主码),则可以展开其子查询。并且展开后的查询的SELECT子句前应加上DISTINCT标志。

b)如果上层查询的SELECT语句中有DISTINCT标志,可以直接进行子查询展开。

如果内层查询结果没有重复元组,则可以展开。

子查询展开的具体步骤:

a)将子查询和外层查询的FROM子句连接为同一个FROM子句,并且修改相应的运行参数。

b)将子查询的谓词符号进行相应修改(如:“IN”修改为“=”)。

c)将子查询的WHERE条件作为一个整体与外层查询的WHERE条件合并,并用AND条件连接词连接,从而保证新生成的谓词与原旧谓词的上下文意思相同,且成为一个整体。

c)聚集子查询消除(Aggregate Subquery Elimination)

通常,一些系统支持的是标量聚集子查询消除。如:

SELECT * FROM t1 WHERE t1.a1>(SELECT avg(t2.a2) FROM t2);

摘自《数据库查询优化器的艺术》一书

时间: 2024-09-30 16:23:31

SQL优化--逻辑优化--子查询优化(MySQL)的相关文章

SQL优化--逻辑优化--数据库的约束规则与语义优化

1)数据库完整性 ①实体完整性(Entity Integrity):自己 a)一个关系对应现实世界中一个实体集.--ER模型 b)现实世界中的实体具有某种惟一性标识.--主键 c)主关键字是多个属性的组合,则所有主属性均不得取空值.--隐含的索引 ②域完整性(Domain Integrity): 自己的局部 保证数据库字段取值的合理性.属性值应是域中的值,这是关系模式规定了的. 包括: a)检查(CHECK) b)默认值(DEFAULT) c)不为空(NOT NULL) d)可为空(NULL)等

SQL优化--逻辑优化--条件化简

1)查询条件 查询条件概念: SQL查询语句中,对元组进行过滤和连接的表达式,形式上是出现在WHERE/JOIN-ON/HAVING的子句中的表达式. 2)条件化简技术 ①条件下推:把与单个表相关的条件,放到对单表进行扫描的过程中执行. SELECT * FROM A, B WHERE A.a=1 and A.b=B.b; 执行顺序: a)扫描A表,并带有条件A.a=1,把A表作为嵌套循环的外表 b)扫描B表,执行连接操作,并带有过滤条件A.b=B.b 说明:数据库系统都支持条件下推,且无论条件

由一条sql语句想到的子查询优化

摘要:相信大家都使用过子查询,因为使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL操作,比较灵活,我也喜欢用,可最近因为一条包含子查询的select count(*)语句导致点开管理系统的一个功能模块列表时,耗时44几秒,到了不可容忍的地步,定位发现是因为未加索引和用了子查询导致,不加索引导致查询慢好理解,但子查询也会引起查询效率过低吗?没错,所以本文就以这次案例来重新认识下MySQL子查询. 特别说明:本文介绍的是在MySQL5.5.6版本下子查询的案例,5.5.29版本的我也

SQL优化--逻辑优化--视图重写与等价谓词重写

1)视图重写 视图的类型: a)用SPJ格式构造的视图,称为简单视图. CREATE VIEW v1 AS SELECT x, y, z FROM t; b)用非SPJ格式构造的视图(带有GROUPBY等操作),称为复杂视图. CREATE VIEW v2 AS SELECT x, y, z FROM t ORDER BY x; 视图重写: a)查询语句中出现视图对象 b)查询优化后,视图对象消失 c)消失的视图对象的查询语句, 融合到初始查询语句中 MySQL视图重写准则: a)MySQL支持

SQL优化--逻辑优化--非SPJ优化

1)GROUP BY分组转换(MySQL不支持) ①分组操作下移 GROUPBY 操作可能较大幅度减小关系元组的个数,如果能够对某个关系先进行分组操作,然后再进行表之间的连接,很可能提高连接效率.这种优化方式是把分组操作提前执行.下移的含义,是在查询树上,让分组操作尽量靠近叶子结点,使得分组操作的结点低于一些选择操作. ②分组操作上移 如果连接操作能够过滤掉大部分元组,则先进行连接后进行GROUPBY 操作,可能提高分组操作的效率.这种优化方式是把分组操作置后执行.上移的含义,和下移正好相反.

SQL优化--逻辑优化--外连接、嵌套连接与连接消除

1)外连接消除 ①外连接简介 1)LEFT JOIN / LEFT OUTER JOIN:左外连接 左向外连接的结果集包括:LEFT OUTER子句中指定的左表的所有行,而不仅仅是连接列所匹配的行.如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值. 2)RIGHT JOIN / RIGHT  OUTER  JOIN:右外连接 右向外连接是左向外联接的反向连接.将返回右表的所有行.如果右表的某行在左表中没有匹配行,则将为左表返回空值. 3)FULL JOIN /

MySql数据库3【优化2】sql语句的优化

1.SELECT语句优化 1).利用LIMIT 1取得唯一行[控制结果集的行数] 有时,当你要查询一张表是,你知道自己只需要看一行.你可能会去的一条十分独特的记录,或者只是刚好检查了任何存在的记录数,他们都满足了你的WHERE子句.在这种情况下,增加一个LIMIT 1会令你的查询更加有效.这样数据库引擎发现只有1后将停止扫描,而不是去扫描整个表或索引. 2).不要使用BY RAND()命令 这是一个令很多新手程序员会掉进去的陷阱.你可能不知不觉中制造了一个可怕的平静.这个陷阱在你是用BY RAN

mysql基础操作、sql技巧和sql的常见优化

一.常见操作 1.复制表结构create table t2 like t1 复制表数据insert into t2 select * from t1 2.mysql索引 alter table用来创建普通索引.unique索引或primary key索引 alter table t add index index_name(column_list) alter table t add unique(column_list) alter table t add primary key(column

MySQL优化 - 性能分析与查询优化

MySQL优化 - 性能分析与查询优化 优化应贯穿整个产品开发周期中,比如编写复杂SQL时查看执行计划,安装MySQL服务器时尽量合理配置(见过太多完全使用默认配置安装的情况),根据应用负载选择合理的硬件配置等. 1.性能分析 性能分析包含多方面:CPU.Memory.磁盘/网络IO.MySQL服务器本身等. 1.1 操作系统分析 常规的操作系统分析,在Linux中通常包含一些性能监控命令,如top.vmstat.iostat.strace.iptraf等. 1.内存:内存是大项,高查询消耗大量