【问题标题】:Which select Statement has better performance?哪个 select 语句性能更好?
【发布时间】:2011-04-04 03:00:09
【问题描述】:

假设master_table包含许多记录,并且master_table的“id”字段,tableA,tableB,tableC和tableD在商业意义上是相同的。

对于如下所示的 2 个选择语句,

它们会返回相同的结果集吗?

哪一个会有更好的表现?

我认为如果 tableA_tmp ,tableB_tmp,tableC_tmp 和 tableD_tmp 返回一个较小的结果集,SQL1 会比 SQL2 快,因为 oracle 不需要为每个 master_table 记录查询 tableA_tmp,,tableB_tmp,tableC_tmp 和 tableD_tmp 一次。

但是如果 tableA_tmp,tableB_tmp,tableC_tmp 和 tableD_tmp 都返回大结果集,SQL 2 会快得多,因为加入许多大结果集的成本远高于查询 tableA_tmp,,tableB_tmp,tableC_tmp 和 tableD_tmp 一次每个 master_table 记录。

如果我有任何误解,请纠正我。还是建议的其他方法?

SQL1:

select 
        master_table.* ,
        tableA_tmp.cnt as tableA_cnt , 
        tableB_tmp.cnt as tableB_cnt ,  
        tableC_tmp.cnt as tableC_cnt ,  
        tableD_tmp.cnt as tableD_cnt 
    from
        master_table,
        (select  tableA.id as id, count(1) as cnt  from tableA group by tableA.id) tableA_tmp,
        (select  tableB.id as id, count(1) as cnt from tableB group by tableB.id) tableB_tmp,
        (select  tableC.id as id, count(1) as cnt from tableC group by tableC.id) tableC_tmp,
        (select  tableD.id as id, count(1) as cnt from tableD group by tableD.id) tableD_tmp
    where 
        master_table.id = tableA_tmp.id(+) and
        master_table.id = tableB_tmp.id(+) and
        master_table.id = tableC_tmp.id(+) and
        master_table.id = tableD_tmp.id(+) ;

SQL 2:

   select 
        master_table.* ,
        (select  count(*)  from tableA where tableA.id = master_table.id) as tableA_cnt,
        (select  count(*)  from tableB where tableB.id = master_table.id) as tableB_cnt,
        (select  count(*)  from tableC where tableC.id = master_table.id) as tableC_cnt,
        (select  count(*)  from tableD where tableD.id = master_table.id) as tableD_cnt
    from
        master_table;

【问题讨论】:

  • 真的值得一试吗?

标签: sql performance oracle select


【解决方案1】:

如果主表和其他表足够大,SQL 1 会更快。原因是表扫描。表扫描很昂贵,因为扫描涉及 I/O。第一个查询只需要对表 tableA、tableB、tablec 和 tableD 中的每一个进行一次扫描。

在 SQL2 中,对于主表中的每个键,表 tableA、tableB、tablec 和 tableD 将被单独扫描。如果主表有 10 行,则表 tableA 将被扫描 10 次,tableB 将被扫描 10 次,tableC 将被扫描 10 次,依此类推。成本会很高。

示例将说明这一点。假设每个表有 1000 条记录,每条记录都有不同的 id。在第一个查询中,表 tableA、tableB、tablec 和 tableD 将分别扫描一次,并将结果连接起来。结果行数会很大,但会在合理的时间内被过滤掉。在 SQL2 中,每个表 tableA、tableB、tablec 和 tableD 将被扫描 1000 次。太贵了。

【讨论】:

    【解决方案2】:

    不同的结果集。 考虑 TableA 是否为空。

    在语句 1 中,tableA_tmp 也将为空。使用外连接,将返回一行,但 tableA_tmp.cnt 的值为 null。

    在语句 2 中,将执行计数并返回零值。

    根据卷、索引、scalar subquery caching、表聚类因子、内存...,两者的性能可能会更好或更差。

    【讨论】:

      【解决方案3】:

      联接通常比内联查询更好 - 内联查询会针对从主查询返回的每一行执行。

      这意味着(1)优于(2)。至少在 99% 的情况下。

      在少数情况下,数据的分布和定义索引的方式可以在将查询执行时间向 2 倾斜以提高效率方面发挥作用,但这在普通数据库中很少发生。

      【讨论】:

        【解决方案4】:

        在更短的时间内完成工作的人。

        【讨论】:

          【解决方案5】:

          查看执行计划

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-12-09
            • 2016-04-16
            相关资源
            最近更新 更多