【问题标题】:Oracle query fine tuningOracle 查询微调
【发布时间】:2015-01-14 07:50:07
【问题描述】:

您好,我有一个包含大量记录的数据库,大约 400K,应该会增长更多。

我有一个查询要从该表中获取数据以向用户显示记录。我的查询如下。

    SELECT  "PC0".PYID   AS "pyID" ,
  "PC0".NAME                 AS "Name" ,
  "PC0".OPPORTUNITYSTAGE     AS "OpportunityStage" ,
  "PC0".PXCREATEOPNAME       AS "pxCreateOpName" ,
  "PC0".PZINSKEY             AS "pzInsKey" ,
  "PC0".OPPORTUNITYSHORTNAME AS "OpportunityShortName" ,
  "PC0".IDTYPE               AS "IDType" ,
  "PC0".IDNO                 AS "IDNo" ,
  "Campaign".PROGRAMNAME     AS "ProgramName" ,
  "Campaign".ENDDATE         AS "EndDate" ,
  "PC0".PRODUCTNAME          AS "ProductName" ,
  "PC0".PRODUCTTYPE          AS "ProductType" ,
  "PC0".OPPORTUNITYSTAGE     AS "OpportunityStage" ,
  "PC0".PXCREATEOPNAME       AS "pxCreateOpName" ,
  "PC0".OPPORTUNITYSOURCE    AS "OpportunitySource" ,
  "PC0".OPPORTUNITYOWNER     AS "OpportunityOwner" ,
  "PC0".IDTYPE
  ||"PC0".IDNO                                                          AS "pyTextValue(1)" ,
  "PC0".REMINDERDATE                                                    AS "ReminderDate" ,
  "PC0".STAGELASTCHANGED                                                AS "StageLastChanged" ,
  ROUND((CAST(SYSDATE AS DATE) - CAST("PC0".STAGELASTCHANGED AS DATE))) AS "pyIntegerValue(1)" ,
  (
  CASE
    WHEN ROUND((CAST(SYSDATE AS DATE) - CAST("PC0".REMINDERDATE AS DATE))) > 0
    THEN 1
    WHEN ROUND((CAST(SYSDATE AS DATE) - CAST("PC0".STAGELASTCHANGED AS DATE))) > 7
    THEN 2
    ELSE 3
  END)                                                              AS "pyIntegerValue(2)" ,
  "PC0".PXCREATEDATETIME                                            AS "pxCreateDateTime" ,
  "PC0".CAMPAIGNID                                                  AS "CampaignID" ,
  ROUND((CAST(SYSDATE AS DATE) - CAST("PC0".REMINDERDATE AS DATE))) AS "pyIntegerValue(3)"
FROM MYCO_OPPORTUNITY "PC0"
LEFT OUTER JOIN MYCO_CAMPAIGN "Campaign"
ON ( "PC0".CAMPAIGNID = "Campaign".PYID)
ORDER BY 21 ASC,
  22 DESC 

在 SQl developer 中获取前 50 条记录大约需要 13 秒。我一次将实时获取近 5k 条记录。

在我为 REMINDERDATE 和 STAGELASTCHANGED 列上的 CAST 定义功能索引以及位图连接索引之后,13 秒的时间即将到来。

您能否建议我应该如何优化查询。大集合的顺序可能是一个问题,这对我来说是必须的。 :(

【问题讨论】:

  • 向我们展示解释计划并检查是否使用了索引。
  • @SylvainLeroux 我们需要获取排序结果。比如第一个超过提醒日期的记录,然后是超过7天没有跟进的记录,然后是其他记录。
  • 看看我是否理解得很好:当你禁用该功能时。指数,你有不错的表现。当它启用时,它太长了?如果是这样,您能否比较两个执行计划?此外,您有没有办法在 minimal example 上重现该行为,以便我们能够对其进行测试?
  • @SylvainLeroux 没有 Sylvain。我不想减少检索结果所花费的时间。最初我得到 18 秒。我定义了两个功能索引,现在我得到了 13 秒。有办法吗?我们可以进一步减少。 Order by 似乎是罪魁祸首,因为如果我删除“order by”,我会在 1 秒内得到结果。但我的业务需要有序数据!!
  • 在弄清楚查询中的瓶颈是什么之前,您无法优化查询。这是你的第一个目标。看看这篇文章 - 它有基础知识docs.oracle.com/database/121/TGSQL/tgsql_interp.htm#TGSQL94618。在您发布带有统计信息的执行计划后 - 我们可能会提供帮助

标签: oracle query-optimization


【解决方案1】:

确保您在“PC0”.CAMPAIGNID 和“Campaign”.PYID 上有一个索引

确保您的 SGA 设置得足够高。在不了解有关服务器和数据库的大量信息的情况下,除了确保 SGA 足够大之外,很难提供指导。

【讨论】:

    【解决方案2】:

    您在计算列上使用“排序依据”,这意味着 Oracle 必须先计算所有 400k 行的该值,然后才能对结果进行排序和返回。确定这是不使用 order by 的问题测试。

    有许多可能的解决方案,但这个示例似乎不是您的实际用例,因此建议对其进行优化几乎没有意义

    如果没有更多关于数据的知识,我建议将查询分成与联合相关的三个部分,并在提醒日期和 stagelastchanged 上实现索引。

    select * from ( [part 1] where reminderdate > sysdate order by pxCreateDateTime ) 
    union all
    select * from ( [part 2] where reminderdate <= sysdate and stagelastchanged + 7 < sysdate order by pxCreateDateTime ) 
    union all
    select * from ( [part 3] where reminderdate <= sysdate and stagelastchanged + 7 >= sysdate order by pxCreateDateTime )
    

    然后我希望 1. 和 2. 应该使用索引和 3. 全表扫描来满足,这可能会通过添加 first_rows 提示来帮助。

    【讨论】:

    • 这是我的实际用例。我需要先获取已超过提醒日期的记录,然后获取 7 天未跟进的记录,然后再获取其余记录。代码也是如此.. ROUND((CAST(SYSDATE AS DATE) - CAST("PC0".REMINDERDATE AS DATE))) > 0 WHEN ROUND((CAST(SYSDATE AS DATE) - CAST("PC0".STAGELASTCHANGED AS DATE) ))) > 7
    • 所以您没有以任何其他方式限制所选结果?
    • 'No' 截至目前;但可以根据查询的性能将最大记录数限制为 5000。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 2017-03-02
    • 2015-04-04
    • 1970-01-01
    • 2020-01-25
    相关资源
    最近更新 更多