子查询

    xiaoxiao2023-10-16  33

    文章目录

    子查询子查询概述独立子查询相关子查询exists谓词派生表MariaDB 对SEMI JOIN的优化

    子查询

    子查询概述

    子查询的优点和限制

    子查询是指在一个select语句中嵌套另一个select语句。 示例:

    select *from t1 where columns = (select columns from t2);

    ‘’’’’’

    在这个示例中,select *from t1是外部查询(outer query),select columns from t2是子查询。一般来说,称子查询嵌套(nested)于外部查询中。实际上也可以将两个或两个以上的子查询进行嵌套。要注意的是,子查询必须包含括号。 通常来讲,使用子查询的好处如下:

    子查询允许结构化的查询,这样就可以把一个查询语句的每个部分隔开。子查询提供了另一种方法来执行有些需要复杂的join和union来实现的操作。在许多人看来,子查询可读性较高,而实际上,这也是子查询的由来。

    一个子查询会返回一个标量(单一值)、一个行、一个列和一个表(一行或多行及一列或多列),这些子查询被称为标量、列、行和表子查询。可返回一个特定种类结果的子查询经常只用于特定的语境中,在后面各节中有说明。子查询可以包括普通select可以包括的任何关键词和子句,如distinct、group by、order by、limit、join、union等。 子查询的限制是其外部必须是以下语句之一:select、insert、update、delete、set或do。还有一个限制是,目前用户不能既在一个子查询中修改一个表,又在用一个表中进行选择,虽然这样的操作可用于普通的delete、insert、replace和updat语句中,但是对子查询不可以同时进行这样操作。

    使用子查询进行比较

    最常见的一种子查询使用方式如下:

    non_subquery_operand comparison_operator (subquery) #示例: ... 'a' = (select column1 from t1)

    comparison_operator可以是以下操作符之一:=、>、<、>=、<=、<>

    使用any、in和some进行子查询

    operand comparison_operator any (subquery) operand in (subquery) operand comparison_operator some (subquery)

    any关键词必须与一个比较操作符一起使用。any关键词的意思是“对于子查询返回的列中的任意数值,如果比较结果为TRUE,则返回TRUE”。

    select s1 from t1 where s1 > any (select s1 from t2);

    假设t1中有一行包含(10),如果表t2包含(20,10),或者表t2为空表,则表达式为false,如果t2包含null,则表达式为unknown。

    关键词in是“=any”的别名。 关键词some是any的别名。

    使用all进行子查询

    operand comparison_operator all (subquery) 关键字all必须与比较操作符一起使用。all的意思是对于子查询返回的列中的所有值,如果比较结果为true,则返回true。

    select s1 from t1 where s1 > all (select s1 from t2);

    假设表t1中有一行包含(10),如果表t2中为(12,null,1),则表达式为false,因为表达式中的12大于10。如果表t2中包含(0,null,1),则表达式为unknown。如果表t2为空表,则结果为true。 not in 是<>all的别名

    独立子查询

    子查询可以按两种方式进行分类,若按照期望的数量,可以将子查询分为标量子查询和多值子查询;若按对外部查询的依赖可以分为独立子查询和相关子查询;标量子查询和多值子查询可以是独立子查询也可以是相关子查询。 标量子查询返回的是单个值或null值。

    但在大多数情况下,MySQL数据库都将独立子查询转换为相关子查询。 比如:

    select ... from t1 where t1.a in (select b from t2); #会被转换成 select ... from t1 where exists (select 1 from t2 where t2.b = t1.a);

    相关子查询

    相关子查询是指引用了外部查询列的子查询,即子查询会对外部查询的每行进行一次计算。

    exists谓词

    exists

    通常exists的输入是一个子查询,并关联到外部查询,但这不是必须的。根据子查询是否返回行,该谓词返回true或false。与其他谓词和逻辑表达式不同的是,无论输入子查询是否返回行,exists都不会返回unknown,如果子查询的过滤器为某行返回unknown,则表示该行不返回,因此,这个unknown被认为是false。

    select customerid,companyname from customers as A where country = 'spain' and exists (select *from orders as B where A.customerid = B.customerid)

    not exists

    exists与in的一个小区别体现在对三值逻辑的判断上,exists总是返回true或false,而对于in,除了true、false值外,还有可能对null值返回unknown。但是在过滤器中,unknown的处理方式与false相同,因此使用in与使用exists一样,SQL优化器会选择相同的执行计划。 但是输入列表中包含null值时,not exists和not in之间的差异就表现得非常明显了。输入列表中包含null值时,in总是返回true和unknown,因此not in总是返回not true和not unknown,即false和unknown。

    mysql> select 'a' not in ('a','b',null); 0

    派生表

    派生表又被称为表子查询,与其他表一样出现在from的子句中,但是是从子查询派生出的虚拟表中产生的,派生表的使用形式一般如下:

    from (subquery expression) as derived_table_alias

    目前派生表在使用上有以下规则:

    列的名称是唯一的。在某些情况下不支持limit。

    在派生表中,列的名称必须是唯一的,而在一般SQL语句中并没有这样的强制规定,例如:

    select 'c' as a,'b' as a;#允许 select *from (select 'c' as a,'b' as a) as T;#不允许

    注意,派生表示完全的虚拟表,并没有也不可能被物理地具体化,因此优化器不清楚派生表的信息。

    MariaDB 对SEMI JOIN的优化

    Table Pullout优化Duplicate Weedout优化Materialization优化
    最新回复(0)