#
第四十五章 SQL命令 FROM(一) 一个SELECT子句,指定要查询的一个或多个表。 # 大纲 ``` SELECT ... FROM [optimize-option] table-ref [[AS] t-alias][,table-ref [[AS] t-alias]][,...] ``` ## 参数 - `optimize-optio`n - 可选-指定查询优化选项(优化器提示)的单个关键字或由空格分隔的一系列关键字。支持以下关键字:`%ALLINDEX`、`%FIRSTTABLE TABLE TABNAME`、`%FULL`、`%IGNOREINDEX NAME`、`%INORDER`、`%NOFLATTEN`、`%NOMERGE`、`%NOREDUCE`、`%NOSVSO`、`%NOTOPOPT`、`%NOUNIONOROPT`、`%PARALLEL`和`%STARTTABLE`。 - `table-ref` - 从其中检索数据的一个或多个表、视图、表值函数或子查询,以逗号分隔的列表或使用`JOIN`语法指定。 在使用带有`JOIN`语法的视图时存在一些限制。 可以指定一个用括号括起来的子查询。 - `AS t-alias` - 可选—表名的别名。 必须是有效的标识符。 # 描述 `FROM`子句指定在`SELECT`语句中查询数据的一个或多个表(或视图或子查询)。 如果没有查询表数据,则`FROM`子句是可选的,如下所述。 多个表被指定为逗号分隔的列表,或者由其他`JOIN`语法分隔的列表。 可以为每个表名提供一个别名。 在`SELECT`语句中为多个表指定字段名时使用表名别名。 如果`FROM`子句中指定了两个(或更多)表,可以通过指定`tablename`来指明需要哪个表的字段。 `SELECT SELECT -item`子句中每个字段的字段名。 由于表名通常是长名称,因此短表名别名在此上下文中很有用(`t-alias.fieldname`)。 下面的示例展示了表名别名的使用: ```sql SELECT e.Name,c.Name FROM Sample.Company AS c,Sample.Employee AS e ``` AS关键字可以省略。 它是为了兼容性和清晰度而提供的。 ## 向表引用提供模式名称 `table-ref`名称可以是限定的(`schema.tablename`)或非限定的(`tablename`)。 非限定表名(或视图名)的模式名使用模式搜索路径或系统范围的默认模式名提供: 1. 如果提供了模式搜索路径, IRIS将在指定的模式中搜索匹配的表名。 2. 如果没有提供模式搜索路径,或者模式搜索路径没有生成匹配, IRIS将使用系统范围的默认模式名。 ## 表连接 当在`FROM`子句中指定多个表名时, SQL将对这些表执行连接操作。 执行的连接类型由每对表名之间的连接关键字短语或符号指定。 当两个表名用逗号分隔时,将执行交叉连接。 执行连接的顺序是由SQL查询优化器自动确定的,而不是基于查询中列出的表的顺序。 如果需要,可以通过指定查询优化选项来控制执行连接的顺序。 以下三个`SELECT`语句显示了两个单独表的行数,以及指定两个表的`SELECT`的行数。后者产生一个更大的表,即笛卡尔乘积,其中第一个表中的每一行都与第二个表中的每一行相匹配,这一操作称为交叉联接(`Cross Join`)。 ```sql SELECT COUNT(*) FROM Sample.Company ``` ```sql SELECT COUNT(*) FROM Sample.Vendor ``` ```sql SELECT COUNT(*) FROM Sample.Company,Sample.Vendor ``` 从`Sample.Company、Sample.Vendor`中选择计数(`*`) ```sql SELECT COUNT(*) FROM Sample.Company CROSS JOIN Sample.Vendor ``` 在大多数情况下,交叉连接的大量数据复制是不可取的,而某些其他类型的连接更可取。 如果在`SELECT`语句中指定`WHERE`子句,则执行交叉联接,然后`WHERE`子句谓词确定结果集。这等效于使用`ON`子句执行内联接。因此,以下两个示例返回相同的结果: ```sql SELECT p.Name,p.Home_State,em.Name,em.Office_State FROM Sample.Person AS p, Sample.Employee AS em WHERE p.Name %STARTSWITH 'E' AND em.Name %STARTSWITH 'E' ``` ```sql SELECT p.Name,p.Home_State,em.Name,em.Office_State FROM Sample.Person AS p INNER JOIN Sample.Employee AS em ON p.Name %STARTSWITH 'E' AND em.Name %STARTSWITH 'E' ``` # 查询优化选项 默认情况下, SQL查询优化器使用复杂而灵活的算法来优化涉及联接操作和/或多个索引的复杂查询的性能。在大多数情况下,这些默认值可提供最佳性能。但是,在极少数情况下,可能希望向查询优化器提供“提示”,指定查询优化的一个或多个方面。因此, SQL在`FROM`子句中提供了`OPTIMIZE-OPTION`关键字。可以按任意顺序指定多个优化关键字,并以空格分隔。 可以在简单的`SELECT`语句、`CREATE VIEW DEFINITION SELECT`语句或`FROM`子句的子查询`SELECT`语句中使用`OPTIMIZE-OPTION FROM`子句关键字。 ## %ALLINDEX 此可选关键字指定提供任何好处的所有索引都用于查询联接顺序中的第一个表。只有在定义了多个索引时才应使用此关键字。优化器的默认设置是只使用优化器认为最有益的那些索引。默认情况下,这包括所有有效的相等索引和其他类型的选定索引。`%ALLINDEX`使用所有类型的所有可能有益的索引。测试所有索引的开销较大,但在某些情况下,它可能会提供比默认优化更好的性能。当使用多个范围条件索引和低效相等条件索引时,此选项特别有用。在这些情况下,查询优化器可能无法获得准确的索引选择性。`%ALLINDEX`可以与`%IGNOREINDEX`一起使用,以包括/排除特定索引。通常,`%ALLINDEX`不应与`TOP`子句查询一起使用。 可以将`%STARTTABLE`与`%ALLINDEX`配合使用,以指定`%ALLINDEX`应用于哪个表。 可以使用`%NOINDEX`条件级别提示为特定条件的`%ALLINDEX`指定异常。 `%NOINDEX`提示放置在不应该使用索引的每个查询选择条件的前面。 例如,`WHERE %NOINDEX hiredate < ?`。 这在绝大多数数据没有被排除的情况下最常用。 对于小于(`<`)或大于(`>`)条件,使用%NOINDEX条件级别提示通常是有益的。 对于相等条件,使用`%NOINDEX`条件级提示没有任何好处。 对于连接条件,`ON`子句连接支持`%NOINDEX`。 ## %FIRSTTABLE ```sql %FIRSTTABLE tablename ``` 此可选关键字指定查询优化器应开始使用指定的表名执行联接。`tablename`为稍后在联接序列中指定的表命名。其余表的联接顺序留给查询优化器。此提示在功能上与`%STARTTABLE`相同,但为提供了以任意顺序指定联接表序列的灵活性。 `tablename`必须是简单标识符,可以是表别名,也可以是非限定表名。不能使用限定表名(`schema.table`)。如果查询指定了表别名,则必须将该表别名用作表名。例如: ```sql FROM %FIRSTTABLE P Sample.Employee AS E JOIN Sample.Person AS P ON E.Name = P.Name ``` `%FIRSTTABLE`和`%STARTTABLE`都允许指定用于联接操作的初始表。`%INORDER`允许指定用于联接操作的所有表的顺序。这三个关键词是相互排斥的;只指定一个和一个。如果不使用这些关键字,查询优化器将按照其认为最佳的顺序对表执行联接,而不管这些表的列出顺序如何。 不能使用`%FIRSTTABLE`或`%STARTTABLE`从左外部联接的右侧(或右外部联接的左侧)开始联接顺序。尝试这样做会导致`SQLCODE-34`错误:“优化器无法找到可用的联接顺序”。 ## %FULL 此可选关键字指定编译器优化器检查所有可选联接序列以最大化访问性能。例如,在创建存储过程时,增加的编译时间可能值得提供更优化的访问。默认优化是,当`FROM`子句中有许多表时,不检查不太可能的连接序列。`%FULL`将覆盖此默认行为。 当`FROM`子句包含使用箭头语法访问的表时,可以同时指定`%INORDER`和`%FULL`关键字,这些表的顺序不受约束。 ## %IGNOREINDEX 此可选关键字指定查询优化器忽略指定的索引或索引列表。(为了向后兼容,支持不推荐使用的同义词`%IGNOREINDICES`。) 在此关键字后面指定一个或多个索引名。多个索引名必须用逗号分隔。可以使用以下格式之一指定索引名: ```java %IGNOREINDEX [[schemaname.]tablename.]indexname [,...] %IGNOREINDEX [[schemaname.]tablename.]* [,...] ``` 方案名和表名是可选的。如果省略,则使用当前默认架构和指定为`from table-ref`的表名。星号(`*`)通配符指定指定表的所有索引名。可以按任意顺序指定索引名称。 SQL不会验证指定的索引名(或它们的模式名和表名);不存在或重复的索引名将被忽略。 通过使用此优化约束,可以使查询优化器不使用对特定查询不是最佳的索引。通过指定除一个索引名之外的所有索引名,实际上可以强制查询优化器使用剩余的索引。 还可以通过在条件前面加上`%noindex`关键字来忽略特定条件表达式的特定索引。 ## %INORDER 此可选关键字指定查询优化器按照表在`FROM`子句中列出的顺序执行联接。这最大限度地减少了编译时间。子查询的扁平化和索引使用不受影响。 `%INORDER`不能与交叉联接或右外部联接一起使用。如果指定的表顺序与外部联接的要求不一致,则会生成`SQLCODE-34`错误:“Optimizer找不到可用的联接顺序。”为避免这种情况,建议在与外部联接一起使用`%INORDER`时,仅与ANSI样式的左外部联接或完全外部联接一起使用。 视图和表子查询按照它们在`FROM`子句中指定的顺序进行处理。 - 流式视图:`%INORDER`不影响视图中表的处理顺序。 - 合并视图:`%INORDER`导致在视图的引用点处按照视图的`FROM`子句顺序处理视图表。 将此关键字与`%FIRSTTABLE`和`%STARTTABLE`进行比较,这两个关键字都只指定初始连接表,而不指定完整的连接顺序。 不能同时使用`%INORDER`和`%PARALLEL`优化;如果同时指定了这两个优化,则忽略`%PARALLEL`。 ## %NOFLATTEN 此可选关键字在量化的子查询(返回布尔值的子查询)的`FROM`子句中指定。它指定编译器优化器应抑制子查询展平。此优化选项禁用“扁平化”(默认),它通过将子查询有效地集成子查询到查询中来优化包含量化的子查询的查询:将子查询的表添加到查询的`FROM`子句中,并将子查询中的条件转换为查询的`WHERE`子句中的联接或限制。 以下是使用`%NOFLATTEN`的量化子查询的示例: ```sql SELECT Name,Home_Zip FROM Sample.Person WHERE Home_Zip IN (SELECT Office_Zip FROM %NOFLATTEN Sample.Employee) ``` ```sql SELECT Name,(SELECT Name FROM Sample.Company WHERE EXISTS (SELECT * FROM %NOFLATTEN Sample.Company WHERE Revenue > 500000000)) FROM Sample.Person ``` `%INORDER`和`%STARTTABLE`优化隐式指定`%NOFLATTEN`。 ## %NOMERGE 此可选关键字在子查询的`FROM`子句中指定。它指定编译器优化器应该禁止子查询到视图的转换。此优化选项通过将子查询作为内联视图添加到查询的`FROM`子句来禁用对包含子查询的查询的优化;子查询与查询字段的比较将作为联接移动到查询的`WHERE`子句。 ## %NOREDUCE 此可选关键字在流式子查询的`FROM`子句中指定-返回行的结果集的子查询,即封闭查询的`FROM`子句中的子查询。它指定编译器优化器应该禁止将子查询(或视图)合并到包含查询中。 在下面的示例中,查询优化器通常会通过对子查询执行`Sample.Person`的笛卡尔乘积联接来“减少”该查询。`%NOREDUCE`优化选项可防止出现这种情况。 IRIS改为在`GNAME`上构建临时索引,并在此临时索引上执行联接: ```sql SELECT * FROM Sample.Person AS p, (SELECT Name||'goo' AS gname FROM %NOREDUCE Sample.Employee) AS e WHERE p.name||'goo' = e.gname ``` ## %NOSVSO 此可选关键字在量化的子查询(返回布尔值的子查询)的`FROM`子句中指定。它指定编译器优化器应禁止集值子查询优化(`SVSO`)。 在大多数情况下,集值子查询优化可以提高`[NOT] EXISTS`和`[NOT] In`子查询的性能,特别是对于只有一个可分离关联条件的子查询。 它通过用满足条件的数据值填充临时索引来实现这一点。 IRIS不是重复执行子查询,而是在临时索引中查找这些值。 例如,`SVSO`优化了 `NOT EXISTS (SELECT P.num FROM Products P WHERE S.num=P.num AND P.color='Pink')`,创建临时索引。 `SVSO`优化了`ALL`或`ANY`关键字与相对操作符(`>`,`>=`,`<`,或`<=`)和子查询的子查询,如`… WHERE S.num > ALL (SELECT P.num…)` 它通过将子查询表达式`sqbExpr`(在本例中为`P.num`)替换为`MIN(sqbExpr)`或`MAX(sqbExpr)`来实现这一点。 当`sqbExpr`上有索引时,它支持快速计算。 `%INORDER`和`%STARTTABLE`优化不禁止集值子查询优化。 ## %NOTOPOPT 当使用带有`ORDER BY`子句的`TOP`子句时指定此可选关键字。 默认情况下,`TOP`和`ORDER By`优化到第一行的最快时间。 相反,指定`%NOTOPOPT`(没有`TOP`优化)将优化查询,以最快地检索完整的结果集。 ## %NOUNIONOROPT 此可选关键字在查询或子查询的`FROM`子句中指定。 它禁用为多个`OR`条件和针对`UNION`查询表达式的子查询提供的自动优化。 这些自动优化将多个`OR`条件转换为`UNION`子查询,或将`UNION`子查询转换为`OR`条件。 这些`UNION/OR`转换允许`EXISTS`和其他低级谓词迁移到顶级条件,以便IRIS查询优化器索引使用它们。 这些默认转换在大多数情况下都是可取的。 然而,在某些情况下,这些`UNION/OR`转换会带来很大的开销负担。 `%NOUNIONOROPT`对与此`FROM`子句关联的`WHERE`子句中的所有条件禁用这些自动`UNION/OR`转换。 因此,在一个复杂的查询中,可以对一个子查询禁用这些自动UNION/OR优化,同时在其他子查询中允许它们。 `UNION %PARALLEL`关键字禁用自动`UNION-to- or`优化。 `%INORDER`和`%STARTTABLE`优化抑制了`OR-to-UNION`优化。 `%INORDER`和`%STARTTABLE`优化不抑制`UNION-to-OR`优化。