CN1592905A - 自动产生数据库查询的系统和方法 - Google Patents

自动产生数据库查询的系统和方法 Download PDF

Info

Publication number
CN1592905A
CN1592905A CNA018118208A CN01811820A CN1592905A CN 1592905 A CN1592905 A CN 1592905A CN A018118208 A CNA018118208 A CN A018118208A CN 01811820 A CN01811820 A CN 01811820A CN 1592905 A CN1592905 A CN 1592905A
Authority
CN
China
Prior art keywords
seq
emp
select
data base
subquery
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
CNA018118208A
Other languages
English (en)
Inventor
爱德华·凯茨尤兹库
蒙诺·萨拉库玛
翰-瓦农·沃
约翰·文森特
托马斯·沃林
乔伊斯·劳
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
CA Inc
Original Assignee
Computer Associates Think Inc
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Computer Associates Think Inc filed Critical Computer Associates Think Inc
Publication of CN1592905A publication Critical patent/CN1592905A/zh
Pending legal-status Critical Current

Links

Images

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/20Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
    • G06F16/24Querying
    • G06F16/245Query processing
    • G06F16/2453Query optimisation
    • G06F16/24534Query rewriting; Transformation
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/20Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
    • G06F16/21Design, administration or maintenance of databases
    • G06F16/217Database tuning

Abstract

一种调节数据库查询的方法包括选择数据库查询;分析选定的数据库查询以确定选定的数据库查询的若干部分之间的关系;从多个可用的最优化模式中选择最优化模式;根据确定的关系和选定的最优化模式,通过修改选定的数据库查询的至少一个部分,调节选定的数据库查询以及显示修改后的数据库查询。

Description

自动产生数据库查询的系统和方法
相关申请书的引用
本申请书基于2000年5月26日提交的60/207,379号临时申请书,其全部内容在此引用作为参考。
技术领域
本说明书涉及数据库,更确切地说,涉及自动产生数据库查询的系统和方法。
背景技术
结构化查询语言(SQL)是一种用于数据库交互操作的ANSI标准语言。SQL允许用户从数据库中许多不同的记录集(表格)组合信息,以便从数据库检索数据。不过,SQL的能力也有某些缺点。例如,用户能够在一个SQL查询中组合不同的表格,它可能产生数据库引擎不可能解决的或者耗用大量系统资源的查询。
数据库系统往往包括性能调节的系统或方法。例如,Oracle 7提供了多种脚本(如UTILBSTAT和UTLESTAT),能够用于通过在一个或多个报告中总结数据库的操作状态,协助性能调节。这些脚本是一组SQL脚本,对于捕捉全系统的数据库性能的统计瞬态情况和产生有助于操作员优化数据库性能的报告十分有用。数据库操作员能够使用这些报告对数据库的性能进行精细调节以及对数据库进行预防性的维护。报告可能包括例如有关数据库存储器目标的信息,包括库缓存、词典缓存、闭锁使用、文件I/O和回退统计。
现有系统的一个问题是,它们往往限制了产生最优执行计划所花费的时间长短。此外,熟悉的用户可能对数据了解得比目标统计表现出的更多,如果确实有目标统计的话。现有系统往往不利用用户的知识。此外,尽管在恰当地提供和分析时统计可能有用,如果目标还没有被分析则可能根本没有统计结果,或者统计结果可能过时了。在具体的事例中,可能没有洞察数据分布的特定统计结果。相反,用户倒可能具有在调节数据库查询中有用的第一手知识,而这可能是无法通过其他途径得到的。例如,用户可能知道,将会在有更多的资源比如多CPU可用时执行查询,即使系统通常是满负荷的。在数据库查询调节过程期间,会证明这种信息是十分有用的。
发明内容
一种调节数据库查询的方法,包括选择数据库查询;分析选定的数据库查询,以确定选定的数据库查询中若干部分之间的关系;从多个可用的最优化模式中选择一个最优化模式;根据确定的关系和选定的最优化模式,通过修改选定的数据库查询中至少一部分,调节选定的数据库查询;以及显示修改后的数据库查询。
这种分析可以确定数据库查询之内的标记,标记是由分隔符分开的若干单词。多个可用的最优化模式可能包括基于成本的和基于规则的模式。基于成本的模式可能包括First_Rows(第一行)模式和All_Rows(所有行)模式。这种方法可能进一步包括确定一种与使用调节后的数据库查询相关联的成本。这种方法可能进一步包括比较与使用选定的数据库查询相关联的成本和与使用调节后的数据库查询相关联的成本。这种方法可能进一步包括分析选定的数据库查询,以确定该数据库查询是否包括至少一个子查询,其中的子句包含有NOTEXISTS、NOT IN和ALL中至少一个。这种方法可能进一步包括提示用户,根据该数据库查询是否包括包含有NOT EXISTS、NOT IN和ALL中至少一个的子句,选择在调节期间使用的优先设置。
这种优先设置可能包括重写优先设置,以便使用户能够选择两种转换之一:一种是NOT EXISTS运算符转换为NOT IN运算符,另一种是选定的数据库查询转换为外部的连接。这种优先设置可能包括重写优先设置,以便使用户能够选择将ALL运算符连接的子查询转换为一个连接或者外部连接。这种优先设置可能包括重写优先设置,以便使用户能够选择是否使用NOT EXISTS运算符和外部连接之一,转换NOT IN运算符连接的子查询。
计算机存储介质包括用于调节数据库查询的、计算机可执行的代码,其中包括用于使用户选择数据库查询的、计算机可执行的代码;用于分析选定的数据库查询以确定选定之数据库查询中若干部分之间关系的、计算机可执行的代码;用于使用户从多个可用的最优化模式中选择一个最优化模式的、计算机可执行的代码;用于根据确定的关系和选定的最优化模式,通过修改选定的数据库查询中至少一部分,调节选定的数据库查询的、计算机可执行的代码;以及用于显示修改后的数据库查询的、计算机可执行的代码。
用于调节数据库查询的、编程的计算机系统包括一台显示器——用于向用户显示至少一个数据库查询;一种用户输入——使用户从显示的数据库查询之中选择一个数据库查询,从多个可用的最优化模式中选择一个最优化模式;以及一个处理器——用于分析选定的数据库查询,以确定选定的数据库查询中若干部分之间的关系,并且用于根据确定的关系和选定的最优化模式,通过修改选定的数据库查询中至少一部分,调节选定的数据库查询;修改后的数据库查询,通过该显示器向用户显示。
附图简要说明
下列附图仅仅描述了说明性的实例,为了更完全地评价和理解下列介绍而提供。
图1是一个框图,用于介绍依据一个实施例的一个数据库查询调节过程;
图2显示了包括一个SQL语句的一个对话显示;
图3显示了一个选择最优化模式对话显示;
图4显示了一个优先设置窗口显示;
图5显示了一个检验SQL对话显示;
图6显示了一个结果窗口显示;
图7显示了一个编辑或者说调节窗口显示;
图8显示了一个详细结果窗口显示;
图9是一个计算机系统的框图,本系统和方法可以应用在其中;以及
图10至图13是显示多种SQL语句中表格层次的示意图。
具体实施方式
在介绍附图中展示的本公开文件的优选实施例时,为清晰起见采用了特定的技术。不过,本公开文件并非试图限于由此选择的特定技术,应当理解,每个特定的要素包括了在类似方式下运行的所有技术上的等效物。
本公开文件涉及为了提高性能而自动调节数据库查询的系统和方法。例如,本系统和方法的形式可能是数据库管理系统(DBMS),它能够调节结构化查询语言(SQL)的语句,以产生最优的执行方案。在一方面,本公开文件涉及的系统和方法用于在数据库结构的上下文中分析数据库查询,并且修改和/或重构该查询,因此它能够在DBMS结构的上下文之内执行。此外,本公开文件的系统和方法能够使用数据库关系结构来使该查询使用的DBMS资源最小化,并确保该查询能够完成。
实现这些结果的一种方法是将SQL语句剖分成定制的数据结构,它容许SQL语句的修改和重构。举例来说,如在某个FROM子句中的每个表格都可以检验以保证引用的完整性,并且可以对照如某个用户的WHERE条件,就可以为了正确的外部连接说明而检验这个WHERE条件。
本系统分析SQL语句并保持追踪每个标记:表格是如何连接的,以及SQL语句若干部分之间的关系。标记可能是SQL语句之内由分隔符分开的任何单词。表示表格列名称的标记可以用于确认SQL语句内部存在的连接和其它关系。然后,系统和方法可以改变例如连接的次序,并且可以移动子查询以调节SQL语句,达到最高性能。系统和方法的实现形式可以是在计算机系统——比如主机、个人计算机(PC)、手持计算机等等——中运行的软件应用程序。计算机系统可以连接到数据库。这种连接可以是例如通过直接连接——比如直接的硬布线或者无线连接,通过网络连接——比如局域网,或者通过因特网。
图9中显示了能够实现本系统和方法之计算机系统的一个实例。该计算机系统一般地成为系统200,可能包括中央处理单元(CPU)202、存储器204、打印机接口206、显示单元208、LAN(局域网)数据传输控制器210、LAN接口212、网络控制器214、内部总线216以及一台或多台输入设备218,比如键盘、鼠标等等。如图所示,系统200可以通过连接装置222连接到数据库。
图1描述了一个为提高性能而调节SQL语句的过程,依据本公开文件的一个实施例。用户首先选择他们需要调节的一个SQL语句(步骤S2)。例如,从显示单元208上显示的SQL编辑窗口,通过将光标放置在SQL语句的起点,按下鼠标的左键,拖动到该SQL语句的末端,然后释放鼠标键,用户能够选中他们需要调节的一个SQL语句。这就选中了该SQL语句。然后用户能够通过例如单击某个适当的按钮,从一个工具菜单(未显示)选择一个SQL调节器选件。
然后,选中的要调节的SQL语句显示在SQL调节器窗口1中(步骤S4),如图2所示。然后用户就能够考察显示的SQL语句2,以核实它就是他们需要调节的SQL语句。然后用户可以选择单击后退按钮3、下一步按钮4、完成按钮5或者取消按钮6。后退按钮3返回前一个窗口,使用户选择一个不同的SQL语句。取消按钮6退出SQL调节器而不对显示的SQL语句2进行任何改变。下一步按钮4移动到下一个窗口(在图3中显示),使用户选择最优化模式设置,下面还要介绍。完成按钮5使用当前的最优化模式设置运行SQL调节过程。
本系统能够采用数种最优化模式和使用数种不同的重写优先设置来运行。用户单击下一步按钮4之后,本系统分析该SQL语句(步骤S6)并显示选择最优化模式窗口11,如同3所示。检验该SQL语句以确定例如在该语句中存在着什么运算符、函数等等。系统也检验该SQL语句之内的任何子查询是否连接了NOT EXISTS、NOT IN和ALL子句。本系统也检验表格统计。例如,可能要检验对表格执行ANALYZE命令时由某个系统比如Oracle产生的表格统计。表格统计可能包括行数(NUM_ROWS)、最高峰之下的数据块数(如已经格式化过的、接收数据的数据块的数目,无论这些数据块当前包含着数据还是空着)(BLOCKS)、分配给表格的、还没有使用的数据块的数目(EMPTY_BLOCKS)、以字节计算的、每个数据块中的平均可用空闲空间(AVG_SPACE)、链接行的数目(CHAIN_COUNT)以及以字节计算的平均行长度,包括行的头部(AVG_ROW_LEN)。
如果存在足够的信息(如对于有关的表格存在统计数据),系统就自动选择一个最优化模式。选定的最优化模式由圆按钮7-9指示。例如,可能会自动选择基于成本的最优化(FIRST ROW或ALL ROW)模式,因为有关的表格存在统计数据时它将会产生很好的结果。在步骤S8中,如果在表格统计中没有足够的信息使系统自动选择一种最优化模式,或者如果用户需要改变系统自动设置的最优化模式,用户通过单击选择最优化模式窗口11中的圆按钮7-9之一,可以手工地选择最优化模式,如图3所示。用户从窗口11中通过单击优先设置按钮10,也可以修改重写优先设置设置,下面还要更详细地介绍。
一种基于成本的最优化模式成为ALL_ROW模式。如果在SQL语句中至少一个引用的表格存在统计数据,系统就会默认地自动选择ALL_ROW模式。ALL_ROW模式为批量处理提供了快速的吞吐率。然后,用户通过单击圆按钮8,可以选择FIRST ROW模式,除非该SQL语句包含着集合运算符(如UNION、INTERSECT、MINUS、UNION ALL)、GROUP BY子句、FOR UPDATE子句、聚合函数或者DISTINCT运算符。如果该SQL语句包含着集合运算符(如UNION、INTERSECT、MINUS、UNION ALL)、GROUP BY子句、FOR UPDATE子句、聚合函数或者DISTINCT运算符,用户就不能选择FIRST ROW模式。用户通过单击圆按钮7,也可以手工选择ALL_ROW模式。
当不能以其它方式确定对话所使用的最优化模式时,系统也可能自动选择FIRST ROW模式。如果对行处理需要快速响应时间,可以手工选择FIRST ROW模式。
另一种模式称为基于规则的模式。如果对于任何引用的表格都没有统计数据,系统就会地自动选择基于规则的模式。通过单击圆按钮9,可以手工选择基于规则的模式。
如果在分析处理(步骤S6)期间确定SQL语句包括连接了NOTEXISTS、NOT IN或ALL子句的子查询,就使窗口11(图3)中的优先设置按钮10活化。单击优先设置按钮10是用户指定重写优先设置,用于重写连接了NOT IN运算符、NOT EXISTS运算符和ALL运算符的子查询。
例如,能够指定NOT EXISTS运算符的重写优先设置,使用户能够选择将NOT EXISTS运算符转换为NOT IN运算符和/或将该语句转换为外部连接。能够指定ALL运算符的重写优先设置,使用户选择将该语句转换为连接或外部连接。能够指定NOT IN运算符的重写优先设置,使用户能够选择将NOT IN运算符转换为NOT EXISTS运算符将该语句转换为外部连接。
通过选择某些选件,对转换到外层的界面列规定为NOT NULL的事例进行限制,用户可以进一步规定重写优先设置。用户也可以指定本系统,如果需要,就对语句全都进行转换并增加IS NOT NULL准则。
用户单击优先设置按钮10时,将显示优先设置窗口50,如图4所示。然后,通过单击调节器标签51,将显示SQL调节器优先设置页52。这个窗口中的选件,使得用户能够为连接了运算符ALL、NOTIN和NOT EXISTS的子查询设置重写优先设置,如前所述。
在图4所示的实例中,要为NOT EXISTS运算符设置重写优先设置,用户就从下拉菜单53中选择NOT EXISTS运算符。这就显示了对于NOT EXISTS运算符可用的选件的列表。例如,然后通过对选件  “通过NOT EXISTS运算符连接的子查询转换到NOT IN”(复选框55)和“通过NOT EXISTS运算符连接的子查询转换到外部连接”(复选框56)选择或不选择适当的复选框,用户可以指定是否使本系统能够使用NOT IN和/或外部连接来转换连接了NOTEXISTS运算符的子查询。
如果选定了“通过NOT EXISTS运算符连接的子查询转换到NOT IN”(复选框55)选件,选件框57和58变为活化。选件框57使用户选择“对外部查询的连接列检验NOT NULL条件”选件,选件框58使用户选择“对子查询的连接列检验NOT NULL条件”选件。用户分别通过选择或不选择复选框59和60,可以在这些选件中选择一个或者两个都选。然后,对于每个选定的选件框,转换选件变为活化。例如,分别通过单击圆按钮61和63,可以对外部查询和子查询选择“仅当列规定为NOT NULL时转换”;分别通过单击圆按钮62和64,可以选择“如果需要,全都转换并增加“IS NOTNULL””。然后用户可以单击“OK”按钮54以保存指定的优先设置,并退出优先设置窗口。选择取消按钮66会退出窗口52,但不保存对优先设置所作的任何改变。选择帮助按钮65会向用户显示帮助菜单。
以类似的方式,要为ALL运算符设置重写优先设置,用户就从下拉菜单53中选择“ALL”运算符以显示选件列表。然后,将会为用户提供某些选件,通过选择或不选择“通过ALL运算符连接的子查询转换到连接或外部连接”选件,指定是否使本系统能够把通过ALL运算符连接的子查询转换到连接或外部连接。
如果用户选择了这个选件,那么将会为用户提供某些选件,“对外部查询的连接列检验NOT NULL条件”和“对子查询的连接列检验NOT NULL条件”。然后,用户可以选择这些选件中的一个,或者两个都选。然后,对于这些选定的选件中的每一个,会为用户提供两个转换选件,“仅当列规定为NOT NULL时转换”和“如果需要,全都转换并增加“IS NOT NULL””。
然后,用户可以单击“OK”按钮54以保存指定的优先设置,并退出优先设置窗口。
要为NOT IN运算符设置重写优先设置,用户就从下拉菜单53中选择NOT IN运算符以显示选件列表。然后用户通过选择或不选择选件“通过NOT IN运算符连接的子查询转换到NOT EXISTS”和“通过NOT IN运算符连接的子查询转换到外部连接”,可以指定是否使本系统能够使用NOT EXISTS运算符和/或外部连接来转换由NOT IN运算符连接的子查询。
对于每个选定的选件,然后为用户提供一个选件,以便对外部查询的连接列检验NOT NULL条件和对子查询的连接列检验NOTNULL条件。用户可以选择这些选件中的一个,或者两个都选。然后,对于每个选定的选件,转换选件变为活化。换句话说,给用户选择权,决定是仅当列规定为NOT NULL时转换,还是如果需要,全都转换并增加  “IS NOT NULL”。因此,用户可以为外部查询和/或子查询的连接列选择一个转换选件。用户单击“OK”按钮54以保存指定的优先设置,并退出优先设置窗口。退出优先设置窗口之后,显示返回选择最优化模式窗口11(图3)。步骤S8完成之后,用户对最优化模式和优先设置选择满意,通过单击下一步按钮8,就能继续处理。
在步骤S10中,本系统为了引用的完整性、外部连接和/或NULL逻辑问题而检验SQL语句。如果发现错误或无效之处,就会显示改动该SQL语句以纠正这些问题的特定建议。例如,对于非法的外部连接——它可能导致非法的结果集,可能会显示建议。对于导致非法结果集的NULL逻辑问题、HAVING子句的不正确使用、笛卡尔乘积、连接准则中为了更好地使用索引的表达式、非连接准则中为了更好地使用索引的表达式以及没有索引的外关键字等等,也可能显示建议。
然后在步骤S12中,向用户显示检验SQL窗口70,如图5所示。窗口部分73显示了该语句中每个子查询的图示。SQL语句中的每个表格显示为一个框,其头部包含着表格的名称和别名。对每个表格也显示主关键字、外关键字和独特外关键字。
表格之间的一条绿线表示正确的连接。如果一条红线连接着表格,该连接包含着某个错误(比如违背了引用的完整性或者不适当的外部连接)。如果一条蓝线连接着表格,该连接由于缺乏引用的完整性而是无效的。
对SQL语句建议的改正显示在窗口部分71中。用户可以按照需要调整检验SQL窗口70的尺寸,以观察任何窗口部分中包含的所有信息。
单击“下一个SQL模块”按钮72和前一个SQL模块”按钮74,会选中蓝色SQL语句中的各个子查询,并且仅仅显示与选中子子查询相关联的图示。
然后用户可以决定(步骤S14)要调节哪个SQL语句,原始语句或者修改后的语句。例如,单击“调节原始SQL”按钮76,会调节在检验SQL窗口70底部区域75中显示的原始SQL语句。单击“调节修改后SQL”按钮78,会执行检验SQL窗口70右侧区域71中显示的、建议的改正,然后调节改正后的SQL语句。
在步骤S16中,通过执行一个或多个步骤使语句最优化,调节选定的SQL语句。例如,系统可以在连接准则中作出传递性的改变,可以确定所有的子查询变换,可以确定需要时非连接准则中的传递性,可以确定连接次序。系统可以产生几个变换后的SQL语句。然后系统可以确定哪个变换后的SQL语句具有最佳的性能,并以此对结果SQL语句排序。
调节或变化一个SQL语句时,如果需要,本系统可以检验某个周围查询的若干列是否属于同一表格并作出传递性的改变。如果它们不属于同一表格,系统就检验是否有任何连接准则引用了连接子查询的一列,并确认等价列。本系统对连接子查询的每一列都这样做,然后在一次操作中使用传递性质来产生等价列的置换,以发现其中所有列都属于同一表格的一个组。本系统对通过NOT IN运算符连接的、非关联的子查询和与NOT IN、NOT EXISTS或ALL运算符连接的、关联的子查询,都可以作出传递性的改变。
本系统通过评价每个子查询和为每个变换分配一个等级,也可以确定对SQL语法所进行的所有子查询变换。变换可以是强制的(全部或绝不),也可以是任选的。然后,这种信息用于产生多种不同的SQL版本。例如,SQL语句包含四个子查询时,本系统可能不把任何一个子查询分配为“全都变换”等级,把一个分配为“绝不变换”等级,而把三个分配为“任选”等级,以产生可能的替代SQL语句。
换句话说,变换的类型决定了该变换是否应当全都进行、绝不进行或者可选地进行。例如,某些变换可能是需要的,因为进行变换之后优化器将使用更好的方案。在这种情况下,变换应当全都进行。所以,该变换会分配给最高的等级。某些变换可能是不需要的,由于进行变换之后优化器将使用效率更低的方案。在这种情况下,该变换不应当进行。所以,该变换会分配给最低的等级。某些变换被选用后可能会也可能不会产生更好的最优化方案,由于它可能还取决于其它因素。在这种情况下,该变换可以是可选地进行。所以,该变换会分配给中间的等级。
进行了子查询变换之后,本系统确认非连接准则中的等价列——它们能够相互替换——并进行替换。这样做使本系统能够重写SQL语句,让数据库(比如ORACLE)利用连接的关键字索引。
例如,在下列SQL语句中,对DEPENDENTS子查询的e.emp_seq准则能够连接到a.emp_seq或t.emp_seq。
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq
AND a.proj_seq=t.proj_seq
AND e.emp_seq IN(SELECT emp_seq FROM dependents
    WHERE relation=‘SPOUSE’)
