2015-04-29 173 views
2

我注意到有两种方法可以在多个表上实现一个目标。结果集中的列将被更新并且速度可能是需求。结果集获得或者通过:在连接的列上连接多个列与单个连接的条件?

情况1:

select ert.* 
from eval_rep_track ert 
inner join 
(
     select erp.evaluation_fk, erp.report_type, LTRIM(erp.assign_group_id, '/site/') course_name 
     from [email protected] erp 
     inner join eval_report er 
     on er.id = erp.id 
     where erp.status='queue' 
     and er.status='done' 
) cat 

on ert.eval_id || '.' || ert.report_type || '.' || ert.course_name = cat.evaluation_fk || '.' || cat.report_type || '.' || cat.course_name; 

OR

情况2:

select ert.* 
from eval_rep_track ert 
inner join 
(
     select erp.evaluation_fk, erp.report_type, LTRIM(erp.assign_group_id, '/site/') course_name 
     from [email protected] erp 
     inner join eval_report er 
     on er.id = erp.id 
     where erp.status='queue' 
     and er.status='done' 
) cat 
on ert.eval_id = cat.evaluation_fk 
and ert.report_type = cat.report_type 
and ert.course_name = cat.course_name; 

既给出相同的结果,与仅连接条件而变化。哪个会更快运行/ exec?

eval_id是NUMBER,report_type和course_name是VARCHAR2

从使用的开发人员,情况1具有以下统计信息:[SELECT - 3077行,0.048秒]获取结果集 ... 1个语句执行,3077行受影响,exec /读取时间:0.048/0.236秒[1次成功,0次警告,0次错误]

while case 2:[SELECT - 3077 row,s0,0.019 secs]取出结果集 ... 1 statement(s) 3077行受到影响,执行/读取时间:0.019/0.194秒[1次成功,0次警告,0次错误]

结果表明案例2更快。这是否会在任何平台(IDE,开发人员)和数据库中通用?这是依赖于数据类型还是串联总是很昂贵?我实际上并不需要连接的结果。谢谢。

+0

带连接的版本无法利用索引来优化连接。 – Barmar

回答

3

我认为带连接的版本实际上总是比较慢。

如果您正在比较的任何列都有索引,数据库通常可以使用索引来优化联接。在比较连接时,必须执行全表扫描,因为计算结果不在索引中。

即使列未被索引,数据库仍然可以更有效地执行比较。它一次比较一对列,并且只要其中一个比较失败就会停止。在使用连接时,必须先将两行中的所有列组合起来,然后进行字符串比较。

最后,如果任何列是数字的,则连接需要将数字转换为字符串的附加步骤。

0

它取决于表上的索引。通常,索引是使用列列表定义的,但不能与列连接(作为表达式)一起定义,因此按照经验法则,第二个版本的索引编制速度更快。

也就是说,dba可能(无论出于什么原因,可能是中毒或精神错乱)决定在列的连接上创建索引。在这种情况下,声明的第一个版本可以使用索引,而不使用第二个版本。

+0

感谢@ammoQ的洞察力。另一篇文章给出了坚定的理由,阻止连接在某些情况下是不正确的。 – paxmemento

3

很简单,加入各个栏目是正确的。加入级联值不正确。与任何性能讨论分开,你应该写出正确的代码。

对于任何特定的查询,您可以使用连接编写大多数正确的查询。但是当你得到你不希望的数据时,你几乎肯定会引入一些微妙的错误,这些错误会咬你。在这种情况下,只要列中包含句点,就可能会错误地匹配数据('a.b' || '.' || null = 'a' || '.' || 'b.')。在其他情况下,您还会遇到其他一些细微问题 - 日期和数字可能会隐式转换为字符串,使用不同的会话级别设置,可能会产生不同的结果(您的NLS_DATE_FORMAT可能包含时间组件,或者它可能不包含您的连接值或者可能不包括时间的比较)。如果您通常连接列,那么最终会出现许多基于表中数据和执行代码的用户具有非常微妙的错误的查询。从维护和支持的角度来看这很糟糕。性能应该至多是次要的问题。

从性能角度来看,正确的连接几乎可以肯定会超越连接方式。当您正确连接时,优化程序可以在生成查询计划时考虑作为连接一部分的各个列上的普通索引。如果您将值连接起来,Oracle最多可以对正常索引进行全面扫描,以获取需要连接在一起的所有数据。但是这可能效率要低得多(特别是当你有超过几千行时)。

从理论上讲,连接方法对于某个查询某个地方会更有效吗?当然。一个虐待开发者可能会在连接结果上创建一个基于函数的索引,避免在各个列上创建索引,并生成一个连接方法更有效的测试用例。但是,通过在基本列上创建适当的相应索引(或索引),可以很容易地进行补救。对于某些查询,连接可能会更有效,因为它会阻止优化器使用它原本想要使用的索引吗?当然。但是,这几乎可以肯定地表明,您在优化程序设置或统计信息方面存在问题,应该解决该问题,而不是在该问题上使用创可贴。

+0

谢谢@Justin,特别是在串联可能不正确的情况下。 – paxmemento