【问题标题】:Join conditions on multiple columns versus single join on concatenated columns?多列的连接条件与连接列的单连接?
【发布时间】:2015-07-09 06:53:25
【问题描述】:

我观察到有两种方法可以在多个表上实现目标。结果集中的一列将被更新,并且可能需要速度。结果集通过以下方式获得:

案例一:

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 eval_report_dup@prod 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;

案例 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 eval_report_dup@prod 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;

两者都给出相同的结果,只有连接条件不同。哪个运行/执行更快?

eval_id 是 NUMBER,report_type 和 course_name 是 VARCHAR2

从使用的开发人员那里,案例 1 具有以下统计信息:[SELECT - 3077 row(s), 0.048 secs] 获取的结果集 ... 1 条语句执行,3077 行受影响,执行/获取时间:0.048/0.236 秒 [1 成功,0 警告,0 错误]

while case 2: [SELECT - 3077 row(s), 0.019 secs] 获取结果集 ... 1 条语句执行,3077 行受影响,执行/获取时间:0.019/0.194 秒 [1 成功,0 警告,0 错误]

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

【问题讨论】:

  • 连接的版本不能利用索引来优化连接。

标签: sql oracle join dbvisualizer


【解决方案1】:

我认为具有连接的版本实际上总是会更慢。

如果您单独比较的任何列都有索引,那么数据库通常能够使用索引来优化连接。当你比较连接时,它必须执行全表扫描,因为计算的结果不会在索引中。

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

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

【讨论】:

    【解决方案2】:

    很简单,加入各个列是正确的。连接到连接值是不正确的。抛开任何关于性能的讨论,您应该编写正确的代码。

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

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

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

    【讨论】:

    • 感谢@Justin,尤其是连接可能出现的错误。
    【解决方案3】:

    这取决于表上的索引。通常,索引是使用列列表定义的,而不是使用列的连接(作为表达式)定义的,因此根据经验,第二个版本像往常一样使用索引更快。

    也就是说,dba 可能(无论出于何种原因,可能是醉酒或精神错乱)决定在列的串联上创建一个索引。在这种情况下,语句的第一个版本可以使用索引,而第二个版本不能。

    【讨论】:

    • 感谢@ammoQ 的洞察力。另一篇文章给出了在某些情况下不鼓励串联不正确的充分理由。
    猜你喜欢
    • 1970-01-01
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    • 2021-09-10
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多