如下(第5行)所示,把e.emp_seq转换到a.emp_seq使数据库能够使用连接到ASSIGNMENTS的关键字索引:
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq
AND a.proj_seq=t.proj_seq
AND a.emp_seq IN(SELECT emp_seq FROM dependents
    WHERE relation=‘SPOUSE’)
在等价列中存在着等价连接准则时,不同的列都能够替换另一列。不过,本系统也可以使用同连接准则相与的非连接准则的传递性。如果非连接准则是同连接准则相或,就不应当使用它产生的传递性。
如果某个多列运算对象具有传递性,本系统对该运算对象增加若干列,并将相应的列复制到选择列表。所有的多列传递性都用于每个变换,原始语句除外。如果运算对象通过某个外部连接的准则等价于另一列,不能使用等价列。
如果某个FROM子句具有嵌套选择语句——它不具有GROUPBY语法或聚集——并且主查询具有引用主查询和嵌套选择之间连接列之一的非连接准则,本系统就在该SQL语句的所有拷贝中,复制嵌套选择语句中的非连接准则,包括原始语句。
本系统能够使用一种ORDERED线索来确定连接次序。这种ORDERED线索迫使优化器依照表格在SQL语句中的FROM子句中出现的次序连接表格。这就使得写入的SQL语句以特定的次序连接FROM子句中引用的表格。系统首先不使用ORDERED线索来测试SQL语句。然后,本系统使用ORDERED线索来产生另外的置换,具有不同的驱动表格,以强制实现某种特定的连接次序——驱动表格是例如嵌套的循环连接运算中的某个父表格。驱动表格中的每一行都能够用于在连接的表格中发现匹配的行以完成连接运算。
如果变换后SQL语句的默认连接比原始的SQL语句具有更好的成本/行值,那么最可能的情况是,ORDERED线索将产生一个比利用默认连接次序的初始变换效率更高的方案但是成本也更高的行。本系统能够显示ORDERED变换,作为一种可行的最佳解决方案。
为了从产生的不同SQL语句中的每一个中确定最佳性能,本系统对原始的SQL语句和重写过程产生的每个SQL语句产生一种成本统计数据。在产生了与该SQL语句相关联的方案后,确定成本。例如,Oracle的EXPLAIN PLAN语句,可以用于产生优化器执行该SQL语句所用的方案。该EXPLAIN PLAN语句能够对该SQL语句运行以获得执行方案,其中描述了优化器执行该SQL语句时计划要使用的步骤。Oracle也会为该方案中的每一步骤提供一个数字(如成本)。该成本是执行方案中该步骤的一个相对数字。对于该方案中的所有步骤,可以对成本求和以获得该方案的总成本。本系统能够将数据库算出的成本除以行数,对每个SQL语句产生成本/行值。根据该方案需要的逻辑读的数目,也可以确定成本。确定了成本之后,本系统以上升的次序(从最低到最高成本)对SQL语句进行排序。
在步骤18中,本系统在结果对话窗口90中,显示原始的SQL语句和成本最低的SQL语句,如图6所示。原始的SQL语句显示在窗口部分92中,建议的修改SQL语句显示在窗口部分94中。然后,用户可以比较建议的修改SQL语句和原始的SQL语句,观察变化,然后选择他们是否想要以调节后的SQL语句替换原始的SQL语句。
然后单击替换SQL按纽100,就会以窗口94所示的、建议的修改SQL语句替换原始的SQL语句。系统在编辑或者说调节窗口104中,增加注释并显示调节后的SQL语句,如图7所示。如图7所示,注释可能包括日期标志、表明语句已经调节和标识所用最优化模式(在这个实例中是ALL_ROWS)的信息。单击后退按钮96返回前一个窗口。单击更多细节按钮98打开详细结果窗口106,如图8所示。调节后的SQL语句显示在窗口部分108中。行110显示了原始的SQL语句的成本统计项目,一个或多个行112显示了调节改变后的SQL语句的成本统计数据。统计项目可能包括占用时间114——执行该SQL需要的时间量(以秒记)、CPU时间116——执行该SQL需要的每秒的CPU周期数目、逻辑读取118——执行该SQL需要的逻辑读取的数目、实际读取120——执行该SQL需要的实际读取的数目、行数122——SQL返回的行数以及成本/行数124——数据库的成本除以行数。
详细结果窗口106使用户能够观察每个语句的成本统计数据,以帮助用户选择最适合其需要的SQL。在包括编辑器功能的系统中,用户也可以选择打开调节后的语句,以进行进一步的编辑。
如果在SQL中有某个结合变量,单击“结合”按纽126就会显示一个对话框,在执行该SQL语句之前,用户能够在其中为该变量指定一个数值。单击“执行”按纽128会产生选定语句的统计数据。单击“全部执行”按纽130会产生列出的所有SQL语句的统计数据。用户可以单击“打印”按纽132来打印当前在窗口中显示的信息。用户可以单击“保存”按纽134把这个窗口中的信息保存为文本文件,以便将来引用。用户可以在表格中选择另外的SQL条目,单击“PAFO”(为Oracle的方案分析器)按纽138在方案窗口中显示代码。
单击“替换SQL”按纽140,以调节后的SQL替换原始的SQL。单击“后退”按纽136返回结果窗口90(图6)。单击“取消”按纽144退出本系统而不改变原始的SQL。
以下说明列出并介绍了多种术语——本说明书自始至终使用这些术语来引用SQL语句的部分或属性——以及本系统为调节SQL语句所用的某些概念。本说明书自始至终使用这些术语来介绍本系统调节SQL语句所用的算法。
A.分支和嵌套
当某个查询具有子查询时,从顶端(主查询)到底部的路径为一“分支”。“嵌套的级别”是分支中子查询的数目。主查询被视为处于“级别”=1。直接在它下面的子查询处于“级别”=2,依此类推。考虑以下的SQL,为了易于引用,已经加上了行号。
1.SELECT*FROM employees
2.WHERE emp_seq IN
3.    (SELECT emp_seq
4.    FROM time_sheets t
5.    WHERE t.rpt_date=‘01-MAY-98’
6.    AND t.proj_seq=
7.                 (SELECT proj_seq FROM projects
8.                  WHERE name=‘EXPLAIN SQL:DEVELOPMENT’))
9.AND hiredate>SYSDATE-10
分支从主查询LEVEL=1(从第1行开始)延伸到LEVEL=2(从第3行开始),再到LEVEL=3最后的子查询(从第7行开始)。在这个实例中,“嵌套的级别”为2,因为主查询具有一个子查询,这个子查询又有一个子查询。以下SQL语句包含两个分支:
1.SELECT*FROM employees
2.WHERE emp_seq IN
3.    (SELECT emp_seq
4.     FROM time sheets t
5.     WHERE t.rpt_date=‘01-MAY-98’
6.     AND t.proj_seq=
7.                 (SELECT proj_seq FROM projects
8.                  WHERE name=‘EXPLAIN SQL:DEVELOPMENT’))
9. AND hiredate>SYSDATE-10
10.AND emp_seq IN
11.    (SELECT emp_seq FROM dependents
12.    WHERE birthdate>‘01-JAN-67’)
这个SQL语句的第一个分支与前一个实例相同。不过,这个SQL语句还具有第二个分支。主查询(从第1行开始)为第1级别。第2级别从11行开始。这个第二分支的嵌套级别等于1。
B.最顶端的父级布尔运算符
当WHERE子句中存在OR运算符时,在合并或者将某个子查询移入FROM子句之前,应当谨慎。如果OR是父级布尔运算符,就不应当进行合并或移动。以下的事例说明了这一点。
对于SQL语句:
SELECT e.emp_seq FROM employees e
WHERE hiredate>SYSDATE-155
OR emp_seq IN(SELECT emp_seq FROM assignments
           WHERE proj_seq=1)
如果我们不考虑OR运算符,子查询可以合并如下:
SELECT e.emp_seq,x.emp_seq FROM employees e,
(SELECT emp_seq FROM assignments
                     WHERE proj_seq=1)x
WHERE e.hiredate>SYSDATE-155
OR e.emp_seq=x.emp_seq
不过,在子查询中没有连接的行时,这项连接现在将变为笛卡尔乘积。例如,当准则“e.emp_seq=x.emp_seq”求值为FALSE,但是非连接准则求值为TRUE时,无论如何来自子查询的行都将被连接。对于这个特定的EMPLOYEES行,无论连接来自子查询的哪一行,非连接准则将永远求值为TRUE。这就产生了笛卡尔乘积。
以下实例说明了当准则前面有NOT时,这个问题可能会变得更加困难。
例如,给定SQL语句:
SELECT e.emp_seq FROM employees e
WHERE NOT(hiredate>SYSDATE-155
OR emp_seq IN(SELECT emp_seq FROM assignments
           WHERE proj_seq=1))
使用DeMorgan规则,NOT反转括号内的布尔和关系运算符。不过,本系统可以使用使用DeMorgan规则消除NOT运算符,得出以下SQL。
反转的布尔和关系运算符有下划线。进行反转首先可能简化了该过程。
SELECT e.emp_seq FROM employees e
WHERE hiredate<=SYSDATE-155
AND emp_seq NOT IN(SELECT emp_seq FROM assignments
                WHERE proj_seq=1)
C.关联到多个SQL模块
关联的子查询能够被关联到多于一个SQL模块,如以下实例所示:
1.SELECT*FROM employees e
2.WHERE EXISTS
3.    (SELECT null FROM assignments a
4.    WHERE a.emp_seq=e.emp_seq
5.    AND EXISTS
6.        (SELECT null FROM time_sheets t
7.        WHERE t.emp_seq=e.emp_seq
8.        AND t.proj_seq=a.proj_seq))
对TIME_SHEETS(第6行)的子查询(通过第7行)既关联到外层的(对ASSIGNMENTS的)查询,又(通过第8行)关联到对EMPLOYEES的主查询。
D.关联准则
在上面的SQL语句中,第7行和第8行的准则称为“关联准则”。这些准则不是“连接准则”,但是在子查询执行时引用查询外部(比如“e.emp_seq”或“a.proj_seq”)像是常数的意义上,更像“非连接准则”。
在例程中可以检验关联准则,以确保它们是用等价运算符。不过应当注意,以这种方式检验的关联准则应当是对应于包括某个独特索引的若干列。例如,以下查询在子查询中具有两个关联准则。不过,有影响的只有一个,即对于PROJ_SEQ的一个,由于它是具有独特索引的列。
SELECT*FROM assignments a
WHERE EXISTS
    (SELECT start_date FROM projects p
     WHERE a.proj_seq=p.proj_seq
     AND a.start_date<p.start_date)
E.非连接准则
在SQL语句中,下面的代码引用某个非连接准则时,它要寻找的准则为:关系运算符是
Figure A0181182000221
而且另一个运算对象或者是一个常数或者是一个子查询。对于子查询的这种假设是,由于用户指定了
Figure A0181182000222
作为关系运算符,子查询必须返回最多一个单行,这意味着一个常数。
以下是非法WHERE子句的实例:
WHERE col1=10+col2
WHERE col1>10
以下是合法WHERE子句的实例:
WHERE col1=lO
WHERE col1=(select co12 from tabl)
WHERE col1=:Bind_Variable
F.连接准则
下面引用连接准则。在每种情况下,关系运算符都应当是 并且准则的每一侧都应当是单列的名称,而不应当是表达式。
G.子查询接口
典型情况下,外层查询和子查询之间的接口包含至少一个“关系运算符”比如“IN”、“=”、“NOT EXISTS”等等。除了EXISTS和NOT EXISTS关系运算符以外,所有关系运算符之前都是一列或多列。运算符之前的列称为“接口列”。在子查询的对应SELECT列表中的列也被称为“接口列”。根据它们是外层查询的接口列还是子查询的接口列,能够区分这两种类型的“接口列”。
这些列也可能不属于子查询之内的对象,并且不与属于子查询内表格的任何列关联,如以下代码所示:
1.SELECT*FROM employees e
2.WHERE emp_seq IN
3.    (SELECT emp_seq FROM assignments a
4.    WHERE(e.hiredate,a.proj_seq)IN
5.        (SELECT rpt_date,proj_seq FROM time_sheets t))
列“e.hiredate”(第4行)不属于子查询(ASSIGNMENTS表格),并且不与ASSIGNMENTS内的任何列关联。本文档将称外层查询的这些列为“外来的”。如果某列是外来的,系统将试图把它合并或者将它转换到一个非关联的子查询。不过,系统将不试图移动该子查询。
H.优先设置
变换SQL语句时,空逻辑会引起许多问题。如果在外层查询中特定的列可为空,变换时可能出现不同的结果集。可以对变换进行修改以确保不发生这样的情况,尽管从性能上说可能会付出某个小的代价。修改就是同某个准则进行与运算,指定该列不可为空(如列IS NOTNULL)。由于对满足原始准则的每一行,该准则必然成立,所以代价不会大。相反,在某些情况下性能还可能改善,因为这时优化器比如ORACLE的优化器就可能执行一个反连接。在下面的算法中将会引用这些优先设置。
I.别名
子查询合并或移动到FROM子句时,外层查询中的准则应当通过某个别名被完全识别,例如,参见以下的实例。
1.SELECT*FROM employees
2.WHERE emp_seq IN
3.    (SELECT emp_seq
4.    FROM time_sheets t,projects p
5.    WHERE t.rpt_date=‘01-MAY-98’
6.    AND t.proj_seq=p.proj_seq
7.    AND p.stop_date IS NULL)
8.AND hiredate>SYSDATE-10
在这个实例中,应当为EMPLOYEES增加一个别名,而且该别名应当在属于该表格的所有列之前。此外,子查询也应当给予一个别名。为EMPLOYEES增加一个“e”别名,那么变换会是:
SELECT e.*FROM employees e,
    (SELECT emp_seq
     FROM time_sheets t,projects p
     WHEERE t.rpt_date=‘01-MAY-98’
     AND t.proj_seq=p.proj_seq
     AND p.stop_date IS NULL)x
WHERE e.emp_seq=x.emp_seq
AND e.hiredate>SYSDATE- 10
如果某个子查询包含聚集,在它被移进FROM子句之前,应当给它一个别名。例如,以下的SQL语句在子查询(第3行)中包含“max”聚集函数。
1.SELECT*FROM sal_history
2.WHERE(emp_seq,effective_date)IN
3.    (SELECT emp_seq,max(effective_date)
4.    FROM sal_history
5.    GROUP BY emp_seq)
因此,该SQL语句应当进行变换,给予聚集“MAX(EFFECTIVE_DATE)”一个别名如下:
SELECT s.*FROM sal_history s,
    (SELECT emp_seq,max(effective_date)cl
    FROM sal_history
     GROUP BY emp_seq)x
WHERE s.emp_seq=x.emp_seq
AND s.effective_date=x.c1
这就产生了一个问题,是否允许用户通过隐含的知识,为已知要返回独特集合的子查询设置旗标。例如,
SELECT*FROM employees e
WHERE EXISTS
    (SELECT null FROM projects p,assignments a
    WHERE p.proj_seq=a.proj_seq
    AND a.emp_seq=e.emp_seq
    AND p.name=‘EXPLAIN_SQL’)
能够转换为
SELECT*FROM employees e
WHERE e.emp_seq IN
    (SELECT a.emp_seq FROM projects p,assignments a
    WHERE p.proj_seq=a.proj_seq
AND p.name=‘EXPLAIN_SQL’)
或者转换为
SELECT e.*FROM employees e,projects p,assignments a
WHERE e.emp_seq=a.emp_seq
AND p.proj_seq=a.proj_seq
AND p.name=‘EXPLAIN_SQL’
这两种情况都是可能的,因为子查询中低级别的表格在PROJ_SEQ和EMP_SEQ上都有PK。传递性允许我们说,因为NAME——它也有一个UNQ索引——上的等价,在PROJ_SEQ上有等价。所以,保证了子查询每一EMPLOYEES行产生一行,这表明合并是可能的。
既然已经解释了本系统所用的某些术语和概念,以下的实例就有助于介绍本系统变换SQL语句可能使用的算法。显示的实例分为关联的和非关联的子查询,并以此识别。非关联的子查询是不与主查询关联的子查询。也就是,在主查询考察任何行之前,就可以逻辑地执行非关联的子查询。换句话说,子查询与主查询独立,并且可以作为有其本身答案的一个查询而存在。与之相反,关联的子查询依赖于被主查询考察的行。
1.以下SQL语句混合了关联的和非关联的子查询。在以下的SQL语句中,最后的子查询是一个标量子查询,并且由于外层子查询对PROJ_SEQ和RPT_DATE都有等价准则,而且EMP_SEQ列在选择列表上,该子查询能够合并,尽管对SAL_HISTORY的子查询不能。对于FROM子句中的嵌套查询是否正确地识别为标量,这是一个很好的试验。
SELECT*FROM employees
WHERE emp_seq IN
    (SELECT emp_seq FROM time_sheets t
    WHERE proj_seq=
        (SELECT proj_seq FROM projects
         WHERE name=‘EXPLAIN SQL:DEVELOPMENT’)
AND rpt_date=
   (SELECT MAX(effective_date) FROM sal_history s
    WHERE s.emp_seq=t.emp_seq))
应当变换为
SELECT e.*FROM employees e,time_sheets t,projects p,
           (SELECT emp_seq, MAX(effective_date) col1 FROM sal_history s
           GROUP BY emp_seq)x
