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

 

将外部连接转换为内部连接

优化程序为其访问计划生成左深 (left-deep) 处理树。这一规则的唯一例外是存在右深 (right-deep) 嵌套外部连接表达式的情况。查询执行引擎的用于计算 LEFT OUTER JOIN 或 RIGHT OUTER JOIN 的算法要求,保留的表必须在任何连接策略中先于提供空值的表。因此,只要可能,优化程序就会寻找机会将 LEFT 或 RIGHT 外连接转换为内连接,这是因为内连接是可交换的,它使优化程序在执行连接枚举时具有更大的自由度。

如果以下条件之一为真,则 LEFT 或 RIGHT 外连接会转换为内连接:

当查询引用使用外连接编写的一个或多个视图时,此重写优化可应用于外连接查询。该查询的 WHERE 子句可以包括限制输出的条件,以便从一个或多个表的表达式中排除所有提供空值的行,从而使这种优化适用。

示例 1

对于下面的查询,针对 SalesOrderItems 表的每一行,均恰好存在与 Products 表匹配的一行,因为 ProductID 列声明为非 NULL,并且 SalesOrderItems 表具有以下外键: "FK_ProductID_ID" ("ProductID") REFERENCING "Products" ("ID").

以下 SELECT 语句显示执行重写优化后如何重写查询:

SELECT * FROM SalesOrderItems s LEFT OUTER JOIN Products p ON (p.ID = s.ProductID);
SELECT * FROM SalesOrderItems s JOIN Products p ON (p.ID = s.ProductID);
示例 2

以下查询列出产品及其数量较大的相应订单;LEFT OUTER JOIN 确保列出所有产品,即使产品没有订单:

SELECT *
FROM Products p KEY LEFT OUTER JOIN SalesOrderItems s
WHERE s.Quantity > 15;

该查询的问题在于,由于谓语 s.Quantity > 15 将在 s.Quantity 为 NULL 的情况下被解释为 FALSE,因此 WHERE 子句中的谓语将从结果中排除所有没有订单的产品。该查询在语义上等效于:

SELECT *
FROM Products p KEY JOIN SalesOrderItems s
WHERE s.Quantity > 15;

这种重写形式即为数据库服务器优化的查询。

在此示例中,该查询的编写几乎毫无疑问地存在错误;它应该改为:

SELECT *
FROM Products p
    KEY LEFT OUTER JOIN SalesOrderItems s
          ON s.Quantity > 15;

这样,数量的测试就是外连接条件的一部分。您可以将一些没有订单的新产品插入 Products 表中,然后再次执行这两个查询,这样就可以发现它们的区别。

INSERT INTO Products
SELECT ID + 10, Name, Description,
        'Extra large', Color, 50, UnitPrice, Photo
FROM Products
WHERE Name = 'Tee Shirt';