【问题标题】:Oracle performance issue in getting first row in sub query在子查询中获取第一行的 Oracle 性能问题
【发布时间】:2013-01-29 03:44:46
【问题描述】:

我在使用子查询返回第一行的以下(示例)选择语句中遇到性能问题:

SELECT ITEM_NUMBER,
       PROJECT_NUMBER,       
       NVL((SELECT DISTINCT
                   FIRST_VALUE(L.LOCATION) OVER (ORDER BY L.SORT1, L.SORT2 DESC) LOCATION
            FROM   LOCATIONS L
            WHERE  L.ITEM_NUMBER=P.ITEM_NUMBER
                   AND L.PROJECT_NUMBER=P.PROJECT_NUMBER
           ),
          P.PROJECT_NUMBER) LOCATION
FROM   PROJECT P

DISTINCT 通过执行SORTUNIQUE 导致性能问题,但我想不出替代方案。

但是,我更喜欢类似于以下内容的内容,但在 2 个 select 语句中引用不起作用:

SELECT ITEM_NUMBER,
       PROJECT_NUMBER,       
       NVL((SELECT LOCATION
            FROM   (SELECT L.LOCATION LOCATION
                           ROWNUM RN
                    FROM   LOCATIONS L
                    WHERE  L.ITEM_NUMBER=P.ITEM_NUMBER
                           AND L.PROJECT_NUMBER=P.PROJECT_NUMBER
                    ORDER BY L.SORT1, L.SORT2 DESC
                   ) R
            WHERE RN <=1
           ), P.PROJECT_NUMBER) LOCATION
FROM   PROJECT P

另外: - 我的权限不允许我创建函数。 - 我在主查询中循环浏览 10k 到 100k 条记录。 - 子查询在限制为 1 行之前可以返回 3 到 7 行。

感谢任何有助于提高性能的帮助。

【问题讨论】:

  • 使用 ROW_NUMBER 代替 FIRST_VALUE
  • 您如何知道 DISTINCT 是导致您的性能问题的原因?仅仅因为您在解释计划中看到 SORT / UNIQUE 并不意味着您的查询实际上正在排序或对大量数据进行排序,更不用说对其性能产生影响了。发布您的解释计划。
  • @JeffreyKemp,+1 你提出了很好的观点。我知道 EXPLAIN PLANPERFORMANCE 之间没有直接联系(也不想争论),但是以我的方式获得解决方案所涉及的额外工作量,我确定我错过了一个简单的解决方案。我只能去当EXPLAIN来估计系统正在做的工作。

标签: sql oracle oracle10g subquery


【解决方案1】:

如果没有样本数据和基数,很难理解,但这能得到你想要的吗?唯一的项目和项目列表,第一次出现位置?

SELECT 
P.ITEM_NUMBER,
P.PROJECT_NUMBER,       
MIN(L.LOCATION) KEEP (DENSE_RANK FIRST ORDER BY L.SORT1, L.SORT2 DESC) LOCATION
FROM   
LOCATIONS L
INNER JOIN
PROJECT P
ON L.ITEM_NUMBER=P.ITEM_NUMBER
AND L.PROJECT_NUMBER=P.PROJECT_NUMBER
GROUP BY
P.ITEM_NUMBER,
P.PROJECT_NUMBER

【讨论】:

  • 是的,你是对的,这就是我需要的输出。我认为您的解决方案效果很好,肯定比我的简单得多。明天我会回复结果。
  • 您缺少 NVL,否则是的;这就是我会回答的;它保存了内联子查询(对于阅读本文的人来说,这并不总是邪恶),但更重要的是它应该更有效率。
  • 感谢我的查询从超过 2 分钟缩短到 6 秒!
  • 优秀。这些分析功能很神奇。好吧,这不是魔术,但通常是最接近灵丹妙药的解决方案。
【解决方案2】:

我过去遇到过类似的问题——虽然这不是最终的解决方案(实际上可能只是走捷径)——可以使用 OPTIMIZER_MODE 初始化参数调整 Oracle 查询优化器。

查看http://docs.oracle.com/cd/B28359_01/server.111/b28274/optimops.htm#i38318上的第 11.2.1 章

FIRST_ROWS

优化器结合使用成本和启发式方法来找到最佳计划 用于快速交付前几行。注意:使用启发式 有时会导致查询优化器生成一个有成本的计划 这比不申请的计划的成本要大得多 启发式的。 FIRST_ROWS 可用于向后兼容和 计划稳定性;请改用 FIRST_ROWS_n。

当然,您还应该分析很多其他因素,例如索引、连接效率、查询计划等。

【讨论】:

  • -1 FIRST_ROWS 是优化器提示。 OP 正在询问一个应该返回第一行的子查询 - 即 只有第一行 - 我知道这很令人困惑,但是这两件事非常不同并且有不同的目的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 1970-01-01
  • 2012-02-06
  • 2020-11-06
  • 2011-04-30
相关资源
最近更新 更多