WHERE e.emp_seq=t.emp_seq
AND t.proj_seq=p.proj_seq
AND p.name=‘EXPLAIN SQL:DEVELOPMENT’
AND t.emp_seq=x.emp_seq
AND t.rpt_date=x.col1
2.以下实例是非关联的,并且与前一个实例略有不同。基本的差异是对SAL_HISTORY的子查询。在这种情况下该子查询初始确定为可能返回多行。这表明在原始查询中可能发生运行错误。这就防止了合并和移动该子查询。也就是,对SAL_HISTORY上的子查询应当保持原样。不过,由于对RPT_DATE的准则具有等价运算符,该子查询与TIME_SHEETS的合并仍然能够发生,并且仍然可能遇到同样的运行错误。换句话说,将不移动对SAL_HISTORY的子查询,因为不能保证产生标量集。不过,在能产生标量集的情况下,对准则“rpt_date=___”将产生一个单一的常数值。本系统将该子查询视为等价于一个常数,允许外层查询与其围绕的查询合并并携带着嵌套的选择。例如,以下SQL语句,
SELECT*FROM employees
WHERE emp_seq IN
    (SELECT emp_seq FROM time_sheets t
    WHERE proj_seq=
        (SELECT proj_seq FROM projects
        WHERE name=‘EXPLAIN SQL:DEVELOPMENT’)
    AND rpt_date=
            (SELECT effective_date FROM sal_history s
             WHERE sal>100)
应当变换为
SELECT e.*FROM employees e,time_sheets t,projects p
WHERE e.emp_seq=t.emp_seq
AND t.proj_seq=p.proj_seq
AND p.name=‘EXPLAIN SQL:DEVELOPMENT’
AND t.rpt_date=
            (SELECT effective_date FROM sal_history s
             WHERE sal>100)
3.以下实例是关联的,并且涉及ALL运算符。如果某个子查询不返回任何行,该准则可能取值为TRUE。这表明该子查询仅仅应当移动,并且作为外部连接而进行,其中仅有外部连接的语法仅仅应用于初始关联准则。进行比较的原始列必须不考虑连接匹配。在外部连接发生之后,对增加的最后准则进行求值。例如,以下SQL语句,
SELECT emp_seq,birthdate FROM employees e
WHERE birthdate<ALL
    (SELECT birthdate FROM dependents d
    WHERE e.emp_seq=d.emp_seq)
能够变换为
SELECT e.emp_seq,e.birthdate FROM employees e,
            (SELECT d.emp_seq,MIN(birthdate)col1,1 col2 FROM dependents d
            GROUP BY emp_seq)x
WHERE e.emp_seq=x.emp_seq(+)
AND(e.birthdate<x.col1 OR x.col2 IS NULL)
系统应当检验确定任何新的外部连接的准则是否与任何运算对象进行或运算,因为这会产生分析错误。可能需要使数据库分析中间结果以判断是否应当进行过变换。如果不应当进行过变换,那么对该子查询就不应当进行任何处理。
4.以下实例是非关联的,并且涉及具有GROUP BY语法的子查询。即使子查询具有GROUP BY子句,SELECT列表也不包含GROUP BY列表中的每一列。这表明复制的可能性不存在,除非DISTINCT关键字增加到该子查询的SELECT列表。例如,以下SQL语句,
SELECT*FROM employees
WHERE emp_seq IN
    (SELECT emp_seq FROM assignments
    GROUP BY emp_seq,proj_seq)
能够变换为
SELECT e.*FROM employees e,
            (SELECT DISTINCT a.emp_seq FROM assignments a
             GROUP BY a.emp_seq,a.proj_seq)x
WHERE e.emp_seq=x.emp_seq
5.SQL语句可能仅仅包含聚集,而不包含GROUP BY子句。所以,它不需要DISTINCT关键字。以下实例是非关联的。例如,以下SQL语句,
SELECT*FROM employees
WHERE hiredate=
    (SELECT MIN(effective_date) FROM sal_history)
能够变换为
SELECT e.*FROM employees e,
            (SELECT MIN(s.effective_date)col1 FROM sal_history s)x
WHERE e.hiredate=x.col1
6.以下实例是非关联的,并且说明了移动到外层查询时如何处理NOT IN运算符。基本要点在于,系统应当转换到外部连接,然后寻找“外部连接的行”(如子查询的选择列表上的不可空的列IS NULL(见下面的准则“x.col1 IS NULL”))。一个解救方案是向选择列表增加一个常数,比如1,因为无论个子查询是否具有GROUP BY语法,它都会起作用。例如,以下SQL语句,
SELECT emp_seq FROM employees
WHERE hiredate NOT IN
    (SELECT effective_date FROM sal_history)
能够变换为
SELECT e.emp_seq FROM employees e,
     (SELECT DISTINCT effective_date,1 col1 FROM sal_history)x
WHERE e.hiredate=x.effective_date(+)
AND x.col1 IS NULL
7.以下实例类似于上面的实例6,并且也是非关联的。不过,在这个实例中有多列连接到该子查询。此外,这些列表示外层查询中的多个表格。在这个实例中,可能会遇到一个问题,因为变换不做分析。可能会产生一个错误信息:“ORA-01417:某个表格可以外部连接到最多一个其它表格”。所以,关系运算符需要一个外部连接而连接到该子查询的列是来自多个表格时,不应当产生这条信息。例如,以下SQL语句,
SELECT e.emp_seq FROM employees e,dependents d
WHERE(e.hiredate,d.birthdate) NOT IN
    (SELECT hiredate,d1.birthdate FROM employees e1,dependents d1
    WHERE e1.emp_seq=1001
    AND e1.emp_seq=d1.emp_seq
       AND relation=‘SPOUSE’)
AND e.emp_seq=d.emp_seq
AND d.relation=‘SPOUSE’
会不正确地变换为
SELECT e.emp_seq FROM employees e,dependents d,
     (SELECT DISTINCT e1 .hiredate,d1.birthdate,1 col1 FROM employees e1,dependents d1
     WHERE e1.emp_seq=1001
     AND e1.emp_seq=d1.emp_seq
     AND d1.relation=‘SPOUSE’)x
WHERE e.emp_seq=d.emp_seq
AND d.relation=‘SPOUSE’
AND e.hiredate=x.hiredate(+)
AND d.birthdate=x.birthdate(+)
AND x.col1 IS NULL
8.以下的非关联实例提供了一种虽然奇怪却值得关注的情况。尽管这种情况在理论上很罕见,但是它能够发生。其原因在于,下面的子查询是非关联的但是却连接到带有EXISTS运算符的外层查询。一般说来,EXISTS运算符仅仅用于关联的子查询。在任何情况下,该变换都是简单的:只须把它移动到不带有连接子句的外层查询,并在子查询中增加准则“ROW NUM=1”,如下所示。例如,以下SQL语句,
SELECT*FROM employees
WHERE EXISTS
    (SELECT*FROM sal_history
    WHERE sal<0)
能够变换为
SELECT e.*FROM employees e,
     (SELECT*FROM sal_history
     WHERE sal<0
     AND ROWNUM=1)
与原始的SQL语句相比,变换后的SQL语句的性能将得到极大的改善。因为现在子查询仅仅执行一次,而不是像在原始SQL语句中执行那样每行一次。
9.以下实例是非关联的,因为子查询包含多于一个同名的列名称而列出。尽管列名称前面有表格别名,列名称还是应当给予一个别名。在外层查询的SELECT列表中的星号,也应当为了外层查询中的每个表格而复制。注意以下所示变换中下划线的项目。SQL语句,
SELECT*FROM employees e,dependents d
WHERE e.emp_seq=d.emp_seq
AND(e.birthdate,d.birthdate)IN
    (SELECT e1.birthdate,d1.birthdate FROM employees e1,dependents d1
    WHERE e1.emp_seq=d1.emp_seq
    AND e1.hiredate=SYSDATE-100)
能够变换为
SELECT  e.*.d.*FROM employees e,dependents d,
           (SELECT DISTINCT e1.birthdate  col1,d1.birthdate  col2
            FROM employees e1,dependents d1
           WHERE e1.eep_seq=d1.emp_seq
           AND e1.hiredate=SYSDATE-100)x
 WHERE e.emp_seq=d.emp_seq
 AND e.birthdate= x.col1
 AND d.birthdate= x.col2
10.以下实例是非关联的,并且说明了标量子查询和NOT IN运算符。由于子查询是标量的,它就能够与外层查询合并为一个外部连接。关键是仅仅保留“外部连接的”行。通过把子查询中带有表格非空列的准则同IS NULL运算符进行与运算,就能够做到这一点。一个更好的解决方案可能是使用行标识(见下面第二个变换)。例如,
SELECT emp_seq FROM employees
WHERE hiredate NOT IN
   (SELECT hiredate FROM employees
    WHERE emp_seq=999)
能够变换为
SELECT e.emp_seq FROM employees e,employees e1
WHERE e.hiredate=e1.hiredate(+)
AND e1.emp_seq(+)=999
AND e1.emp_seq IS NULL
或者变换为
SELECT e.emp_seq FROM employees e,employees e1
WHERE e.hiredate=e1.hiredate(+)
AND e1.emp_seq(+)=999
AND e1.rowid IS NULL
11.以下的关联实例既包含关联准则,又包含非连接准则。由于该子查询保证唯一性,所以该子查询能够合并。例如,以下SQL语句,
SELECT*FROM employees e
WHERE EXISTS
    (SELECT*FROM projects p,assignments a
    WHERE p.proj_seq=a.proj_seq
    AND e.emp_seq=a.emp_seq
    AND p.name=‘EXPLAIN SQL:DEVELOPMENT’)
能够变换为
SELECT e.*FROM employees e,projects p,assignments a
WHERE p.proj_seq=a.proj_seq
AND e.emp_seq=a.emp_seq
AND p.name=‘EXPLAIN SQL:DEVELOPMENT’
12.以下的关联实例不同,因为SELECT列表包含不返回外层查询的列。(事实上,如果在前面一个实例11中的子查询具有选择列表中的项目,变换也将会恰恰如此。注意,在前面一个实例11中,子查询选择列表上的星号不起作用。)例如,
SELECT*FROM employees e
WHERE EXISTS
    (SELECT relation FROM dependents d
    WHERE e.emp_seq=d.emp_seq)
能够变换为
SELECT e.*FROM employees e,
            (SELECT DISTINCT emp_seq FROM dependents d)x
WHERE e.emp_seq=x.emp_seq
13.这个关联的实例与前一个实例不同,因为SELECT列表列具有外层查询中的对应列。例如,
SELECT*FROM sal_history s1
WHERE effective date>
    (SELECT MAX(effective_date) FROM sal_history s2
    WHERE s1.emp_seq=s2.emp_seq)
能够变换为
SELECT s1.*FROM sal_history s1,
            (SELECT emp_seq,MAX(effectiw_date) col1 FROM sal_history s2
             GROUP BY emp_seq)x
WHERE s1.emp_seq=x.emp_seq
AND s1.effective_date>x.col1
14.以下的非关联实例说明了通过NOT EXISTS运算符连接的非关联子查询。例如,
SELECT*FROM employees
WHERE NOT EXISTS (SELECT*FROM dependents)
能够变换为
SELECT e.*FROM employees e,
    (SELECT count(*) col1 FROM dependents WHERE ROWNUM=1)x
WHERE x.col1=0
注意,原始子查询的SELECT列表改变为“COUNT(*)”,并且子查询增加了“ROWNUM=1”准则。
15.以下的非关联实例类似于前一个实例14,只是该子查询包含GROUP BY。变换也类似于前一个实例14。例如,
SELECT*FROM employees
WHERE NOT EXISTS
   (SELECT null FROM sal_history
    GROUP BY emp_seq)
能够变换为
SELECT e.*FROM employees e,
    (SELECT count(*) col1 FROM sal_history
    WHERE ROWNUM=1
    GROUP BY emp_seq)x
WHERE x.col1=0
在子查询的SELECT列表中的任何内容,都交换为“COUNT(*)”。
16.以下是一个使用NOT EXISTS运算符的关联实例。例如,
SELECT emp_seq FROM employees e
WHERE NOT EXISTS
    (SELECT*FROM sal_history s
     WHERE e.emp_seq=s.emp_seq
     AND effective_date=SYSDATE)
能够变换为
SELECT e.emp_seq FROM employees e,sal_history s
WHERE e.emp_seq=s.emp_seq(+)
AND effective_date(+)=SYSDATE
AND s.emp_seq IS NULL
17.以下的关联实例说明了以IN运算符连接的集合子查询。例如,
SELECT*FROM sal_history s1
WHERE effective date IN
    (SELECT effective_date FROM sal_history s2
    WHERE s1.emp_seq=s2.emp_seq
    AND sal>100)
能够变换为
SELECT s1.*FROM sal_history s1,sal_history s2
WHERE s1.effective_date=s2.effective_date
AND s1.emp_seq=s2.emp_seq
AND s2.sal>100
18.以下的非关联实例说明了<ALL运算符。例如,
SELECT*FROM employees
WHERE hiredate<ALL
   (SELECT hiredate FROM employees
    WHERE birthdate>‘01-JAN-87’)
能够变换为
SELECT e.*FROM employees e,
    (SELECT MIN(hiredate) col1 FROM employees
    WHERE birthdate>‘01-JAN-87’)x
WHERE (hiredate<x.col1 OR x.col1 IS NULL)
注意变换中“x.col1 IS NULL”的使用。其要点在于,聚集函数总会返回一个值,即使没有一行符合准则。由于子查询结果为空集时ALL运算符永远取值TRUE,系统应当仍然返回外层查询中的行。
19.以下的非关联实例类似于前一个实例18。不过在这个实例中使用>ALL运算符而不是<ALL运算符。例如,
SELECT*FROM employees
WHERE hiredate>ALL
    (SELECT hiredate FROM employees
    WHERE birthdate>‘01-JAN-77’)
能够变换为
SELECT e.*FROM employees e,
    (SELECT MAX(hiredate) col1 FROM employees
    WHERE birthdate>‘01-JAN-77’)x
WHERE (hiredate>x.col1 OR x.col1 IS NULL)
20.以下的非关联实例包括了可合并的集子查询。例如,
SELECT*FROM employees
WHERE emp_seq NOT IN
    (SELECT emp_seq FROM sal_history
    WHERE effective_date=‘5-JUL-98’)
能够变换为
SELECT e.*FROM employees e,sal_history s
WHERE e.emp_seq=s.emp_seq(+)
AND effective_date(+)=‘5-JUL-98’
AND s.emp_seq IS NULL
21.以下的关联实例类似于前一个实例20,只是它是关联的。这个实例说明了如何把外部连接语法增加到关联准则。例如,
SELECT*FROM assignments a
WHERE start_date NOT IN
    (SELECT effective_date FROM sal_history s
    WHERE a.emp_seq=s.emp_seq)
能够变换为
SELECT a.*FROM assignments a,sal_history s
WHERE a.start_date=s.effective_date(+)
AND a.emp_seq=s.emp_seq(+)
AND s.emp_seq IS NULL
22.以下的非关联实例类似于前一个实例21。不过在这个实例中,子查询有多个表格。下面的实例说明了如何合并到外层查询时,如何把外部连接语法放置到子查询之内的连接准则上。例如,
SELECT*FROM status_list
WHERE status s NOT IN(SELECT p.status
    FROM projects p,assignments a
    WHERE a.proj_seq=p.proj_seq
    AND p.name=‘EXPLAIN SQL:DEVELOPMENT’)
能够变换为
SELECT s.*FROM status_list s,projects p,assignments a
WHERE s.status=p.status(+)
AND p.name(+)=‘EXPLAIN SQL:DEVELOPMENT’
AND a.proj_seq(+)=p.proj_seq
AND a.ROWID IS NULL
在子查询中,在刚刚连接的表格上保证了唯一性(在这种情况下是别名“p”,因为p.name是唯一的)。以连接的次序,最多一个最低的子级能够非唯一,在这种情况下是别名“a”。连接次序是别名“s”,然后是“p”,然后是“a”。
23.以下的关联实例可能颇为复杂。由于NOT IN运算符,它应当是外部连接。不过,问题是别名“e”和“a”都与子查询关联。因为子查询只包含一个表格,子查询应当是可合并的,所以我们无须保证唯一性。例如,
SELECT*FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq
AND e.emp_seq NOT IN
(SELECT t.emp_seq FROM time_sheets t
WHERE a.proj_seq=t.proj_seq
AND t.rpt_date=‘20-FEB-94’)
由于关联准则,该子查询既不能合并,也不能移动。如果子查询的关联准则和接口列引用外层查询中的多于一个表格,该子查询能够跳过。在这种情况下,一个关联准则引用别名“a”,外层查询的接口引用“e.emp_seq”。若是系统要变换该子查询,变换就会以TIME_SHEETS被外部连接到多于一个表格而结束,而这是非法的。因此,以上SQL语句会不正确地合并到:
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND e.emp_seq=t.emp_seq(+)
AND a.proj_seq=t.proj_seq(+)
AND t.rpt_date(+)=‘20-FEB-94’
AND t.emp_seq IS NULL
并被不正确地移动到
SELECT*FROM employees e, assignments a,
     (SELECT t.emp_seq,t.proj_seq,1 col1 FROM time sheets t
     WHERE t.rpt_date=‘20-FEB-94’)x
WHERE e.emp_seq=a.emp_seq
AND e.emp_seq=x.emp_seq(+)
AND a.proj_seq=x.proj_seq(+)
AND x.col1 IS NULL
这种两种情况都会造成非法的外部连接,所以应当避免。
24.这个关联的实例类似于上面的实例23。通过传递性,对于以下的原始语句,系统能够变换原始语句,如实例23所示,然后执行变换,因此消除了实例23中遇到的限制。
例如,实例23中的原始语句能够变换为:
SELECT*FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq
AND a. emp_seq NOT IN
   (SELECT t.emp_seq FROM time_sheets t
   WHERE a. proj_seq=t.proj_seq
   AND t.rpt_date=‘20-FEB-94’)
它又可变换为
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq(+)
AND a.proj_seq=t.proj_seq(+)
AND t.rpt_date(+)=‘20-FEB-94’
AND t.emp_seq IS NULL
25.以下的关联实例涉及标量运算符“=”。这个实例显示了如何使用子查询中的传递性来确定子查询是标量的;如“e.emp_seq=t.emp_seq=a.emp_seq”。例如,
SELECT*FROM time_sheets t,projects p
WHERE t.proj_seq=p.proj_seq
AND t.rpt_date=
      (SELECT hiredate FROM employees e,assignments a
      WHERE a.proj_seq=p.proj_seq
      AND e.emp_seq=a.emp_seq
      AND e.emp_seq=t.emp_seq)
能够变换为
SELECT*FROM time_sheets t,projects p,employees e,assignments a
WHERE t.proj_seq=p.proj_seq
AND t.rpt_date=e.hiredate
AND a.proj_seq=p.proj_seq
AND e.emp_seq=t.emp_seq
AND e.emp_seq=a.emp_seq
26.以下的关联实例涉及集合运算符“IN”。例如,
SELECT*FROM employees e
WHERE emp_seq IN
    (SELECT a.emp_seq FROM assignments a,time_sheets t
    WHERE a.emp_seq=t.emp_seq
    AND a.proj_seq=t.proj_seq
    AND a.proj_seq=1
    AND t.rpt_date=‘20-FEB-94’)
可以变换为
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq
AND a.proj_seq=t.proj_seq
AND a. proj_seq=1
AND t.rpt_date=‘20-FEB-94’
27.以下的关联实例显示了虽然关联准则涉及子查询中多于一个表格,还是可能合并的情况。在这种情况下,“t.”通过接口把“e.”连接到子查询;然后“t.”通过PROJ_SEQ列与“a.”关联。能够应用传递性,所以“t”既通过PROJ_SEQ又通过EMP_SEQ与“a”关联。此外,连接时对“e”和“a”保证了唯一性。例如,
SELECT*FROM time_sheets t
WHERE t.rpt_date NOT IN
    (SELECT hiredate FROM employees e,assignments a
    WHERE a.proj_seq=t.proj_seq
    AND e.emp_seq=a.emp_seq
    AND e.emp_seq=t.emp_seq)
能够变换为
SELECT t.*FROM time_sheets t,employees e,assignments a
    WHERE t.rpt_date=e.hiredate(+)
    AND t.emp_seq=e.emp_seq(+)
    AND t.proj_seq=a.proj_seq(+)
    AND t.emp_seq=a.emp_seq(+)
    AND (a.emp_seq IS NULL OR e.emp_seq IS NULL)
由于“a”和“e”是分别连接“t”的,系统需要对每个表格的不可空列增加IS NULL,并把它们用或连在一起。
28.以下的关联实例说明了带有GROUP BY子句的子查询中SELECT列表上的聚集。例如,
SELECT*FROM sal_history s
WHERE effective_date IN
    (SELECT MAX(start_date) FROM assignments a
    WHERE s.emp_seq=a.emp_seq
    GROUP BY proj_seq)
能够变换为
SELECT*FROM sal_history s,
    (SELECT DISTINCT.emp_seq,MAX(start_date)col1 FROM assignments a
     GROUP BY proj_seq,emp_seq)x
WHERE s.emp_seq=x.emp_seq
AND effective_date=x.col1
29.以下的非关联实例说明了子查询移动时把聚集变换为聚集的聚集。例如,
SELECT*FROM assignments a
WHERE start_date<ANY
    (SELECT MIN(rpt_date)FROM time_sheets
GROUP BY proj_seq)
能够变换为
SELECT*FROM assignments a,
    (SELECT MAX(MIN(rpt_date))col1 FROM time_sheets
    GROUP BY proj_seq)x
WHERE a.start_date<x.col1
30.以下的关联实例说明了,通过像是“<ANY”的运算符连接的子查询不能变换。例如,
SELECT*FROM assignments a
WHERE start_date<ANY
   (SELECT MIN(rpt_date)FROM time_sheets t
    WHERE a.emp_seq=t.emp_seq
    GROUP BY proj_seq)
会不正确地变换为
SELECT*FROM assignments a,
    (SELECT emp_seq,MIN(rpt_date)col1 FROM time_sheets t
    GROUP BY proj_seq,emp_seq)x
WHERE a.start_date<x.col1
AND a.emp_seq=x.emp_seq
这种变换是不正确的,因为子查询仍然是一个集合,而不是所需要的标量,如每EMP_SEQ,由于PROJ_SEQ的成组作用,仍然可能有许多MIN(rpt_date)值。就算该子查询不具有GROUP BY子句,该变换也仍然不是毫无问题的,因为该变换会需要把关联列放到SELECT列表上并进行聚集以及聚集的聚集。
虽然原始的GROUP BY列既不与HAVING子句关联,又不是它的一部分,系统也不能摆脱它。
例如,该查询可能会不正确地变换为
SELECT e.*FROM employees e,
    (SELECT emp_seq,MAX(rpt_date)col1 FROM time_sheets t
    GROUP BY t.emp_seq)x
WHERE e.emp_seq=x.emp_seq
AND e.hiredate<x.col1
以上变换是不正确的,因为对于同样的PROJ_SEQ,可能会由某个rpt_date小于e.hiredate,而另一个rpt_date大于e.hiredate。在原始的查询中,带有MIN(rpt_date)的子查询将返回行中的第一个数据。不过,在以上的查询中,该子查询将返回最大值。
31.以下的关联实例是一个极好的实例,因为关联准则使用“<”运算符而不是“=”运算符,其中的子查询不能移动。例如,
SELECT*FROM sal_history s1,employees e
WHERE e.emp_seq=s1.emp_seq
AND s1.effective_date=
   (SELECT MIN(s2.effective_date)
   FROM sal_history s2
   WHERE e.emp_seq=s2.emp_seq
   AND e.hiredate<s2.effective_date)
会不正确地变换为
SELECT*FROM sal_history s1,employees e,
     (SELECT s2.emp_seq,s2.effective_date,MIN(s2.effective_date)col1
     FROM sal_history s2
     GROUP BY s2.emp_seq,s2.effective_date)x
WHERE e.emp_seq=x.emp_seq
AND s1.effective_date=x.col1
AND e.hiredate<x.effective_date
进行正确变换的一种方法可能是,将不等关联中涉及的表格移动到子查询中,如下所示:
SELECT*FROM sal_history s1,
    (SELECT e.emp_seq,MIN(s2.effective_date)col1
    FROM sal_history s2,employees e
    WHERE e.emp_seq=s2.emp_seq
    AND e.hiredate<s2.effective_date
    GROUP BY e.emp_seq)x
WHERE s1.emp_seq=x.emp_seq
AND s1.effective_date=x.col1
这种解决方案是将EMPLOYEES表格移动到子查询中,然后移动子查询。
32.以下的关联实例是一个不带聚集的标量子查询。例如,
SELECT*FROM sal_history s
WHERE effective_date=
    (SELECT hiredate FROM employees e
    WHERE s.emp_seq=e.emp_seq)
能够变换为
SELECT s.*FROM sal_history s,employees e
WHERE s.effective_date=e.hiredate
AND s.emp_seq=e.emp_seq
33.以下的关联实例类似于前一个实例32。不过,在这个实例中在并非唯一关键字一部分的列上有另外的关联准则。处理关联的子查询时这可能是重要的;也就是对子查询的PK或UNQ关键字的关联准则应当使用“=”运算符,而另外的关联准则使用的运算符则无关紧要。在这种情况下,关联准则“t.rpt_date>=a.start_date”不是唯一关键字的一部分。例如,
SELECT*FROM time_sheets t
WHERE rpt_date<
   (SELECT stop_date FROM assignments a
    WHERE a.emp_seq=t.emp_seq
    AND a.proj_seq=t.proj_seq
    AND t.rpt_date>=a.start_date)
能够变换为
SELECT t.*FROM time_sheets t,assignments a
WHERE t.rpt_date<a.stop_date
AND a.emp_seq=t.emp_seq
AND a.proj_seq=t.proj_seq
AND t.rpt_date>=a.start_date
34.以下的关联实例使用了标量运算符来连接标量子查询,其中由于聚集和没有GROUP BY子句,子查询是标量的。例如,
SELECT*FROM employees e
WHERE hiredate>
    (SELECT MIN(effective_date)FROM sal_history s
    WHERE e.emp_seq=s.emp_seq)
能够变换为
其中
SELECT e.*FROM employees e,
    (SELECT emp_seq,MIN(effective_date)col1 FROM sal_history s
    GROUP BY emp_seq)x
WHERE e.emp_seq=x.emp_seq
AND e.hiredate>x.col1
35.以下的关联实例说明了HAVING子句中的关联。解决方案是,HAVING子句变为外层查询中的准则,在关联准则中比较的局部项目应当出现在子查询的SELECT列表中。应当注意,另一个要校验的语法将是子查询没有GROUP BY子句,但确实具有HAVING子句。例如,
SELECT*FROM employees e
WHERE NOT EXISTS
    (SELECT a.proj_seq FROM assignments a,time_sheets t
    WHERE a.proj_seq=t.proj_seq
    AND a.emp_seq=t.emp_seq
    AND e.emp_seq=a.emp_seq
    GROUP BY a.proj_seq
    HAVING MIN(t.rpt_date)<e.hiredate)
能够转换为
SELECT*FROM employees e,
    (SELECT a.proj_seq,a.emp_seq,MIN(t.rpt_date)col1,1 col2
    FROM assignments a,time_sheets t
    WHERE a.proj_seq=t.proj_seq
    AND a.emp_seq=t.emp_seq
    GROUP BY a.proj_seq,a.emp_seq)x
WHERE e.emp_seq=x.emp_seq(+)
AND x.col1<e.hiredate(+)
AND x.col2 IS NULL
36.以下是一个关联的实例,其中运算符是NOT IN运算符,并且有不等关联准则。系统应当注意,它不必把EMP_SEQ列的另一个拷贝移动到GROUP BY子句上,因为它已经在那里了。例如,
SELECT*FROM sal_history s1
WHERE s1.sal NOT IN
(SELECT MIN(sal) FROM sal_history s2
WHERE s1.emp_seq!=s2.emp_seq
AND s1.effective_date=s2.effective_date
GROUP BY emp_seq)
能够变换为
SELECT s1.*FROM sal_history s1,
   (SELECT emp_seq,effective_date,MIN(sal)col1,1 col2
    FROM sal_history s2
    GROUP BY emp_seq,effective_date)x
WHERE s1.sal=x.col1(+)
AND s1.emp_seq!=x.emp_seq(+)
AND s1.effective_date=x.effective_date(+)
AND x.col2 IS NULL
order by s1.emp_seq,s1.effective_date
37.以下的关联实例类似于上面的实例30,只不过在实例30中子查询不具有聚集。虽然这个查询可能不实际,这个实例用于说明,带有GROUP BY的子查询为什么不应当对于任何的ANY、SOME或ALL运算符移动。例如,
SELECT*FROM assignments a
WHERE start_date<ALL
    (SELECT rpt_date FROM time_sheets t
    WHERE a.emp_seq=t.emp_seq
    GROUP BY rpt_date
    HAVING COUNT(*)>1)
会不正确地变换为
SELECT a.*FROM assignments a,
    (SELECT MIN(rpt_date)col1,emp_seq,1 col2 FROM time_sheets t
    WHERE a.emp_seq=t.emp_seq
    GROUP BY rpt_date,emp_seq
    HAVING COUNT(*)>1)x
WHERE(start_date<x.col1 OR x.col2 IS NULL)
AND a.emp_seq=x.emp_seq(+)
问题在于,对于外层查询,已经有了RPT_DATE的组合,而且没有连接准则。因此,我们需要标量时,对EMP_SEQ我们就以每个连接一个集合而结束。
38.以下的关联实例说明了由于不等关联准则,ANY、SOME或ALL子查询不能移动的情况。要移动,应当确保最多一行与原始外层查询进行比较。不过,对于该变换中的不等连接准则,可以连接多行。例如,
SELECT*FROM sal_history s1
WHERE sal<ANY
    (SELECT sal FROM sal_history s2
    WHERE s1.emp_seq!=s2.emp_seq
    AND s1.effective_date=s2.effective_date)
会不正确地变换为
SELECT s1.*FROM sal_history s1,
    (SELECT emp_seq,effective_date,MAX(sal)col1 FROM sal_history s2)x
WHERE s1.sal<x.col1
AND s1.emp_seq!=x.emp_seq
AND s1.effective_date=x.effective_date
39.以下是一个带有“>ALL”运算符的关联实例。这个实例类似于上面的实例3,只不过这个实例使用MAX函数而不是MIN函数。例如,
SELECT emp_seq,birthdate FROM employees e
WHERE birthdate>ALL
    (SELECT birthdate FROM dependents d
    WHERE e.emp_seq=d.emp_seq)
能够变换为
SELECT e.emp_seq,e.birthdate FROM employees e,
           (SELECT d.emp_seq,MAX(birthdate)col1,1 col2 FROM dependents d
            GROUP BY emp_seq)x
WHERE e.emp_seq=x.emp_seq(+)
AND(e.birthdate>x.col1 OR x.col2 IS NULL)
40.以下的关联实例说明了“<ANY”运算符。<ANY和“>ANY”运算符之间的唯一差异是MAX变为MIN。例如,
SELECT*FROM sal_history s1
WHERE emp_seq=1001
AND sal<ANY
   (SELECT sal FROM sal_history s2
   WHERE s1.emp_seq=s2.emp_seq
   AND s1.effective_date=s2.effective_date)
能够变换为
SELECT s1.*FROM sal_history s1,
    (SELECT emp_seq,effective_date,MAX(sal)col1 FROM sal_history s2
    GROUP BY emp_seq,effective_date) x
WHERE emp_seq=1001
AND s1.sal<x.col1
AND s1.emp_seq=x.emp_seq
AND s1.effective_date=x.effective_date
41.以下的关联实例说明了标量运算符“=”。例如,
SELECT * FROM employees e
WHERE hiredate=
    (SELECT MIN(effective_date) FROM sal_history s
    WHERE e.emp_seq=s.emp_seq)
能够变换为
SELECT e.*FROM employees e,
    (SELECT emp_seq,MIN(effective_date)col1 FROM sal_history s
    GROUP BY emp_seq)x
WHERE hiredate=x.col1
AND e.emp_seq=x.emp_seq
42.以下的关联实例说明了EXISTS运算符,其中子查询包含HAVING子句但是没有GROUP BY和聚集。这里的要点在于在HAVING子句之前增加GROUP BY子句。例如,
SELECT*FROM employees e
WHERE EXISTS
    (SELECT null FROM sal_history s
    WHERE e.emp_seq=s.emp_seq
    HAVING COUNT(*)>1)
能够变换为
SELECT e.*FROM employees e,
    (SELECT emp_seq FROM sal_history s
     GROUP BY emp_seq
    HAVING COUNT(*)>1)x
WHERE e.emp_seq=x.emp_seq
43.这个关联的实例类似于前面的实例42,其中有HAVING子句。不过,在这个实例中也存在GROUP。例如,
SELECT*FROM employees e
WHERE EXISTS
    (SELECT null FROM sal_history s
    WHERE e.emp_seq=s.emp_seq
    GROUP BY effective_date
HAVING COUNT(*)>1)
能够变换为
SELECT e.*FROM employees e,
    (SELECT DISTINCT emp_seq FROM sal_history s
    GROUP BY effective_date,emp_seq
    HAVING COUNT(*)>1)x
WHERE e.emp_seq=x.emp_seq
44.以下的非关联实例说明了由于EXISTS运算符子查询不能移动的情况。其理由是这种解决方法向子查询增加“ROWNUM=1”准则。不过,HAVING子句能够使检索到的唯一行失去资格。在这个实例中,应当至少有两行合格,否则子查询返回空集。例如,
SELECT*FROM employees e
WHERE EXISTS
    (SELECT null FROM sal_history s
     HAVING COUNT(*)>1)
会不正确地变换为
SELECT*FROM employees e,
    (SELECT null FROM sal_history s
    WHERE ROWNUM=1
    HAVING COUNT(*)>1)
45.下一个关联的实例说明了与上面多个级别关联的子查询。包括这个实例是因为在上一节中,“限制”表明不应当试图转换这些类型的关联子查询。其理由是它们相对比较复杂,尽管还是可能的,如下面所示。例如,
SELECT*FROM employees e
WHERE EXISTS
    (SELECT null FROM assignments a
    WHERE a.emp_seq=e.emp_seq
    AND EXISTS
        (SELECT null FROM time_sheets t
        WHERE temp_seq=e.emp_seq
        AND t.proj_seq=a.proj_seq))
能够首先变换为
SELECT e.*FROM employees e
WHERE EXISTS
    (SELECT null FROM assignments a,
            (SELECT DISTINCT emp_seq,proj_seq FROM time_sheets t)x1
    WHERE a.emp_seq=e.emp_seq
    AND x1.emp_seq=e.emp_seq
    AND x1.proj_seq=a.proj_seq)
再变换为
SELECT e.*FROM employees e,
     (SELECT DISTINCT a.emp_seq col1,x1.emp_seq col2 FROM assignments a,
             (SELECT DISTINCT emp_seq,proj_seq FROM time_sheets t)x1
    WHERE x1.proj_seq=a.proj_seq)x2
WHERE x2.col1=e.emp_seq
AND x2.col2=e.emp_seq
第一个变换相对比较简单。子查询也许不能合并,所以就移动它。这需要SELECT列表中的DISTINCT关键字,加上曾经是要移动到SELECT列表之关联准则一部分的局部列。此外,关联的准则会移动到外层查询。
第二个变换稍微复杂一点,因为现在有来自子查询不同的局部表格的两列,它们曾经具有相同的名称,但是曾经与外层查询关联。这表明它们移动到SELECT列表时必须给这些列独特的别名。然后系统只需把关联的准则移动到外层查询。
为了更好地优化这一点,系统在移动之前应当注意准则的传递性。例如,我们有“a.emp_seq=e.emp_seq”,也有“x1.emp_seq=e.emp_seq”。这等价于说“a.emp_seq=x1.emp_seq”。理解了这一点,就会使子查询中的连接效率更高,并会得出:
SELECT e.*FROM employees e,
    (SELECT DISTINCT a.emp_seq col1,x1.emp_seq col2 FROM assignments a,
          (SELECT DISTINCT emp_seq,proj_seq FROM time_sheets t)x1
     WHERE x1.proj_seq=a.proj_seq
     AND a.emp_seq=x1.emp_seq) x2
WHERE x2.col1=e.emp_seq
AND x2.col2=e.emp_seq
46.OR运算符被视为子查询的父级。以下的实例说明了转换为一个连接将产生错误的答案。例如,
SELECT count(*) FROM employees
WHERE hiredate>‘01-jan-97’
OR emp_seq IN(SELECT emp_seq FROM sal_history
           WHERE sal>100)
如果不考虑OR,转换将是:
SELECT count(*)
FROM employees e,(SELECT DISTINCT emp_seq FROM sal_history WHERE sal>100)x
WHERE hiredate>‘01-jan-97’
OR e.emp_seq=x.emp_seq
看到这个问题的一种方法是现在把OR转换为一个UNION ALL,如下所示:
SELECT count(*)
FROM employees e,(SELECT DISTINCT emp_seq FROM sal_history WHERE sal>100)x
WHERE hiredate>‘01-jan-97’
    UNION ALL
SELECT count(*)
FROM employees e,(SELECT DISTINCT emp_seq FROM sal_history WHERE sal>100)x
WHERE hiredate>‘01-jan-97’
47.以下的实例涉及OR运算中的关联准则。如果关联准则在OR运算中,就不可能转换为外部连接,并且转换为NOT IN也很复杂。例如,
SELECT*FROM employees e
WHERE NOT EXISTS (SELECT*FROM sal_history s
                 WHERE s.effective_date=e.birthdate
                 OR s.effective_date=e.hiredate)
如果转换为NOT,系统应当做以下工作:
SELECT*FROM employees e
WHERE birthdate NOT IN (SELECT effective_date FROM sal_history s)
OR hiredate NOT IN(SELECT effective_date FROM sal_history s)
如果因为会产生不可分析的语法而不可能转换为外部连接:
SELECT e.*FROM employees e,(SELECT DISTINCT effective_date FROM sal_history)x
WHERE e.birthdate=x.effective_date(+)
OR e.hiredate=x.effective_date(+)
48.以下的实例说明了原始子查询可能产生空集时NOT IN到NOT EXISTS的变换。为了展示的目的,人为地强制子查询产生一个空集。例如,
SELECT*FROM employees
WHERE hiredate NOT IN
    (SELECT effective_date FROM sal_history
    WHERE 1=2)
应当变换如下以确保产生同样的结果集:
SELECT*FROM employees e
WHERE NOT EXISTS
   (SELECT*FROM sal_history s
   WHERE 1=2
    AND e.hiredate=s.effective_date)
AND (e.hiredate IS NOT NULL
     OR
     NOT EXISTS(SELECT*FROM sal_history
                 WHERE 1=2)
不过,这种解决方法的一个问题是我们又回到了原始状态。
49.以下的关联实例说明了带有与外层查询关联的聚集的HAVING子句。例如,
SELECT*FROM projects p
WHERE EXISTS
    (SELECT null FROM time_sheets t
    WHERE t.proj_seq=p.proj_seq
     GROUP BY emp_seq
     HAVING MIN(t.rpt_date)=p.start_date)
这种变换可能需要移动聚集和关联列到SELECT列表,如下所示:
SELECT*FROM projects p,
     (SELECT proj_seq,MIN(rpt_date)col1 FROM time_sheets
     GROUP BY emp_seq,proj_seq)x
WHERE p.proj_seq=x.proj_seq
AND p.start_date=x.col1
50.以下的关联实例展示了与NOT IN的合并。注意,变换中增加的准则包含了连接到外层查询的子查询表格的ROWID。使用别名“t”而不是“a”的ROWID这一点很重要,因为“t”是连接次序中最低级别的子级,“e”外部连接到“a”,然后“a”外部连接到“t”。例如,
SELECT emp_seq FROM employees e
WHERE e.hiredate NOT IN
    (SELECT start_date FROM assignments a,time_sheets t
    WHERE e.emp_seq=a.emp_seq
    AND a.emp_seq=t.emp_seq
    AND a.proj_seq=t.proj_seq
    AND t.rpt_date=‘01-jan-87’
    AND a.proj_seq=1)
能够变换为
SELECT e.emp_seq FROM employees e,assignments a,time_sheets t
WHERE e.hiredate=a.start_date(+)
AND e.emp_seq=a.emp_seq(+)
AND a.emp_seq=t.emp_seq(+)
AND a.proj_seq=t.proj_seq(+)
AND t.rpt_date(+)=‘01-jan-87’
AND a.proj_seq(+)=1
AND t.ROWID is null
51.以下的关联实例类似于前一个实例50,只不过子查询的接口列与子查询中关联表格不相同。例如START_DATE属于ASSIGNMENTS,但是T.EMP_SEQ关联却属于一个不同的表格。如果使用传递性,因为T和A之间的连接准则,我们可以把T.EMP_SEQ转换到A.EMP_SEQ。例如,
SELECT emp_seq FROM employees e
WHERE e.hiredate NOT IN
    (SELECT start_date FROM assignments a,time_sheets t
    WHERE e.emp_seq=t.emp_seq
    AND a.emp_seq=t.emp_seq
    AND a.proj_seq=t.proj_seq
    AND t.rpt_date=‘01-jan-87’
    AND a.proj_seq=1)
首先增加传递性以产生
SELECT emp_seq FROM employees e
WHERE e.hiredate NOT IN
    (SELECT start_date FROM assignments a,time_sheets t
    WHERE e.emp_seq=a.emp_seq
    AND a.emp_seq=t.emp_seq
    AND a.proj_seq=t.proj_seq
    AND t.rpt_date =‘01-jan-87’
    AND a.proj_seq=1)
然后,我们就有了与前一个实例50相同的查询,这说明发生了同样的变换。
52.这个关联的实例类似于实例50,只不过现在子查询中对应于接口列的表格是TIME_SHEETS。唯一的差异在于,EMPLOYEES外部连接到TIME_SHEETS,然后TIME_SHEETS外部连接到ASSIGNMENTS。所以,增加的准则使用ASSIGNMENTS表格的ROWID,而不是像在实例50中的TIME_SHEETS表格。例如,
SELECT emp_seq FROM employees e
WHERE e.hiredate NOT IN
    (SELECT rpt_date FROM assignments a,time_sheets t
    WHERE e.emp_seq=t.emp_seq
    AND a.emp_seq=t.emp_seq
    AND a.proj_seq=t.proj_seq
    AND t.proj_seq=1)
能够变换为
SELECT e.emp_seq FROM employees e,assignments a,time_sheets t
WHERE e.hiredate=t.rpt_date(+)
AND e.emp_seq=t.emp_seq(+)
AND t.emp_seq=a.emp_seq(+)
AND t.proj_seq=a.proj_seq(+)
AND t.proj_seq(+)=1
AND a. ROWID is null
53.以下的关联实例说明了一个聚集的聚集不是一种可能的转换。例如,
SELECT*FROM projects p
WHERE stop_date IN
    (SELECT MAX(MIN(rpt_date))FROM time_sheets t
    WHERE t.proj_seq=p.proj_seq
     GROUP BY emp_seq
     HAVING MIN(t.rpt_date)=p.start_date)
会不得不错误地转换为
SELECT * FROM projects p,
    (SELECT proj_seq,MIN(rpt_date)col1,MAX(MIN(rpt_date))col2 FROM time_sheets t
    GROUP BY emp_seq,proj_seq)x
WHERE p.proj_seq=x.proj_seq
AND p.start_date=x.col1
AND p.stop_date=x.col2
不过,这样的SQL将不会编译,所以应当避免。
54.以下的关联实例说明了一个不等关联准则,以及聚集不是一种可能的转换。例如,
SELECT * FROM assignments a
WHERE a.emp_seq IN
    (SELECT emp_seq FROM time_sheets t
     WHERE t.proj_seq=a.proj_seq
     AND a.start_date>t.rpt_date
     GROUP BY emp_seq
     HAVING MAX(rpt_date)<a.stop_date)
会错误地变换为
SELECT*FROM assignments a,
    (SELECT emp_seq,proj_seq,rpt_date,MAX(rpt_date)col1 FROM time_sheets t
    WHERE t.proj_seq=a.proj_seq
    AND a.start_date>t.rpt_date
    GROUP BY emp_seq,proj_seq,rpt_date,)x
WHERE a.emp_seq=x.emp_seq
AND a.proj_seq=x.proj_seq
AND a.start_date>x.rpt_date
AND a.stop_date>x.col1
这里的问题在于,由于不等准则“a.start_date>t.rpt_date”,T.RPT_DATE将不得不移动到SELECT列表以及GROUP BY。不过,聚集也不能移动到SELECT列表,因为它将包含错误的组。事实上,现在MAX将等于RPT_DATE。
55.以下的关联实例也说明了一个聚集的聚集不是一种可能的转换。例如,
SELECT*FROM assignments a
WHERE a.stop_date IN
    (SELECT MAX(MIN(rpt_date))FROM time_sheets t
    WHERE t.proj_seq=a.proj_seq
    GROUP BY emp_seq)
会错误地变换为
SELECT*FROM assignments a,
    (SELECT proj_seq,MAX(MIN(rpt_date))col1 FROM time_sheets t
    GROUP BY emp_seq,proj_seq)x
WHERE a.stop_date=x.col1
AND a.proj_seq=x.proj_seq
问题在于,你不能在SELECT列表中具有标量和聚集。
最优化
以下进一步列出系统或用户选定了最优化模式之后,本系统通过产生另外的SQL语句,用来优化SQL语句的方法。最优化目标的线索应当包括在每个SQL语句变换中。系统将确定非连接准则中的所有传递性,确定所有连接次序以及确定所有的不同子查询变换。
非连接传递性
简要地看一看以下的查询,
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq
AND a.proj_seq=t.proj_seq
AND e.emp_seq IN(SELECT emp_seq FROM dependents
              WHERE relation=′SPOUSE′)
在这个实例中,DEPENDENTS子查询的准则可以连接到“a.emp”或“t.emp_seq”,正如同原始的 e.emp_seq”一样。其它系统不会理解这一点。通过转换到“a.emp seq”,本系统允许数据库使用ASSIGNMENTS上的连接键索引。
另一种变换会是把“e.emp_seq”改变为“a.emp_seq”(第5行),如下所示:
1  SELECT*FROM employees e,assignments a,time_sheets t
2  WHERE e.emp_seq=a.emp_seq
3  AND a.emp_seq=t.emp_seq
4  AND a.proj_seq=t.proj_seq
5  AND a.emp_seq IN(SELECT emp_seq FROM dependents
6               WHERE relation=′SPOUSE′)
由于运算对象“e.emp_seq”能够被两个其它值取代,该SQL能够以三种方式写出(一种是原始方式,另外两种是能够取代“ e.emp_seq”的不同值的数)。
多种非连接传递性
下面介绍系统如何处理多种非连接传递性。例如,给定SQL语句,
1  SELECT*FROM employees e,assignments a,time_sheets t
2  WHERE e.emp_seq=a.emp_seq
3  AND a.emp_seq=t.emp_seq
4  AND a.proj_seq=t.proj_seq
5  AND a.proj_seq=(SELECT proj_seq FROM projects
6                WHERE name=′EXPLAIN SQL:DEVELOPMENT′)
7  AND e.emp_seq IN(SELECT emp_seq FROM dependents
8             WHERE relation=′SPOUSE′)
在两个不同的非连接准则中,“a.proj_seq”(第5行)和“e.emp_seq”(第7行)两个运算对象能够被等价的列取代。其它系统不会理解这一点。不过,本系统通过把“e.emp_seq”(第7行)转换到“a.emp_seq”,将允许数据库使用ASSIGNMENTS上的连接键索引。对于“e.emp_seq”的准则与上一个实例相同。本系统也能够以“t.proj_seq”取代“a.proj_seq”(第5行)。这表明可能有6(2×3)种不同的SQL语句能够使用(注意这包括原始值)。
多列运算对象
如何处理包括多列的运算对象?例如:
1  SELECT*FROM employees e,sal_history s
2  WHERE e.emp_seq=s.emp_seq
3  AND(s.emp_seq,s.effective_date)IN
4     (SELECT emp_seq,max(effective_date)
5     FROM sal_history s1
6     WHERE effective_date<=SYSDATE
7     GROUP BY emp_seq)
准则“s.emp_seq,seffective_date”(第3行)表示能够应用传递性的非连接准则。由于连接子句说明“e.emp_seq”和“s.emp_seq”是等价的,对于非连接准则运算对象就有两种选择。第一种是原始的,第二种是由“e.emp_seq”取代“s.emp_seq”。
问题在于这到底是否应当做。这个问题的理由在于运算对象中的两列都引用同一个表格,并且在两列中都有连接索引。即使在两列中只有一个单列索引。
答案是不要担心,只要把其它列加到运算对象上,并把对应列加到SELECT列表中,如下所示:
SELECT*FROM employees e,sal_history s
WHERE e.emp_seq=s.emp_seq
AND“(e.emp_seq,s.emp_seq,s.effective_date)IN”
     (SELECT“emp_seq”,emp_seq,max(effective_date)
     FROM sal_history s1
     WHERE effective_date<=SYSDATE
     GROUP BY emp_seq)
这就简化了判断,并让数据库决定使用哪一个。
非连接准则进行OR运算
如果查询中存在进行OR运算的准则怎么办?如果非连接准则与任何连接准则进行OR运算,由于与连接准则的OR运算,不能使用传递性了。能够使用的仅有的传递性是进行AND运算者。
以下SQL说明了带有OR的查询,但是注意所有的连接准则是与非连接准则进行AND运算。
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq
AND a.proj_seq=t.proj_seq
AND(e.emp_seq IN(SELECT emp_seq FROM dependents
              WHERE relation=′SPOUSE′)
OR t.rpt_date=SYSDATE-7)
以下的SQL不使用括号来指定准则的优先次序。使用默认的优先次序——AND在OR之前执行。
1  SELECT*FROM emplovees e,assignments a,time_sheets t
2  WHERE e.emp_seq=a.emp_seq
3  OR e.emp_seq IN(SELECT emp_seq FROM dependents
4                 WHERE relation=′SPOUSE′)
5  AND a.emp_seq=t.emp_seq
6  AND a.proj_seq=t.proj_seq
在这种情况下,在第5行和第6行中只有与非连接准则进行AND运算的连接准则。“e.emp_seq=a.emp_seq”的传递性不能使用。并且由于没有与非连接准则进行AND运算的连接准则引用“e.emp_seq”,就没有传递值。
外部连接
如果查询中存在非连接准则但是有外部连接怎么办?下一个实例给出了说明了:
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq(+)
AND a.emp_seq=t.emp_seq(+)
AND a.proj_seq=t.proj_seq(+)
AND e.emp_seq IN(SELECT emp_seq FROM dependents
              WHERE relation= ′SPOUSE′)
由于这里的非连接准则在“e.emp_seq”上有一个运算对象,并且在来自非外部连接表格的等价列处没有连接准则,就没有传递值。
以下的实例与前一个略有不同。
SELECT*FROM employees e,assignments a,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq(+)
AND a.proj_seq=t.proj_seq(+)
AND e.emp_seq IN(SELECT emp_seq FROM dependents
              WHERE relation=′SPOUSE′)
在这个实例中,TIME_SHEETS是仅有的外部连接表格。所以在这个实例中,传递性“e.emp_seq=a.emp_seq”能够使用,但是不能使“e.emp_seq”等于“t.emp_seq”。
简单非连接准则的传递性
以下的查询将被用于解释这个概念。
1  SELECT*FROM employees e,dependents d
2  WHERE e.emp_seq=d.emp_seq
3  AND“d.emp_seq=1001”
非连接准则为“d.emp_seq=1001”(第3行)。由于基于连接准则的传递性,该查询可以重写为:
SELECT*FROM employees e,dependents d
WHERE e.emp_seq=d.emp_seq
AND“e.emp_seq=1001”
现在这个非连接准则在EMPLOYEES表格上了。
这应当视为单列运算对象带有两个可能值的传递性。
非连接准则和嵌套选择的传递性
这是一个单列传递性的区域,它可能是极为有益的。如果嵌套选择在选择列表中不具有GROUP BY语法和聚集,并且在引用连接列之一的主查询中有非连接准则,这种非连接准则就可以移动到嵌套选择中。
例如,非连接准则是“e.emp_seq BETWEEN 1001 and 1010”(第4行)。
1   SELECT*FROM employees e,
2               (SELECT DISTINCT emp_seq FROM dependents)x
3   WHERE e.emp_seq=x.emp_seq
4   AND“e.emp_seq BETWEEN 1001 and 1010”
因为连接准则和传递性,该查询可以重写如下:
SELECT*FROM employees e,
           (SELECT DISTINCT emp_seq FROM dependents
            WHERE“emp_seq BETWEEN 1001 and 1010”)x
WHERE e.emp_seq=x.emp_seq
AND e.emp_seq BETWEEN 1001 and 1010
其要点在于不把它视为能够接受多个值的单列运算对象,而是简单地在嵌套的选择中复制准则。
驱动表格
可能有带有没有索引之非连接准则的查询。例如,一个索引搜索没有办法开始查询。可能有确实具有有索引之非连接准则的查询。以及最后可能有不带有非连接准则的查询。另一个重要的考虑为连接准则是不是在两面都有索引。所有这些都必须考虑到最优化模式是什么。
注意,下面引用的发连接准则包括了一个运算对象是一个子查询的情况。
也要注意,对于带有多于一个表格的所有子查询以及主查询,都应当确定潜在的驱动表格。
如果非连接准则存在
确定驱动表格是根据使用的最优化模式。
FIRST ROWS
如果最优化模式设置为FIRST ROWS,那么对于表格/视图或者From子句中的嵌套选择(它不是外部连接的表格),对有索引的非连接准则和没有索引的非连接准则的数目进行计数。如果表格具有任何有索引的非连接准则,那么表格能够用于驱动查询。如果所有表格都没有有索引的非连接准则,那么潜在的驱动表格就是带有任何没有索引的非连接准则者。
ALL ROWS
如果最优化模式设置为ALL ROWS,那么对于表格/视图或者From子句中的嵌套选择(它不是外部连接的表格),只须非连接准则的数目进行计数,无论是有索引的还是没有索引的。潜在的驱动表格就是带有任何非连接准则者。(该计数后来将用于确定连接次序。)
以下SQL语句将用于说明最优化模式和变换两个方面。
SELECT*FROM employees e,dependents d,assignments a
WHERE e.emp_seq=d.emp_seq
AND e.emp_seq=a.emp_seq
AND lname like‘SM%’
AND fname=‘ED’
AND relation=‘SPOUSE’
对于上面的SQL,如果最优化模式为FIRST ROWS,因为LNAME(我们可以忘记FNAME是连接索引的一部分这一事实)上的有索引的非连接准则,EMPLOYEES可以是驱动表格。RELATION上的非连接准则是没有索引的,所以IEPENDENTS不能是驱动表格。此外,ASSIGNMENTS上没有非连接准则。所以,仅有的潜在驱动表格是EMPLOYEES。
对于上面的SQL,如果最优化模式为ALL ROWS,因为EMPLOYEES和DEPENDENTS都有非连接准则,它们都可以是驱动表。而且,ASSIGNMENTS没有非连接准则,因而不能是驱动表。
如果没有非连接准则
如果绝对没有非连接准则,而且我们或者通过引用的完整性,或者通过用户连接,知道了层次(其中使用唯一索引一方是父级一方,而使用非唯一索引一方是子级一方),那么驱动表格应当是最顶端的父级。对于FIRST ROWS和ALL ROWS两种最优化模式,都应当如此。
例如,假设在以下的实例中没有引用的完整性:
SELECT*FROM employees e,dependents d,assignments a
WHERE e.emp_seq=d.emp_seq
AND e.emp_seq=a.emp_seq
EMPLOYEES和DEPENDENTS之间的连接,使用了EMPLOYEES一方的唯一索引和DEPENDENTS一方的非唯一索引。所以,EMPLOYEES视为父级,而DEPENDENTS视为一个子级。EMPLOYEES和ASSIGNMENTS之间的连接,使用了EMPLOYEES一方的唯一索引。不过,在ASSIGNMENTS一方没有索引(有一个索引包括EMP_SEQ但是不作为导引列)。下一节“如果没有索引的连接准则”将解释这一点的重要性。
所以对于上面的实例,EMPLOYEES会是驱动查询的唯一候选者(尽管在下一节中你将看到,由于缺乏连接索引,ASSIGNMENTS也可以被视为潜在的驱动者)。
一个查询中有不止一个表格能够被视为最顶端的表格时怎么办?以下的SQL可说明。
SELECT*FROM employees e,dept_history dh,departments d
WHERE e.emp_seq=dh.emp_seq
AND dh.dept_seq=d.dept_seq
在这种情况下,EMPLOYEES和DEPENDENTS都是DEPT_HISTORY的父级。所以,两者都能够被试用为驱动表格。
没有索引的连接准则
如果某个表格的连接没有索引,那么该表格是驱动查询的一个候选者,如果最优化模式为ALL ROWS的话。注意,即使该表格不具有任何非连接准则而其它表格却有,该表格也能够驱动一个ALLROWS查询。如果最优化模式为FIRST ROWS,这样一个表格就不会如此对待,除非表格上有非连接准则。例如,使用前面的规则,给予带有有索引之准则的表格优先设置。以下的实例说明了:
SELECT*FROM employees e,assignments a,projects p
WHERE a.proj_seq=p.proj_seq
AND e.emp_seq=a.emp_seq
在上面的查询中,ASSIGNMENTS在“a.proj_seq”上不具有所引。所以ASSIGNMENTS也是ALL ROWS最优化模式下的驱动查询的一个候选者。
外部连接
如果某个表格是外部连接的,它就不应当用作驱动表格。所以,如以下实例所示,即使在DEPENDENTS上有某个非连接准则,DEPENDENTS仍然不能用于驱动查询。
SELECT*FROM employees e,dependents d
WHERE e.emp_seq=d.emp_seq(+)
AND d.relation(+)=‘SPOUSE’
FROM子句嵌套选择
以下的查询将说明外部连接带来的问题。由于嵌套选择作为非连接准则中的一个子查询,该子查询应当永远是一个驱动表格。事实上,所有不是外部连接的嵌套SELECTS都首先连接,无论它们是否具有非连接准则。
在以下的查询中,子查询首先连接时出现了最佳方案,因而效率更高地驱动了历史记录的选择。在下面的ORDERED线索一节还要讨论这一点。
SELECT e.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seq
FROM employees e,sal_history s,job_history j,dept_history d,
     (SELECT emp_seq,MAX(effective_date)col1 FROM sal_history
     GROUP BY emp_seq)x1,
     (SELECT emp_seq,MAX(effective_date)col1 FROM job_history
     GROUP BY emp_seq)x2,
     (SELECT emp_seq,MAX(effective_date)col1 FROM dept_history
     GROUP BY emp_seq)x3
WHERE e.emp_seq=s.emp_seq
AND e.emp_seq=j.emp_seq
AND e.emp_seq=d.emp_seq
AND s.emp_seq=x1.emp_seq
AND s.effective_date=x1.col1
AND j.emp_seq=x2.emp_seq
AND j.effective_date=x2.col1
AND d.emp_seq=x3.emp_seq
AND d.effective_date=x3.col1
视图
理想情况下,系统应当为非连接准则检验视图定义本身,同时检验查询包含该视图。如果视图定义包含一个视图,你就不会递归地检验该视图了。一个级别就足够了,往往这也是全部需要。也要记住视图可能是多个表格的一个连接。
为了简化处理,把视图看作一个潜在的驱动表格。
连接次序
在决定连接次序之前,系统需要知道从何处开始。例如,什么是潜在的驱动表格/视图或者From子句中的嵌套选择。(参见上面的驱动表格。)
ORDERED线索将用于指定连接次序。
首先,对于我们将要指定连接次序的SQL语句,不用ORDERED线索对它进行测试。例如,这将是(不用ORDERED线索)测试的第一种置换。其它置换将根据决定的不同驱动表格。如果某个SQL语句具有能够驱动查询的两个表格,那么至少将有三种置换:原始的和两种使用ORDERED线索和不同驱动表格的。
采取驱动表格之一。看一下FROM子句中对象之间的层次,检验哪个连接例程将遇到  “最多的”非连接准则(其中FIRST ROWS寻找有索引的非连接准则——如果它们存在,否则寻找没有索引的非连接准则;ALL ROWS只是寻找最多的非连接准则,无论是否有索引)。所有对象以非连接准则连接之后,其它的连接就无关紧要了,所以不产生那些表格的变化。
以下的实例将予以说明。
实例1
下面的实例是用于ALL ROWS最优化模式。
SELECT e.*FROM employees e,time_sheets t,projects p,
               (SELECT emp_seq,MAX(effective_date)col1
               FROM sal_history s
               WHERE sal>100
               GROUPBY emp_seq)x
WHERE e.emp_seq=t.emp_seq
AND t.proj_seq=p.proj_seq
AND p.name=‘PAFO’
AND t.emp_seq=x.emp_seq
AND t.rpt_date=x.col1
在PROJECTS上有一个非连接准则,对于嵌套选择也有一个。这个实例的层次显示在图10中。
如图10所示,该层次把嵌套的选择描述为EMPLOYEES的一个子级。在这种情况下可以这样做,因为我们知道SAL_HISTORY是EMPLOYEES的一个子级。虚线显示了这种关系是通过传递性的,正如下面还要进一步介绍的。
因为传递性,如果PROJECTS用作驱动表格,我们会希望在最多非连接准则的方向上连接。这表明我们希望尽快获得嵌套的选择。所以该连接应当是:
PROJECTS->TIME_SHEETS->nested select->EMPLOYEES.
如果嵌套的选择用作驱动者,该连接应当是:
nested select->TIME_SHEETS->PROJECTS->EMPLOYEES
实际情况是,在前面的SQL中所有非连接准则也都有索引,所以会使用相同的连接次序。
实例2
SELECT*FROM employees e,
         (SELECT emp_Seq FROM dependents)x
WHERE e.emp_seq=x.emp_seq
AND e.emp_seq BETWEEN 1001 and 1010
下面的实例是用于FIRST ROWS或者ALL ROWS最优化模式。
EMPLOYEES和嵌套的选择之间的连接准则在双方都是有索引的。不过,由于非连接准则应当在嵌套的选择中复制(回顾上面关于传递性一节),那么两个对象都能够驱动查询。
实例3
这个查询意在用于FIRST ROWS最优化模式。
这是使用的标准历史数据查询。这里的要点在于,每个准则中有运算对象之一的非连接准则是一个子查询。由于在每种情况下其它运算对象都是有索引的,它们被视为有索引的非连接准则。
SELECT e.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seq
FROM employees e,sal_history s,job_history j,dept_history d
WHERE e.emp_seq=s.emp_seq
AND e.emp_seq=j.emp_seq
AND e.emp_seq=d.emp_seq
AND s.effective_date=
              (SELECT MAX(effective_date)FROM sal_history s1
              WHERE s.emp_seq=s1.emp_seq
              AND effective_date<=SYSDATE)
AND j.effective_date=
             (SELECT MAX(effectiv_ate)FROM job_history j1
             WHERE j.emp_seq=j1.emp_seq
             AND effective_date<=SYSDATE)
AND d.effective_date=
             (SELECT MAX(effective_date)FROM dept_history d1
             WHERE d.emp_seq=d1.emp_seq
             AND effective_date<=SYSDATE)
这个实例的层次显示在图11中。虚线表示了传递的连接。由于每一个历史表格都有有索引的非连接准则,因而它们能够直接连接。所以,任何历史表格都能成为驱动表格。除了默认的以外,不同的连接次序如下:
SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES
或者
SAL_HISTORY->JOB_HISTORY->DEPT_HISTORY->EMPLOYEES
或者
DEPT_HISTORY->SAL_HISTORY->JOB_HISTORY->EMPLOYEES
或者
DEPT_HISTORY->JOB_HISTORY->DEPT_HISTORY->EMPLOYEES
或者
JOB_HISTORY->DEPT_HISTORY->SAL_HISTORY->EMPLOYEES
或者
JOB_HISTORY->SAL_HISTORY->DEPT_HISTORY->EMPLOYEES
实例4
那么,如果实例3中的子查询移动到FROM子句中怎么办?现在嵌套的选择就有可能驱动查询。假设这是在ALL ROWS最优化模式下。
SELECT e.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seq
FROM employees e,sal_history s,job_history j,dept_history d,
     (SELECT emp_seq,MAX(effective_date)col1 FROM sal_history
     WHERE effective_date<=SYSDATE
     GROUP BY emp_seq)x1,
    (SELECT emp_seq,MAX(effective_date)col1 FROM job_history
     WHERE effective_date<=SYSDATE
     GROUP BY emp_seq)x2,
    (SELECT emp_seq,MAX(effective_date)col1 FROM dept_history
     WHERE effective_date<=SYSDATE
     GROUP BY emp_seq)x3
WHERE e.emp_seq=s.emp_seq
AND e.emp_seq=j.emp_seq
AND e.emp_seq=d.emp_seq
AND s.emp_seq=x1.emp_seq
AND s.effective date=x1.col1
AND j.emp_seq=x2.emp_seq
AND j.effective_date=x2.col1
AND d.emp_seq=x3.emp_seq
AND d.effective_date=x3.col1
这个实例的层次显示在图12中。注意,由于EMP_SEQ的传递性,在历史表格之间有传递的连接准则。例如,由于“s.emp_seq=x1.emp_seq”,以及“s.emp_seq=e.emp_seq”,以及“e.emp_seq=j.emp_seq”,以及“j.emp_seq=x2.emp_seq”,所以“x1.emp_seq=x2.emp_seq”。
此外,注意对于历史表格,没有非连接准则,只有嵌套的选择。所以历史表格都不能驱动查询。在上面论述的任何情况下,对于驱动表格,FROM子句中的嵌套子查询永远都能是驱动者。
现在我们具有更多的可能连接次序。为了使它更便于观察,给嵌套的选择以别名;SAL_HISTORY上的嵌套选择是S.N.;DEPT_HISTORY上的嵌套选择是DN;等等。此外,正如前面所述,系统不管没有非连接准则之对象的重新排列。
S.N.->DN->JN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES
S.N.->JN->DN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES
DN->S.N.->JN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES
DN->JN->S.N.->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES
JN->DN->S.N.->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES
JN->S.N.->DN->SAL_HISTORY->DEPT_HISTORY->JOB_HISTORY->EMPLOYEES
再次注意,后面的表格在其次序中保持不变。初始次序可能变化,但是对于不同的连接次序它总是保持不变。
集群表格
如果某个表格组合在查询中的一个其它表格之内,那些表格就应当一起连接,而不要其它表格的中间连接。例如,ASSIGNMENTS、PROJECTS和TIME_SHEETS在相同的散列集群中。以下的查询说明了:
SELECT*FROM employees e,assignments a,projects p,time_sheets t
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t.emp_seq
AND a.proj_seq=p.proj_seq
AND a.proj_seq=t.proj_seq
AND t.rpt_date BETWEEN′01-JAN-97′AND′30-JAN-97′
这个实例的层次显示在图13中。传递的连接关系由图13中的虚线显示。仅有TIME_SHEETS具有非连接准则。所以TIME_SHEETS将是唯一的驱动者。由于集群和别处缺乏非连接准则,所有的集群表格都应当依次连接如下:
TIME_SHEETS->ASSIGNMENTS->PROJECTS->EMPLOYEES
ORDERED线索
ORDERED线索永远可用。不过,如果连接准则允许连接的次序,系统的效率将更高。这往往表明增加与当前连接准则中传递性对应的连接准则。
挑选连接次序时,系统必须检验是否存在显式的连接准则。如果没有,那么系统应当通过传递性检验连接准则的隐含之处。如果存在隐含的连接准则,该准则应当在测试之前加到查询中。由于参数已经嵌入在ORDERED线索之内,隐含的连接准则应当继续留在ORDERED线索中。允许用户手工使用ORDERED线索时,系统以这种方式处理连接次序,因为不需要为了其它最优化模式而修改SQL文本。
对于下面的实例,虽然表格X1和X2之间没有显式的连接准则,通过传递性确实存在一个连接。检验的方法是沿着从X1到X2的连接路径。例如,从X1到S,连接为“x1.emp_seq=s.emp_seq ANDx1.col1=s.effective_ate”。从S到E连接也通过EMP_SEQ。这就隐含了“x1.emp_seq=e.emp_seq”。继续沿着该连接路径到X2,从E到D也通过EMP_SEQ。因此可以说“x1.emp_seq=d.emp_seq”。最后该路径通过“d.emp_seq=x2.emp_seq ANDd.effective_date=x2.col1”从D到X2。所以,该路径最后为“x1.emp_seq=x2.emp_seq”。由于ORDERED线索需要X1连接X2,并且隐含连接准则“x1.emp_seq=x2.emp_seq”存在,应当增加该准则作为ORDERED的一个参数。
为了获得X2和X3之间的传递连接准则,可以执行同样的过程。例如,“x2.emp_seq=x3.emp_seq”。由于X3并非显式地连接到E,系统应当包括连接准则 “x3.emp_seq=e.emp_seq”。
对于隐含的连接准则,建议的ORDERED线索格式如下:
SELECT/*+ORDERED(x1,x2,x3,e,s,j,d,“x1.emp_seq=x2.emp_seq”,“x2.emp_seq=x3.emp_seq”,
“x3.emp_seq=e.emp_seq”) */e.emp_seq,e.lname,e.fname,s.sal,d.dept_seq,j.job_seq
FROM employees e,sal_history s,job_history j,dept_history d,
      (SELECT emp_seq,MAX(effective_date)col1 FROM sal_history
     GROUP BY emp_seq)x1,
      (SELECT emp_seq,MAX(effective_date)col1 FROM job_history
     GROUP BY emp_seq)x2,
      (SELECT emp_seq,MAX(effective_date)col1 FROM dept_history
     GROUP BY emp_seq)x3
WHERE e.emp_seq=s.emp_seq
AND e.emp_seq=j.emp_seq
AND e.emp_seq=d.emp_seq
AND s.emp_seq=x1.emp_seq
AND s.effective date=x1.col1
AND j.emp_seq=x2.emp_seq
AND j.effective_date=x2.col1
AND d.emp_seq=x3.emp_seq
AND d.effective_date=x3.col1
FROM子句中的嵌套选择
如果嵌套的选择在FROM子句中,并且非连接准则在主SQL模块中引用它,系统将核实把该准则移动到嵌套SELECT的WHERE子句中。例如SQL语句,
SELECT*FROM employees e,(SELECT DISTINCT emp_seq,relation
                              FROM dependents d
                              WHERE birthdate>‘01-jan-80’)x
WHERE e.emp_seq=x.emp_seq
AND x.relation=‘SPOUSE’
能够变换为
SELECT*FROM employees e,(SELECT DISTNCT emp_seq,relation
                              FROM dependents d
                              WHERE birthdate>‘01-jan-80’
                              AND relation=‘SPOUSE’)x
WHERE e.emp_seq=x.emp_seq
在这种情况下,非连接准则移动到子查询,以便进一步减少先前合格的、连接后要过滤的行数。
应当注意,虽然某些数据库可能已经考虑到这一点,把该准则移动到WHERE子句还是有益的,加之更便于指定线索。
进行NOT运算的逻辑
一般说来,以优化而论,本文不考虑进行NOT运算的准则,因为它无关紧要。换句话说,典型情况下数据库自动处理进行NOT运算之准则的调换。
NVL函数
如果该函数的默认参数不等于运算对象常数,那么返回NULL时WHERE NVL(cost,0)=10将取值为WHERE 0=10。所以,由于默认值(0)不等于10,NVL函数能够去掉,因此允许准则使用索引。如果准则不能使用索引,就什么都不做。如果该列不是可空的,那么也什么都不做,因为完全没有要NVL函数的理由。
WHERE NVL(cost,0)=0不应当调换,除非存在着其它有索引的准则。例如,要是这种情况确实发生了,系统会不得不调换为WHEREcost=0 OR cost IS NULL。那仍然会需要不用其它有索引之准则的全表格扫描。例如,看一看下面的实例:
SELECT*FROM employees e,dependents d
WHERE e.emp_seq=d.emp_seq
AND e.hiredate=SYSDATE-7
AND NVL(d.birthdate,’01-JAN-80’)=’01-JAN-80’
能够变换为
现在,这能够进一步变换为:
SELECT*FROM employees e,dependents d
WHERE e.emp_seq=d.emp_seq
AND e.hiredate=SYSDATE-7
AND(d.birthdate=’01-JAN-80’OR d.birthdate IS NULL)
SELECT * FROM employees e,dependents d
WHERE e.emp_seq=d.emp_seq
AND e.hiredate=SYSDATE-7
AND d.birthdate=’01-JAN-80’
    UNION ALL
SELECT*FROM employees e,dependents d
WHERE e.emp_seq=d.emp_seq
AND e.hiredate=SYSDATE-7
AND d.birthdate IS NULL
分别优化每个SQL模块(如每个嵌套的查询)变得更加可能了。此外,注意该变换不包括底层模块中标准的不等式。它不必如此,因为OR在同一列。下面将更详细地讨论进行OR运算的准则。
进行OR运算的准则
以下实例介绍了系统如何处理进行OR运算的准则。例如,SQL语句,
select*from tab where A=10 OR B=20
能够重写为
select*from tab where(A=10)
UNION ALL
Select*from tab where(A!=10)AND(B=20)
如果列A和B可空,那么该方法会是:
某个WHERE子句写为,
select*from tab where(A=10)
UNION ALL
select*from tab where(A!=10 OR A IS NULL)AND(B=20)
写成如下形式的WHERE子句
where A=10 or(B=20 AND C=1)
能够重写为
WHEREA=10
UNION ALL
WHERE A!=10 AND(B=20 AND C=1)
如果列是可空的,应当增加‘IS NOT NULL’。
新方案运算
位图键迭代
某个子查询输出多个值,然后去往位图索引时,就会发生这种情况。遇到IN等运算符时,也要检验是否发生这种情况。过去对于位图索引中的IN运算符,是BITMAP OR处理多值情况。
其它线索
在数据仓库中,可以使用一种星形模式来描述一个或多个非常大的事实表格,表格中包含着数据仓库中的主要信息和若干个维数小得多的表格(如查找表格),每个小表格包含着事实表格中某个具体属性条目有关的信息。
星形查询是事实表格和若干查找表格之间的一种连接。每个查找表格连接事实表格,是使用一种主键到外来键的连接。不过,查找表格并不相互连接。
星形变换是一种基于成本的查询变换,致力于高效地执行星形查询。虽然星形最优化可能对于小维数和致密的事实表格很适用,但是如果以下的任何一条成立的话,星形变换也可以被视为一种替代方案。例如,假若维数大或者假若事实表格稀疏,星形变换可能有用。此外,对于并非所有维的表格都具有限定性谓语的查询,星形变换可能有用。星形变换不依赖于计算维表格的笛卡尔乘积,这使它更适于事实表格稀疏和维数大的情况,这种情况会导致大的笛卡尔乘积,而与事实表格中实际匹配的行却不多。此外,星形变换不是依赖于连接索引,而是基于位图索引与事实表格中各列的结合。因此该变换能够结合与限定维严格对应的索引。没有必要产生许多连接索引,其中不同的列次序匹配不同查询中限定维的不同模式。
“STAR_TRANSFORMATION”使本系统使用最好的方案,其中使用了变换。在事实表格中有位图索引和维表格中有足够的准则时,就会发生这种情况。
带有特定特征的表格不支持星形变换。例如,带有以下特征的表格不支持。带有与位图存取路径不兼容之表格线索的表格,带有太少的位图索引的表格(为了优化器考虑产生一个子查询,事实表格一列上应当有一个位图索引),远程表格(不过,在产生的子查询中允许远程维表格),反连接表格,在子查询中已经用作维表格的表格,视图真正分离而不是视图部分的表格,具有良好的单表格存取路径的表格以及对于变换来说太小而不值得做的表格。
以下实例说明了在查询中早期减少嵌套选择的结果。例如,如果用户输入下面带有FROM子句中的嵌套选择的查询。
SELECT e.*FROM employees e,time_sheets t,projects p,
                (SELECT emp_seq,MAX(effective_date)col1
                 FROM sal_history s
                 GROUP BY emp_seq)x
WHERE e.emp_seq=t.emp_seq
AND t.proj_seq=p.proj_seq
AND p.name=‘PAFO’
AND t.emp_seq=x.emp_seq
AND t.rpt_date=x.col1
“AND x.col1<SYSDATE”
用户应当放置了带有嵌套选择的准则,如下所示。那样的话,就能够早期减少嵌套选择的结果。
SELECT e.*FROM employees e,time_sheets t,projects p,
                (SELECT emp_seq,MAX(effective_date)col1
                 FROM sal_history s
                GROUP BY emp_seq
                “HAVING MAX(effective_date)<SYSDATE)”x
WHERE e.emp_seq=t.emp_seq
AND t.proj_seq=p.proj_seq
AND p.name=‘PAFO’
AND t.emp_seq=x.emp_seq
AND t.rpt_date=x.col1
OBJECT INSTANCE
如果某个表格不在最优化期间存取,系统将不能在SQL语句中鉴别是哪个表格。例如,在以下的SQL语句中,ASSIGNMENTS和PROJECTS都是仅仅由它们的索引存取在ALL ROWS模式下表示的。换句话说,该表格不必存取。所以,如果用户对ASSIGNMENTS单击索引操作,在该SQL中将不会选中任何内容来确认该方案和该SQL之间的关系。
SELECT*FROM employees e,
           (SELECT DISTINCT emp_seq FROM assignments a,projects p
            WHERE a.proj_seq=p.proj_seq)x
WHERE e.emp_seq=x.emp_seq
系统至少应当检验该表格在整个SQL语句中是不是唯一的。如果是,那么用户单击索引操作时,系统应当选中该表格。
OBJECT INSTANCE
在FROM子句中有嵌套选择时,本系统不考虑给予嵌套选择的OBJECT_INSTANCE值,以及给予嵌套选择内部对象的OBJECT_INSTANCE值。
改变SQL
如果用户希望FIRST ROWS模式,一般说来在把子查询移动到FROM子句中它不会有意义。合并总是好的,但是不必移动。例如检验历史数据查询的实例。事实上,离开关联的子查询,或者甚至把不关联的转换为关联的可能有意义。
增加ORDERED线索时,它申请一个不同于指定的原始SQL的连接次序,系统重新排列FROM子句并传递到数据库。不过,系统重新排列时,它仍然显示带有参数的原始ORDERED线索。由于参数不是实际线索语法的一部分,显示SQL的HINTS模式时,系统丢弃了ORDERED线索的参数。例如,如果EDIT窗口中的原始SQL为:
SELECT/*+HINT1 ORDERED(s,d,e,j)*/*
FROM employees e,sal_history s,job_history j,dept_history d
WHERE e.emp_seq=s.emp_seq
AND e.emp_seq=j.emp_seq
AND e.emp_seq=d.emp_seq
AND s.sal>500
AND j.job_seq=10
AND d.effective_date=j.effective_date
AND s.effective_date=j.effective_date
the HINTS1 window should display:
SELECT/*+ ORDERED*/*
FROM sal_history s,dept_history d,employees e,job_history j
WHERE e.emp_seq=s.emp_seq
AND e.emp_seq=j.emp_seq
AND e.emp_seq=d.emp_seq
AND s.sal>500
AND j.job_seq=10
AND d.effective_date=j.effective-date
AND s.effective_date=j.effective_date
这与关键字HINTS1的消失一致,再加上FROM子句的变化。换句话说,对于特定的模式,SQL窗口应当原原本本地显示传递到数据库的内容。当连接准则增加到ORIERED线索时,应当这样做。
报告
从产生一种直方图来说,推荐哪些“有索引的列(单列索引)”也许有益,会是一种有用的报告。由于仅仅对于不具有正态分布的列,才应当构造直方图,我们需要找到不具有正态分布的列。
“线索”:对于ALL ROWS,“连接到表格”索引大于表格时,表示FULL。
SQL检验
如果子查询以关系运算符NOT IN或任何形式的ALL连接,系统就能够显示以下消息,并选中该子查询——如果可能的话:
“如果子查询不返回行(空集),包括该子查询的准则将取值为TRUE,换句话说,子查询不返回行时,它的作用与NOT EXISTS完全相同。”
改变SQL
子查询返回了将馈入引用同一表格之准则的列时,应当改变该子查询的选择列表,使它包含ROWID。例如,看一看下面的历史查询,
SELECT*FROM employees e,sal_history s1
WHERE e.emp_seq=s1.emp_seq
AND s1.effective_date=
    (SELECT max(effective_date)FROM sal_history s2
    WHERE e.emp_seq=s2.emp_seq
    AND s2.effective_date<=SYSDATE)
可以变换为
SELECT*FROM employees e,sal_history s1
WHERE e.emp_seq=s1.emp_seq
AND s1.“ROWID” =
        (SELECT“ROWID”FROM sal_history s2
        WHERE e.emp_seq=s.emp_seq
         AND s2.effective_date<=SYSDATE)
线索
应用线索时,用户必须负责查看线索是否见效。本系统能够提供反馈,通知用户线索确实具有所需的效果。例如,系统可能通知用户ORDERED线索是否以指定的次序连接。
对于包括NOT IN或NOT EXISTS子查询的查询,可以应用传递性,所以外层查询中的连接列属于同一表格。这就合并了NOT IN和NOT EXISTS子查询,因为一个表格不能外部连接到多于一个表格。例如以下的SQL语句,
SELECT*
FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq
  AND(e.emp_seq,a.start_date)NOT IN(SELECT emp_seq,rpt_date
                                     FROM time_sheets)
能够转换为
SELECT*
FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq
AND(a.emp_seq,a.start_date)NOT IN(SELECT emp_seq,rpt_date
                                       FROM time_sheets)
然后它能够转换为
SELECT e.*,a.*
FROM employees e,assignments a,time_sheets t1
WHERE e.emp_seq=a.emp_seq
AND a.emp_seq=t1.emp_seq(+)
AND a.start_date=t1.rpt_date(+)
AND t1.ROWID IS NULL
以下的实例说明了合并要连接的NOT IN和NOT EXISTS子查询。例如,SQL语句,
SELECT*
FROM employees e
WHERE NOT EXISTS
 (SELECT*
  FROM assignments a
  WHERE e.emp_seq=a.emp_seq)
将转换为
SELECT/*+ALL_ROWS */e.*
FROM employees e,
 (SELECT DISTINCT 1 col2,a.emp_seq col1
 FROM assignments a)
t1
WHERE e.emp_seq=t1.col1(+)
AND t1.col2 IS NULL
不过,该子查询应当合并如下
SELECT e.*
FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq(+)
AND a. emp_seq IS NULL
系统通过把外层的连接列中的常数移动到子查询中,能够把SQL4转换到SQL 5再转换到SQL 6,如下所示。例如,原始SQL语句,
SELECT*
FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq
 AND(e.emp_seq,′22-FEB-94′)NOT IN (SELECT emp_seq,rpt_date
                     FROM time_sheets)
                              SQL 4
能够变换为
SELECT*
FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq
AND e.emp_seq NOT IN (SELECT emp_seq
                             FROM time_sheets
                  WHERE rpt_date=′22-FEB-94′)
                                           SQL 5
它能够变换为
SELECT e.*,a.*
 FROM employees e,assignments a,time_sheets t1
 WHERE e.emp_seq=a.emp_seq
 AND a.emp_seq=t1.emp_seq(+)
 AND t1.rpt_date(+)=′22-FEB-94′
 AND t1.ROWID IS NULL
                 SQL 6
以下的查询不能转换,因为如果合并,该子查询表格必须外部连接到一个表格。该子查询不能外部连接到一个单独的常数。
SELECT*
FROM employees e,assignments a
WHERE e.emp_seq=a.emp_seq
AND′22-FEB-94′NOT IN(SELECT rpt_date
             FROM time._sheets)
                           SQL 7
如果一个子查询的连接列是一个常数,就能够执行合并,如果连接时所有表格都唯一的话。合并该子查询时,常数Θ设置为NOTEQUALS对应的外层连接列,并且与‘<child>.ROWID IS NULL’进行OR运算。例如,SQL语句,
SELECT*
FROM employees e
WHERE(e.emp_seq,lname)NOT IN(SELECT emp_seq,′SMITH′
                  FROM time_sheets
                  WHERE proj_seq=1
                  AND rpt_date=′22-feb-94′)
                                         SQL 8
能够变换为
SELECT e.*
 FROM employees e,time_sheets t1
 WHERE e.emp_seq=t1.emp_seq(+)
 AND proj_seq(+)=1
 AND rpt_date(+)=′22-feb-94′
 AND (t1.ROWID IS NULL
 OR lname <>′SMITH′)
                SQL 9
试图变换SQL语句时必须谨慎。例如,可能试图把以下的SQL语句
 SELECT*
  FROM employees e
  WHERE emp_seq NOT IN(SELECT a.emp_seq
            FROM projects p,assignments a
            WHERE a.proj_seq=p.proj_seq
            AND p.name=′EXPLAIN SQL:DEVELOPMENT′)
ORDER BY 1
变换为以下的
SELECT/*+ ALL_ROWS */
 e.*
FROM employees e,projects p,assignments a
WHERE e.emp_seq=a.emp_seq(+)
AND a.proj_seq=p.proj_seq(+)
AND p.name(+)=′EXPLAIN SQL:DEVELOPMENT′
AND p.ROWID IS NULL
ORDER BY 1
不过,这会是不正确的,由于不可能把这里的原始SQL合并到外部查询。这会导致一种不正确的变换。
如果系统试图增加带有任意表格的‘ROWID IS NULL’子句,可能发生另一个问题。例如,有时系统也许挑选项目表格,有时它也许挑选分配表格,取决于FROM子句中的次序。这会是不正确的。应当谨慎地确保最低级别的子级表格为空(如项目表格)。否则,向子表格(在这种情况下是项目)连接准则将是不适当的。
在变换期间,应当遵循以下的规则和方针。
A)只有满足以下条件,本系统才应当进行变换:
i)在连接次序中的所有中间表格都应当连接以保证唯一性。
ii)可以有多于一个分支。不过,最多只能有一个最低级别的子表格可为非唯一。按次序加如时,所有其它的表格都应当是唯一的。换句话说,检验以上的SQL时,分配表格就是带有连接子查询列的表格。由于它不是最低级别的子级(项目表格连接它),它在选择列表中或者在WHERE子句中的列连接带有=运算符的常数,必然形成一个独特的键。不过,emp_seq不是唯一的列。所以这个子查询不能合并。不过,项目名称是唯一的列时,下面的实例SQL 10能够转换。
iii)如果子查询连接列之一是一个常数,所有表格都应当连接以保证唯一性。
iv)没有聚集函数(只要没有聚集,GROUP BY、DISTINCT和HAVING都可以。合并时,忽略GROUP BY和DISTINCT并把HAVING准则移动到WHERE子句)
v)没有CONNECT BY语法
vi)没有集合运算(如UNION、MINUS)
vii)子查询不包含外部连接。
B)对于每个更低级别的子级,增加‘<child>.ROWID IS NULL’并用OR连在一起。
C)如果在外层的连接列中有一个常数并且有其它的连接列,改变它为与子查询WHERE子句的相等准则。
D)如果在子查询的连接列中的一个常数中有一个常数,设置该常数为NOT EQUALS对应的外层连接列并把它与‘<child>.ROWIDIS NULL’进行OR运算。
SELECT*
FROM status_list
WHERE status NOT IN(SELECT p.status
           FROM projects p,assignments a
           WHERE a.proj_seq=p.proj_seq
           AND p.name=′EXPLAIN SQL:DEVELOPMENT′)
                           SQL 10
