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 的用法 » 查询处理 » 查询优化与执行 » 语义查询转换

 

将子查询重写为 EXISTS 谓语

作为 SQL Anywhere 设计基础的假定要求其节约内存并且在缺省情况下尽可能快地返回游标的前几项结果。为了与这些目标一致,SQL Anywhere 会在重写后语义正确的情况下,将所有集合操作子查询(如 IN、ANY 或 SOME 谓语)重写为 EXISTS 或 NOT EXISTS 谓语。这样,SQL Anywhere 就可以避免创建不必要的工作表,并且可以更容易地找到用于对表进行访问的合适索引。

不相关和相关子查询

不相关子查询是这样的子查询:其不包含对查询中其它更高级别部分中的表的显式引用。

下面是一个包含不相关子查询的普通查询。它选择在 2001 年 1 月 1 日没有下订单的所有客户的相关信息。

SELECT *
FROM Customers c
WHERE c.ID NOT IN
   (  SELECT o.CustomerID
      FROM SalesOrders o
      WHERE o.OrderDate = '2001-01-01' );

计算此查询的一种可能方式是先为 SalesOrder 表中所有在 2001 年 1 月 1 日下订单的客户创建一个工作表,然后查询 Customers 表并为该工作表列出的每位客户抽取一行。

但是,SQL Anywhere 会避免将结果实现为工作表。它还将优先考虑最快返回前几行结果的计划。因此,优化程序会使用 NOT EXISTS 谓语重写此类查询。这样,子查询就变成相关子查询了:现在,子查询包含对 Customers 表的 ID 列的显式外部引用。

SELECT *
FROM Customers c
WHERE NOT EXISTS
   (  SELECT *
      FROM SalesOrders o
      WHERE o.OrderDate = '2000-01-01'
         AND o.CustomerID = c.ID );

该查询在语义上等效于上面的查询,但用这种新语法表示时,会显示出多个优点:

  1. 优化程序可以选择使用 SalesOrders 表的 CustomerID 属性或 OrderDate 属性上的索引。然而,在 SQL Anywhere 示例数据库中,只有 ID 和 CustomerID 列为索引列。

  2. 优化程序可以选择计算子查询,而不将中间结果实现为工作表。

  3. 数据库服务器可以在执行过程中高速缓存相关子查询的结果。这样就可以对外部引用 c.ID 的相同值重新使用此谓语的先前计算值。对于上述查询,高速缓存不起作用,因为客户标识号在 Customers 表中是唯一的。因此,始终使用外部引用 c.ID 的不同值来计算子查询。

有关子查询高速缓存的详细信息,请参见子查询和函数高速缓存

另请参见