Database Subquery
1. 子查询定义
Any sub-query block in a query statement may be called a subquery; however, we use the term subquery for a sub-query block that appears in the WHERE, SELECT and HAVING clauses. Some Oracle documentation uses the term "nested subquery" for what we refer to as a subquery. A sub-query block that appears in the FROM clause is called a view or derived table.
任何在查询表述中的子查询块都可以称为子查询。一般来说,我们将出现在WHERE,SELECT,HAVING语法中的子查询块称作subquery(也可以叫做nested subquery),将出现在FROM语法中的子查询块叫做inline view或derived table。
There are many ways to classify a subquery. The main categorization comes from the way a subquery is used in SQL statements. A WHERE clause subquery belongs to one of the following types: SINGLE-ROW, EXISTS, NOT EXISTS, ANY, or ALL. A single-row subquery must return at most one row, whereas the other types of subquery can return zero or more rows.
ANY and ALL subqueries are used with relational comparison operators: =, >,>=, <, <=, and <>. In SQL, the set operator IN is used as a shorthand for =ANY and the set operator NOT IN is used as a shorthand for <>ALL.
对子查询分类的主要方式是根据子查询在SQL中的使用方式来进行划分的。一个WHERE语法中的子查询可以划分为SINGLE-ROW,EXISTS,NOT EXISTS,ANY,ALL。其中SINGLE-ROW子查询最多返回一行数据,其他类型可以返回0行或者多行。
ANY和ALL子查询是与关系比较符=,>,>=,<,<=,<>一块使用的。在SQL语法中,集合运算符IN是=ANY的缩写;NOT IN是<>ALL的缩写。
SELECT C.cust_last_name, C.country_id FROM customers C WHERE EXISTS (SELECT 1 FROM sales S WHERE S.quantity_sold > 1000 and S.cust_id = C.cust_id);
如果出现在子查询中的某个列来自于某个不是该子查询定义的表,那么就可以把这个列叫做关联列(correlated column)。判断条件S.cust_id = C.cust_id叫做关联条件(correlating condition或correlated predicate)。
2. Subquery Unnesting
Subquery unnesting is an optimization that converts a subquery into a join in the outer query and allows the optimizer to consider subquery table(s) during access path, join method, and join order selection. Unnesting either merges the subquery into the body of the outer query or turns it into an inline view.
子查询去嵌套化是将嵌套子查询转换为外层查询的一个join表,以此来使得优化器在考虑子查询表的访问方式、join方法(nested-loop,hash,sort-merge三种)、join顺序的时候有更多的选择。子查询去嵌套化要么将子查询合并到外层查询的查询体中,要么将子查询转换为inline view。
2.1 Validity of Unnesting
子查询在去嵌套化之前,需要经过一系列的合法性检查,因为去嵌套化不是在任何情形下都能保证同等的语义。以下是部分重要的不合法去嵌套化规则:
- 子查询不是和直接父查询产生关联。比如子查询Q3包含在外层查询Q2(Q3的父查询)中,Q2包含在外层查询Q1(Q2的父查询)中,Q3与Q1中的表有关联。
- 关联子查询是Group-by查询。在这种情况下,去嵌套化意味着在Group-by之后再做join,改变这两个操作的顺序并不总是合法的。
- 关联条件没有很好的排布。比如,在判断条件的两边都包含local column和correlated column的混合,子查询需要生成内联视图,但是像这种类型的判断条件比较不容易将视图的列和外表的列分开。
- 对于隔离的子查询,关联条件中的外表列不相同。