确定一个外部连接是否能够发生时,关联的子查询可能会产生一个问题。确切地说,当NOT IN运算符连接到关联的子查询时,外层查询中的连接列必须属于与子查询关联的表格相同的表格。例如,参见下面的SQL语句。子查询中的连接列应当属于与子查询关联的表格相同的表格。在下面的实例中,HIREDATE列属于“e.”以及关联准则之一,而其它关联准则引用“a.”所以合并是不可能的。
SELECT*FROM time_sheets t
WHERE t.rpt_date NOT IN
   (SELECT hire date FROM employees e,assignments a
    WHERE a.proj_seq=t.proj_seq
    AND e.emp_seq=a.emp_seq
    AND e.emp_seq=t.emp_seq)
                       SQL 11
“[NOT IN]子查询中的连接列必须属于与子查询关联的表格相同的表格”不是必需的,只要上面的规则/方针A)i)和A)ii)成立。不过,因为外部连接,外层查询中对应的连接列应当属于同一表格。如果进行转换,分配表格既需要外部连接到TIME_SHEETS,又需要外部连接到EMPLOYEES。这是不合法的。不过,可以应用传递性来把上面显示的SQL 11语句转换为下面显示的SQL 12。然后SQL 12可以合并到下面显示的SQL 13。这种合并是可能的,因为EMPLOYEES和ASSIGNMENTS在连接列上都有唯一的索引。
SELECT*FROM time_sheets t
WHERE t.rpt_date NOT IN
   (SELECT hiredate FROM employees e,assignments a
   WHERE a.proj_seq=t.proj_seq
   AND t.emp_seq=a.emp_seq
   AND e.emp_seq=t.emp_seq)
                      SQL 12
