Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (中文) » SQL Anywhere 服务器 - SQL 的用法 » 查询处理 » 查询优化与执行 » 语义查询转换

 

取消子查询嵌套

利用 SQL 语言提供的方便语法,可以将语句表达为嵌套查询。但是,由于 SQL Anywhere 可以更为有效地利用子查询的 WHERE 子句中的高选择性条件,因此将嵌套查询重写为连接通常会提高执行和优化的效率。一般情况下,会始终对 FROM 子句中最多包含一个表的相关子查询(用于 ANY、ALL 和 EXISTS 谓语中)执行取消子查询嵌套。如果根据查询语义可以确定子查询最多返回一行,则不相关子查询或在 FROM 子句中有多个表的子查询将被展平。

示例

对于外部块中的每个行,以下示例中的子查询最多可以匹配一行。由于该子查询最多可以匹配一行,SQL Anywhere 将发现可以将其转换为内连接。

SELECT s.*
FROM SalesOrderItems s
WHERE EXISTS
    ( SELECT *
      FROM Products p
      WHERE s.ProductID = p.ID
         AND p.ID = 300 AND p.Quantity > 20);

转换之后,这一相同语句将使用连接语法在内部表达:

SELECT s.*
FROM Products p JOIN SalesOrderItems s
   ON p.ID = s.ProductID
WHERE p.ID = 300 AND p.Quantity > 20;

p<Products> JNL s<FK_ProductID_ID>

同样,以下查询在子查询中包含一个连接性 EXISTS 谓语。该子查询可以匹配多个行。

SELECT p.*
FROM Products p
WHERE EXISTS
    ( SELECT *
      FROM SalesOrderItems s
      WHERE s.ProductID = p.ID
         AND s.ID = 2001);

SQL Anywhere 在 SELECT 列表中使用 DISTINCT,将该查询转换为内连接。

SELECT DISTINCT p.*
FROM Products p JOIN SalesOrderItems s
   ON p.ID = s.ProductID
WHERE s.ID = 2001;

Work[ DistH[ s<FK_ID_ID> JNL p<Products> ] ]

对于外部块中的每一行,如果该子查询最多可以匹配一行,则 SQL Anywhere 也可以在比较中排除子查询。下面的查询中就存在这种情况。

SELECT *
FROM Products p
WHERE p.ID =
    ( SELECT s.ProductID
      FROM SalesOrderItems s
      WHERE s.ID = 2001
         AND s.LineID = 1 );

SQL Anywhere 以如下方式重写该查询:

SELECT p.*
FROM Products p, SalesOrderItems s
WHERE p.ID = s.ProductID
   AND s.ID = 2001
   AND s.LineID = 1;

s<SalesOrderItems> JNL p<Products>

在执行取消子查询嵌套的重写优化时,会将 DUMMY 表视为一个特殊的表。即使子查询不相关,也始终会在形式为 SELECT expression FROM DUMMY 的子查询上执行子查询展平。