select语句中的子查询是否会创建任何性能降级?

时间:2017-06-20 07:00:41

标签: sql oracle performance

select po_number,
            (select t.full_name 
             from person t 
             where t.subscriber_id=358 
              and t.company_id=2
              and person_id=p.buyer_person_id) buyer_name 
from po_header p 
where subscriber_id=358 and company_id=2 ;

请看上面的例子。 伙计们,请你帮我理解select语句中的子查询性能吗?

2 个答案:

答案 0 :(得分:1)

那么,有什么可说的?对于每个po_header,您将获得某个匹配人员的姓名。我们可以自然地想到循环:

  1. 循环标题。
  2. 对于每个标题循环,通过名称并找到匹配的。
  3. 但是我们已经知道,如果存在适当的索引,DBMS可能只是使用索引来查找名称而不是遍历person表。然而,不那么明显的是,DBMS可以完全自由地在内部重新编写查询。因此,DBMS可能做的第一件事就是加入两个表,然后删除它不需要的东西。或者它可以首先创建与公司和订户ID匹配的所有名称的列表,并在以后使用它进行查找。 DBMS有很多关于如何处理表的技术,Oracle的优化器非常好。

    所以我们可能会猜到DBMS实际上做了什么,或者我们可能会看看执行计划。无论如何,这不是我们应该浪费太多时间的事情。如果查询运行良好而没有任何明显的性能问题,那么为什么要担心?一旦它显示查询 缓慢,我们就会查看执行计划并考虑要构建哪些索引,在这种情况下可能是这样的:

    create index idx1 on po_header(subscriber_id, company_id, buyer_person_id, po_number);
    create index idx2 on person(subscriber_id, company_id, person_id, full_name);
    

    查询看起来很好并且可读且因此可维护。我认为没有理由改变它。那么,我们当然可以使相关性更清晰:

    select 
      po_number,
      (
        select p.full_name 
        from person p 
        where p.subscriber_id = h.subscriber_id
          and p.company_id    = h.company_id
          and p.person_id     = h.buyer_person_id
      ) as buyer_name 
    from po_header h
    where subscriber_id = 358 and company_id = 2;
    

答案 1 :(得分:0)

这是您当前的查询:

select po_number,
       (select t.full_name from person t where t.subscriber_id=358 and
        t.company_id=2 and person_id=p.buyer_person_id) buyer_name
from po_header p
where subscriber_id=358 and company_id=2;

SELECT语句中的子查询是一种称为相关子查询的特定类型。此子查询的输出取决于外部查询或与外部查询相关。实际上,这意味着必须为po_header表的每个记录运行子查询。从性能的角度来看,这可能代价高昂。

您所写的内容的替代方法是加入您的两个表,如下所示:

SELECT
    p.po_number,
    COALESCE(t.full_name, 'NA') AS full_name
FROM po_header p
LEFT JOIN person t
    ON p.buyer_person_id = t.person_id AND
       t.subscriber_id   = 358         AND
       t.company_id      = 2
WHERE p.subscriber_id = 358 AND
      p.company_id    = 2

我希望这比原始查询执行得更好,特别是如果我们要为连接和WHERE子句中涉及的列添加索引。