SELECT*FROM time_sheets t,employees e,assignments a
WHERE e.hiredate(+)=t.rpt_date
AND a.proj_seq(+)=t.proj_seq
AND a.emp_seq(+)=t.emp_seq
AND e.emp_seq(+)=t.emp_seq
AND (a.rowid IS NULL or e.rowid IS NULL)
                           SQL 13
也应当注意,你不能合并在子查询SELECT子句中带有non-column(常数、函数等等)的NOT EXISTS或NOT IN子查询。例如,可以把以下的SQL 14试图变换为SQL 15。不过,因为t.rpt_date=’22-FEB-94’,SQL 15产生的结果集与SQL 14不同。该准则可以改变为t.rpt_date<>’22-FEB-94’。不过,我们将不得不保证原始子查询返回至少一行。这就破环了变换的目的,因为我们不得不保持该子查询。
SELECT*
FROM time_sheets t
WHERE (t.emp_seq,t.rpt_date)NOT IN(SELECT emp_seq,′22-FEB-94′
                      FROM employees)
                         SQL 14
SELECT/*+ALL_ROWS */
t.*
FROM time_sheets t,employees t1
WHERE t.emp_seq=t1.emp_seq(+)
AND t.rpt_date=′22-FEB-94′
AND t1.ROWID IS NULL
                      SQL 15
设置NOT IN、NOT EXISTS子查询可以为查询
如果运算符是NOT IN或者NOT EXISTS,可以调用以下的例程,试图确定它是否应当试图把子查询转换为一个连接。
<<code begin>>
IF subquery contains aggregate in Select list OR subquery contains aggregate in
HAVING clause OR subquery contains Connect By syntax OR subquery contains set
operation THEN RETURN FALSE
LOOP over each table X in the FROM list,if there is more than 1 join criterion,apply
transitivity so the table join to the same table,if possible.
Initialize Unique_list to empty
Non_Unqiue_table:=null
LOOP over each TABLE in the FROM list containing interface columns
     IF CheckTableUniqueIndexCols return TRUE
            (CheckTableUniqueIndexCols routine checks for a given table,whether all
            the columns of its any one unique indexes are present in the where clause
            and have a′=′operation and the other operand is a constant or a
            correlated.)
THEN add TABLE to the Unique_list
ELSE
                IF Non_Unqiue_table is null
                THEN
                        Non_Unqiue_table=TABLE
                ELSE
                        RETURN FALSE
END LOOP over each TABLE in the FROM list containing interface columns
LOOP over each TABLE in the FROM list containing interface columns
     IF Check_Unique(TABLE,interface table of the surrounding query,Unique_list,
            Non_Unique_table)returns FALSE
            RETURN FALSE
END LOOP over each table in the FROM list containing interface columns
(Make sure all table is joined)
LOOP over each TABLE
        IF TABLE not in unique_list and TABLE<>Non_unique_table
        THEN
                RETURN FALSE
END LOOP over each TABLE
RETURN TRUE
<<code end>>
检验唯一性
输入:
       TABLE
       PARENT_TABLE
       NONUNIQUE_TABLE
       <<code begin>>
       LOOP over each table Y joined to TABLE
               IF Y=PARENT_TABLE
                     continue loop
               IF Y is in Unique_list or Y is Non_unique_table(if Y is already joined,cannot
               join to another table)
               THEN RETURN FALSE
               LOOP over each index of Y
                       IF all indexed columns are joined to X with=operator OR index columns
=constant
                       THEN
                                add Y to Unique_list
                         IF Check_Unique(Y,X,Unique_list,Non_unique_table)returns
FALSE
                         THEN RETURN FALSE
                         BREAK(unique index found,no need to search anymore)
           END LOOP over each index of Y
           IF Y not in Unique_list
                 IF Non_unique_table is null
                      Non_unique_table=Y
                      (Since Y is not unique,make sure no other table is joined to Y)
                      LOOP over each table Z joined to Y
                           IF Z not in Unique_list and Z<>Non_unique_table
                           THEN RETURN FALSE
                           END LOOP over each table Z joined to Y
                   ELSE
                           RETURN FALSE
   END LOOP over each table Y joined to TABLE
   RETURN TRUE
   <<code end>>
如果某个WHERE子句准则仅仅引用FROM子句中嵌套选择内的表格,就把它移动到该嵌套选择。
例如,以下的SQL
SELECT*
 FROM employees e,
   (SELECT DISTINCT emp_seq,relation
   FROM dependents d
   WHERE birthdate>′01-jan-80′)x
WHERE e.emp_seq=x.emp_seq
AND x.reLation=′SPOUSE′
能够转换为
SELECT*
FROM employees e,
  (SELECT DISTINCT emp_seq,relation
   FROM dependents d
   WHERE birthdate>′01-jan-80′
   AND x.relation=′SPOUSE′)x
WHERE e.emp_seq=x.emp_seq
如果某个HAVING子句准则不涉及组函数,它就能够移动到WHERE子句。
例如,以下的SQL语句
SELECT LNAME,count(*)
FROM employees
GROUP BY LNAME
HAVING LNAME<′D′
能够变换为
SELECT LNAME,count(*)
FROM employees
WHERE LNAME<′D′
GROUP BY LNAME
使用按照本说明书的指导编程的一台或多台常规的通用数字计算机和/或服务器,可以方便地实现本公开文件。根据本公开文件的指导,可以容易地准备适当的软件代码。
此外,虽然以上的介绍引用了特定的数据库系统(如Oracle),但是应当理解,本公开文件不限于任何具体的数据库或数据库系统的类型。
考虑到以上的指导,本公开文件许多另外的修改和变化都是可能的。所以应当理解,在附带的权利要求书的范畴之内,本公开文件的实现方式可以不同于本文中介绍的特定方式。

Claims (33)

1.一种调节数据库查询的方法,包括:
选择数据库查询;
分析选定的数据库查询以确定选定的数据库查询的若干部分之间的关系;
从多个可用的最优化模式中选择最优化模式;
根据确定的关系和选定的最优化模式,通过修改选定的数据库查询的至少一个部分,调节选定的数据库查询;以及
显示修改后的数据库查询。
2.根据权利要求1的方法,其特征在于,该分析确定数据库查询之内的标记,标记是由分隔符分开的单词。
3.根据权利要求1的方法,其特征在于,多个可用的最优化模式包括基于成本的和基于规则的模式。
4.根据权利要求3的方法,其特征在于,基于成本的模式包括First_Rows模式和All_Rows模式。
5.根据权利要求1的方法,进一步包括确定与使用调节后的数据库查询相关联的成本。
6.根据权利要求5的方法,进一步包括比较两种成本,一种是与使用选定的数据库查询相关联的成本,另一种是与使用调节后的数据库查询相关联的成本。
7.根据权利要求1的方法,进一步包括分析选定的数据库查询,以确定该数据库查询是否包括由NOT EXISTS、NOT IN和ALL子句中至少一个连接的至少一个子查询。
8.根据权利要求7的方法,进一步包括提示用户根据该数据库查询是否包括NOT EXISTS、NOT IN和ALL子句中的至少一个,选择调节期间使用的优先设置。
9.根据权利要求8的方法,其特征在于,该优先设置包括重写优先设置,使得用户能够在从NOT EXISTS运算符到NOT IN运算符的转换和从选定的数据库查询到外部连接的转换中,选择至少一个。
10.根据权利要求8的方法,其特征在于,该优先设置包括重写优先设置,使得用户能够选择把ALL运算符连接的子查询转换为一个连接或外部连接。
11.根据权利要求8的方法,其特征在于,该优先设置包括重写优先设置,使得用户能够选择是否使用一个NOT EXISTS运算符和一个外部连接中的至少一个,对NOT IN运算符连接的子查询进行转换。
12.一种包括用于调节数据库查询的计算机可执行代码的计算机存储介质,包括:
使用户选择数据库查询的计算机可执行代码;
用于分析选定的数据库查询以确定选定的数据库查询的若干部分之间关系的计算机可执行代码;
使用户从多个可用的最优化模式中选择最优化模式的计算机可执行代码;
用于根据确定的关系和选定的最优化模式,通过修改选定的数据库查询的至少一个部分,调节选定的数据库查询的计算机可执行代码;以及
用于显示修改后的数据库查询的计算机可执行代码。
13.根据权利要求12的计算机存储介质,其特征在于,该分析确定数据库查询之内的标记,标记是由分隔符分开的单词。
14.根据权利要求12的计算机存储介质,其特征在于,多个可用的最优化模式包括基于成本的和基于规则的模式。
15.根据权利要求14的计算机存储介质,其特征在于,基于成本的模式包括First_Rows模式和All_Rows模式。
16.根据权利要求12的计算机存储介质,进一步包括用于确定与使用调节后的数据库查询相关联的成本的代码。
17.根据权利要求16的计算机存储介质,进一步包括用于比较两种成本的代码,一种是与使用选定的数据库查询相关联的成本,另一种是与使用调节后的数据库查询相关联的成本。
18.根据权利要求12的计算机存储介质,进一步包括用于分析选定的数据库查询的代码,以确定该数据库查询是否包括由NOTEXISTS、NOT IN和ALL子句中至少一个连接的至少一个子查询。
19.根据权利要求18的计算机存储介质,进一步包括用于提示用户根据该数据库查询是否包括NOT EXISTS、NOT IN和ALL子句中的至少一个,选择调节期间使用的优先设置的代码。
20.根据权利要求19的计算机存储介质,其特征在于,该优先设置包括重写优先设置,使得用户能够在从NOT EXISTS运算符到NOTIN运算符的转换和从选定的数据库查询到外部连接的转换中,选择至少一个。
21.根据权利要求19的计算机存储介质,其特征在于,该优先设置包括重写优先设置,使得用户能够选择把ALL运算符连接的子查询转换为一个连接或外部连接。
22.根据权利要求19的计算机存储介质,其特征在于,该优先设置包括重写优先设置,使得用户能够选择是否使用一个NOT EXISTS运算符和一个外部连接中的至少一个,对NOT IN运算符连接的子查询进行转换。
23.一种用于调节数据库查询的、编程的计算机系统,包括:
一种显示器,用于向用户显示至少一个数据库查询;
一种用户输入,使用户从显示的数据库查询中选择一个数据库查询,从多个可用的最优化模式中选择一个最优化模式;以及
一种处理器,用于分析选定的数据库查询以确定选定的数据库查询的若干部分之间关系,并用于根据确定的关系和选定的最优化模式,通过修改选定的数据库查询的至少一个部分,调节选定的数据库查询,修改后的数据库查询通过显示器向用户显示。
24.根据权利要求23的系统,其特征在于,该分析确定数据库查询之内的标记,标记是由分隔符分开的单词。
25.根据权利要求23的系统,其特征在于,多个可用的最优化模式包括基于成本的和基于规则的模式。
26.根据权利要求25的系统,其特征在于,基于成本的模式包括First_Rows模式和All_Rows模式。
27.根据权利要求23的系统,其特征在于,该处理器确定与使用调节后的数据库查询相关联的成本。
28.根据权利要求27的系统,其特征在于,该处理器比较两种成本的代码,一种是与使用选定的数据库查询相关联的成本,另一种是与使用调节后的数据库查询相关联的成本。
29.根据权利要求23的系统,其特征在于,该处理器分析选定的数据库查询的代码,以确定该数据库查询是否包括由NOT EXISTS、NOT IN和ALL子句中至少一个连接的至少一个子查询。
30.根据权利要求29的系统,其特征在于,该处理器提示用户根据该数据库查询是否包括NOT EXISTS、NOT IN和ALL子句中的至少一个,选择调节期间使用的优先设置。
31.根据权利要求30的系统,其特征在于,该优先设置包括重写优先设置,使得用户能够在从NOT EXISTS运算符到NOT IN运算符的转换和从选定的数据库查询到外部连接的转换中,选择至少一个。
32.根据权利要求30的系统,其特征在于,该优先设置包括重写优先设置,使得用户能够选择把ALL运算符连接的子查询转换为一个连接或外部连接。
33.根据权利要求30的系统,其特征在于,该优先设置包括重写优先设置,使得用户能够选择是否使用一个NOT EXISTS运算符和一个外部连接中的至少一个,对NOT IN运算符连接的子查询进行转换。
CNA018118208A 2000-05-26 2001-05-25 自动产生数据库查询的系统和方法 Pending CN1592905A (zh)

Applications Claiming Priority (2)

Application Number Priority Date Filing Date Title
US20737900P 2000-05-26 2000-05-26
US60/207,379 2000-05-26

Publications (1)

Publication Number Publication Date
CN1592905A true CN1592905A (zh) 2005-03-09

Family

ID=22770299

Family Applications (1)

Application Number Title Priority Date Filing Date
CNA018118208A Pending CN1592905A (zh) 2000-05-26 2001-05-25 自动产生数据库查询的系统和方法

Country Status (10)

Country Link
US (1) US8019750B2 (zh)
EP (1) EP1350184B1 (zh)
JP (1) JP2004509382A (zh)
KR (1) KR20030047889A (zh)
CN (1) CN1592905A (zh)
AU (2) AU2001265048B2 (zh)
BR (1) BR0111192A (zh)
CA (1) CA2409276A1 (zh)
IL (2) IL152987A0 (zh)
WO (1) WO2001093105A2 (zh)

Cited By (7)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN100403314C (zh) * 2006-04-19 2008-07-16 华为技术有限公司 一种数据查询方法
CN100498793C (zh) * 2007-06-08 2009-06-10 北京神舟航天软件技术有限公司 用基于小波的压缩直方图实现二维谓词选择率估计的方法
CN101436192B (zh) * 2007-11-16 2011-03-16 国际商业机器公司 用于优化针对垂直存储式数据库的查询的方法和设备
CN102968420A (zh) * 2011-08-31 2013-03-13 国际商业机器公司 数据库查询的方法和系统
CN104881460A (zh) * 2015-05-22 2015-09-02 国云科技股份有限公司 一种基于Oracle数据库实现多行数据并为一行显示的方法
CN106598963A (zh) * 2015-10-14 2017-04-26 五八同城信息技术有限公司 查询语句优化方法及装置
CN106919678A (zh) * 2017-02-27 2017-07-04 武汉珞佳伟业科技有限公司 一种数据库查询优化系统及方法

Families Citing this family (59)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US8910241B2 (en) 2002-04-25 2014-12-09 Citrix Systems, Inc. Computer security system
US7747606B2 (en) * 2003-09-06 2010-06-29 Oracle International Corporation Automatic SQL tuning advisor
US7587394B2 (en) * 2003-09-23 2009-09-08 International Business Machines Corporation Methods and apparatus for query rewrite with auxiliary attributes in query processing operations
US7132796B2 (en) 2003-12-30 2006-11-07 Lg.Philips Lcd Co., Ltd Organic electroluminescent device and method of fabricating the same
US7343367B2 (en) * 2005-05-12 2008-03-11 International Business Machines Corporation Optimizing a database query that returns a predetermined number of rows using a generated optimized access plan
US20070143246A1 (en) * 2005-12-15 2007-06-21 International Business Machines Corporation Method and apparatus for analyzing the effect of different execution parameters on the performance of a database query
US7882121B2 (en) * 2006-01-27 2011-02-01 Microsoft Corporation Generating queries using cardinality constraints
US7702658B2 (en) * 2006-01-27 2010-04-20 International Business Machines Corporation Method for optimistic locking using SQL select, update, delete, and insert statements
US8903763B2 (en) * 2006-02-21 2014-12-02 International Business Machines Corporation Method, system, and program product for transferring document attributes
CN101093493B (zh) * 2006-06-23 2011-08-31 国际商业机器公司 数据库查询语言转换方法、转换装置
US20080040334A1 (en) * 2006-08-09 2008-02-14 Gad Haber Operation of Relational Database Optimizers by Inserting Redundant Sub-Queries in Complex Queries
US8694524B1 (en) * 2006-08-28 2014-04-08 Teradata Us, Inc. Parsing a query
US20080126393A1 (en) * 2006-11-29 2008-05-29 Bossman Patrick D Computer program product and system for annotating a problem sql statement for improved understanding
US8019771B2 (en) * 2006-11-30 2011-09-13 International Business Machines Corporation Method for dynamically finding relations between database tables
US10255583B2 (en) * 2007-05-01 2019-04-09 Oracle International Corporation Nested hierarchical rollups by level using a normalized table
US8065329B2 (en) * 2007-06-18 2011-11-22 Oracle International Corporation Query optimization on VPD protected columns
US8112421B2 (en) 2007-07-20 2012-02-07 Microsoft Corporation Query selection for effectively learning ranking functions
US7774318B2 (en) * 2007-07-30 2010-08-10 Sap Ag Method and system for fast deletion of database information
US9009181B2 (en) 2007-08-23 2015-04-14 International Business Machines Corporation Accessing objects in a service registry and repository
US7783656B2 (en) * 2007-09-24 2010-08-24 International Business Machines Corporation Accessing objects in a service registry and repository using a treat as function
US8903801B2 (en) 2007-09-14 2014-12-02 Oracle International Corporation Fully automated SQL tuning
US8335767B2 (en) * 2007-10-17 2012-12-18 Oracle International Corporation Maintaining and utilizing SQL execution plan histories
US8516539B2 (en) * 2007-11-09 2013-08-20 Citrix Systems, Inc System and method for inferring access policies from access event records
US8990910B2 (en) * 2007-11-13 2015-03-24 Citrix Systems, Inc. System and method using globally unique identities
US7827153B2 (en) * 2007-12-19 2010-11-02 Sap Ag System and method to perform bulk operation database cleanup
US9240945B2 (en) * 2008-03-19 2016-01-19 Citrix Systems, Inc. Access, priority and bandwidth management based on application identity
US8943575B2 (en) * 2008-04-30 2015-01-27 Citrix Systems, Inc. Method and system for policy simulation
US8150865B2 (en) * 2008-07-29 2012-04-03 Oracle International Corporation Techniques for coalescing subqueries
US8990573B2 (en) * 2008-11-10 2015-03-24 Citrix Systems, Inc. System and method for using variable security tag location in network communications
US8065323B2 (en) * 2009-02-23 2011-11-22 Oracle International Corporation Offline validation of data in a database system for foreign key constraints
US8452754B2 (en) * 2009-05-08 2013-05-28 Microsoft Corporation Static analysis framework for database applications
WO2011090549A1 (en) * 2010-01-20 2011-07-28 Aetna Inc. System and method for code automation
US10311105B2 (en) * 2010-12-28 2019-06-04 Microsoft Technology Licensing, Llc Filtering queried data on data stores
US8880508B2 (en) * 2010-12-30 2014-11-04 Sap Se Processing database queries using format conversion
US8694525B2 (en) * 2011-06-24 2014-04-08 Sas Institute Inc. Systems and methods for performing index joins using auto generative queries
GB2505183A (en) * 2012-08-21 2014-02-26 Ibm Discovering composite keys
US10726010B2 (en) * 2012-09-04 2020-07-28 Oracle International Corporation Optimization technique of generalized disjunctive semi/anti join
KR101432700B1 (ko) * 2012-10-10 2014-08-25 (주)티베로 쿼리의 최적화를 위한 방법
US10592506B1 (en) * 2013-02-13 2020-03-17 Amazon Technologies, Inc. Query hint specification
US9146984B1 (en) * 2013-03-15 2015-09-29 Google Inc. Enhancing queries for data tables with nested fields
US20150039555A1 (en) * 2013-08-02 2015-02-05 International Business Machines Corporation Heuristically modifying dbms environments using performance analytics
US10394807B2 (en) * 2013-11-27 2019-08-27 Paraccel Llc Rewrite constraints for database queries
US10621064B2 (en) 2014-07-07 2020-04-14 Oracle International Corporation Proactive impact measurement of database changes on production systems
US9779136B2 (en) * 2014-09-30 2017-10-03 Linkedin Corporation Rearranging search operators
US10229358B2 (en) * 2015-08-07 2019-03-12 International Business Machines Corporation Optimizer problem determination
US10210223B2 (en) 2015-10-27 2019-02-19 International Business Machines Corporation Executing conditions with negation operators in analytical databases
US10558458B2 (en) * 2016-06-06 2020-02-11 Microsoft Technology Licensing, Llc Query optimizer for CPU utilization and code refactoring
KR101797483B1 (ko) 2016-07-19 2017-11-15 주식회사 티맥스데이터 데이터베이스 관리 시스템에서 쿼리를 프로세싱하기 위한 기법
US11386058B2 (en) 2017-09-29 2022-07-12 Oracle International Corporation Rule-based autonomous database cloud service framework
US11327932B2 (en) 2017-09-30 2022-05-10 Oracle International Corporation Autonomous multitenant database cloud service framework
US10354203B1 (en) * 2018-01-31 2019-07-16 Sentio Software, Llc Systems and methods for continuous active machine learning with document review quality monitoring
US10733187B2 (en) * 2018-02-09 2020-08-04 International Business Machines Corporation Transforming a scalar subquery
JP7044086B2 (ja) * 2019-03-15 2022-03-30 オムロン株式会社 制御システム、制御方法、および制御プログラム
US11100104B2 (en) * 2019-04-09 2021-08-24 Accenture Global Solutions Limited Query tuning utilizing optimizer hints
US11151131B2 (en) 2019-07-19 2021-10-19 Bank Of America Corporation Query generation from a natural language input
US11409744B2 (en) * 2019-08-01 2022-08-09 Thoughtspot, Inc. Query generation based on merger of subqueries
CN111209305B (zh) * 2019-11-19 2023-07-18 华为云计算技术有限公司 查询数据的方法、数据节点、分布式数据库、计算设备
US11755579B2 (en) 2021-08-04 2023-09-12 Cysiv, Inc. Database system with run-time query mode selection
US11847121B2 (en) 2021-08-27 2023-12-19 International Business Machines Corporation Compound predicate query statement transformation

Family Cites Families (21)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
JPH022459A (ja) * 1987-12-11 1990-01-08 Hewlett Packard Co <Hp> 問合わせ処理方法
US5555409A (en) * 1990-12-04 1996-09-10 Applied Technical Sysytem, Inc. Data management systems and methods including creation of composite views of data
US5347653A (en) * 1991-06-28 1994-09-13 Digital Equipment Corporation System for reconstructing prior versions of indexes using records indicating changes between successive versions of the indexes
US5421008A (en) * 1991-11-08 1995-05-30 International Business Machines Corporation System for interactive graphical construction of a data base query and storing of the query object links as an object
US5404510A (en) * 1992-05-21 1995-04-04 Oracle Corporation Database index design based upon request importance and the reuse and modification of similar existing indexes
US6259896B1 (en) * 1994-02-15 2001-07-10 Nokia Mobile Phones Limited Device for radio communication
US5560007A (en) * 1993-06-30 1996-09-24 Borland International, Inc. B-tree key-range bit map index optimization of database queries
US5675785A (en) * 1994-10-04 1997-10-07 Hewlett-Packard Company Data warehouse which is accessed by a user using a schema of virtual tables
US5758145A (en) * 1995-02-24 1998-05-26 International Business Machines Corporation Method and apparatus for generating dynamic and hybrid sparse indices for workfiles used in SQL queries
US5806062A (en) * 1995-10-17 1998-09-08 Lucent Technologies Inc. Data analysis system using virtual databases
US5745904A (en) * 1996-01-12 1998-04-28 Microsoft Corporation Buffered table user index
US6061676A (en) * 1996-05-29 2000-05-09 Lucent Technologies Inc. Effecting constraint magic rewriting on a query with the multiset version of the relational algebric theta-semijoin operator
US5761654A (en) * 1996-06-05 1998-06-02 Oracle Corporation Memory structure and method for tuning a database statement using a join-tree data structure representation, including selectivity factors, of a master table and detail table
US5765168A (en) * 1996-08-09 1998-06-09 Digital Equipment Corporation Method for maintaining an index
US5765147A (en) * 1996-11-21 1998-06-09 International Business Machines Corportion Query rewrite for extended search capabilities
US5956707A (en) * 1997-02-13 1999-09-21 Chu; Wesley W. Database system with query relaxation using type abstraction hierarchy (TAH) as query condition relaxation structure
US6363377B1 (en) * 1998-07-30 2002-03-26 Sarnoff Corporation Search data processor
US6434545B1 (en) * 1998-12-16 2002-08-13 Microsoft Corporation Graphical query analyzer
US6205441B1 (en) * 1999-03-31 2001-03-20 Compaq Computer Corporation System and method for reducing compile time in a top down rule based system using rule heuristics based upon the predicted resulting data flow
EP1109117A1 (en) * 1999-12-14 2001-06-20 Sun Microsystems, Inc. Method for converting table data between a database representation and a representation in tag language
US7747606B2 (en) * 2003-09-06 2010-06-29 Oracle International Corporation Automatic SQL tuning advisor

Cited By (8)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN100403314C (zh) * 2006-04-19 2008-07-16 华为技术有限公司 一种数据查询方法
CN100498793C (zh) * 2007-06-08 2009-06-10 北京神舟航天软件技术有限公司 用基于小波的压缩直方图实现二维谓词选择率估计的方法
CN101436192B (zh) * 2007-11-16 2011-03-16 国际商业机器公司 用于优化针对垂直存储式数据库的查询的方法和设备
CN102968420A (zh) * 2011-08-31 2013-03-13 国际商业机器公司 数据库查询的方法和系统
CN104881460A (zh) * 2015-05-22 2015-09-02 国云科技股份有限公司 一种基于Oracle数据库实现多行数据并为一行显示的方法
CN106598963A (zh) * 2015-10-14 2017-04-26 五八同城信息技术有限公司 查询语句优化方法及装置
CN106598963B (zh) * 2015-10-14 2021-08-10 五八同城信息技术有限公司 查询语句优化方法及装置
CN106919678A (zh) * 2017-02-27 2017-07-04 武汉珞佳伟业科技有限公司 一种数据库查询优化系统及方法

Also Published As

Publication number Publication date
EP1350184A2 (en) 2003-10-08
WO2001093105A3 (en) 2003-07-31
IL152987A0 (en) 2003-06-24
BR0111192A (pt) 2005-05-10
WO2001093105A2 (en) 2001-12-06
IL152987A (en) 2009-05-04
EP1350184B1 (en) 2014-11-19
AU6504801A (en) 2001-12-11
AU2001265048B2 (en) 2007-10-18
KR20030047889A (ko) 2003-06-18
JP2004509382A (ja) 2004-03-25
US20070038618A1 (en) 2007-02-15
US8019750B2 (en) 2011-09-13
CA2409276A1 (en) 2001-12-06

Similar Documents

Publication Publication Date Title
CN1592905A (zh) 自动产生数据库查询的系统和方法
CN1155906C (zh) 数据处理方法、系统、处理程序及记录媒体
CN1204515C (zh) 自由格式数据处理的方法和设备
CN1609855A (zh) 查询优化系统和方法
CN1797399A (zh) 用于文本挖掘和搜索的应用程序编程接口
CN1524216A (zh) 软件构件插件程序结构的系统和方法
CN1679026A (zh) Web服务设备和方法
CN1766886A (zh) 用于数据管理和/或转换的数据结构、数据库系统及方法
CN1299177C (zh) 数据管理装置、计算机系统及数据处理方法
CN1604082A (zh) 用于任意数据模型的映射体系结构
CN1875345A (zh) 在编译过程中表示和检查程序组件的一致性的可扩展类型系统
CN1749999A (zh) .net数据类型和实例的持久存储
CN1689022A (zh) 可扩展标记语言流化转换器
CN1609856A (zh) 查询中间语言的方法和系统
CN1501285A (zh) 排版系统、排版程序和排版方法
CN1577324A (zh) 文档管理方法和程序、记录介质和文档管理装置
CN1359489A (zh) 用于构筑建模工具的装置和方法
CN1558348A (zh) 将基于模式的分级数据结构转换成平面数据结构的方法以及系统
CN101040292A (zh) 数据管理装置及其方法
CN1744036A (zh) 报告软件中支持定制图形表示的系统和方法
CN1774712A (zh) 在数据表中管理递归可缩放模板实例中的插入操作的系统和方法
CN101030138A (zh) 应用构架
CN1763712A (zh) 动态确定对网络主页gui环境中选定项执行的动作的方法
CN1914594A (zh) 用于创建和提供多层联网服务的方法和系统
CN1809829A (zh) 数据库装置和作成方法、数据库检索装置及检索方法

Legal Events

Date Code Title Description
C06 Publication
PB01 Publication
C10 Entry into substantive examination
SE01 Entry into force of request for substantive examination
C02 Deemed withdrawal of patent application after publication (patent law 2001)
WD01 Invention patent application deemed withdrawn after publication