【问题标题】:How do you "globally" tune a SQL query so it's driven by records in a view if the view name keeps changing but query structure stays the same?如果视图名称不断变化但查询结构保持不变,您如何“全局”调整 SQL 查询,使其由视图中的记录驱动?
【发布时间】:2021-11-07 18:04:54
【问题描述】:

由于需要 15 分钟的低效查询,我有一个通过应用程序运行的 Crystal 报表需要很长时间才能运行。我们正在运行 Oracle 19.4。 CURSOR_SHARING = FORCE 用于数据库,这是每个供应商所必需的。请参阅下面的查询。

问题是,查询中的视图名称(例如下面示例中的 TW_RPT_11263_7833_199916)会根据在应用程序内部运行的查询进行更改,以提供经过过滤的记录 ID 列表。每次根据不同的应用程序查询运行报告时,都会根据特定视图的选择条件使用不同的 SQL ID。

因此,可以生成 SQL 配置文件,但它仅适用于一个查询/一个视图。即使使用 FORCE 选项生成 SQL 配置文件也不会使查询更快,因为它具有不同的视图名称 TW_RPT_####_#####,并且它没有使用在 v$sql 中看到的 sql_profile。

在查询中添加提示效果很好;查询在 1 秒内运行(参见下面的 SQL)。但是,每个用户使用不同的视图名称,这意味着应用提示仅适用于一个视图和该特定查询 ID。我也不知道如何注入这个提示;这是水晶报表。另外我不知道是否可以使用带有模式匹配的提示,例如 /*+ USE_HASH(TW_RPT_%) */ 或使用其他一些会根据视图名称更改提示的技术。

PR 表有 200 万行,而视图只有几行,所以视图需要驱动查询。

有提示 USE_HASH 的查询需要

SELECT /*+ USE_HASH(TW_RPT_11263_7833_199916)*/ "PR"."ID", "PR"."NAME", "TW_V_IMPACT_LEVEL"."S_VALUE", "PROJECT"."NAME", "PR_1"."ID", "PROJECT_1"."NAME", "PR_1"."NAME", "PR_STATUS_TYPE_1"."NAME", "PR_STATUS_TYPE"."NAME", "PR_1"."PARENT_ID", "PROJECT_2"."NAME", "TW_RPT_11263_7833_199916"."ID", "TW_V_DESCRIPTION"."TEXT", "TW_V_MATERIAL_CONTINUATION_DEC"."TEXT", "TW_V_DESCRIPTION_1"."TEXT", "TW_V_JUSTIFICATION"."TEXT", "TW_V_CLOSURE_SUMMARY"."TEXT", "TW_V_QI_CLOSURE_SUMMARY"."TEXT" FROM   (((((((((((((("TRACKWISE_OWNER"."PR" "PR" LEFT OUTER JOIN "TRACKWISE_OWNER"."PR" "PR_1" ON "PR"."ID"="PR_1"."ROOT_PARENT_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_DESCRIPTION" "TW_V_DESCRIPTION" ON "PR"."ID"="TW_V_DESCRIPTION"."PR_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_MATERIAL_CONTINUATION_DEC" "TW_V_MATERIAL_CONTINUATION_DEC" ON "PR"."ID"="TW_V_MATERIAL_CONTINUATION_DEC"."PR_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_IMPACT_LEVEL" "TW_V_IMPACT_LEVEL" ON "PR"."ID"="TW_V_IMPACT_LEVEL"."PR_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."PROJECT" "PROJECT" ON "PR"."PROJECT_ID"="PROJECT"."ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."PR_STATUS_TYPE" "PR_STATUS_TYPE" ON "PR"."STATUS_TYPE"="PR_STATUS_TYPE"."ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_CLOSURE_SUMMARY" "TW_V_CLOSURE_SUMMARY" ON "PR"."ID"="TW_V_CLOSURE_SUMMARY"."PR_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_QI_CLOSURE_SUMMARY" "TW_V_QI_CLOSURE_SUMMARY" ON "PR"."ID"="TW_V_QI_CLOSURE_SUMMARY"."PR_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."PROJECT" "PROJECT_1" ON "PR_1"."PROJECT_ID"="PROJECT_1"."ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_DESCRIPTION" "TW_V_DESCRIPTION_1" ON "PR_1"."ID"="TW_V_DESCRIPTION_1"."PR_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."PR_STATUS_TYPE" "PR_STATUS_TYPE_1" ON "PR_1"."STATUS_TYPE"="PR_STATUS_TYPE_1"."ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."PR" "PR_2" ON "PR_1"."PARENT_ID"="PR_2"."ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_JUSTIFICATION" "TW_V_JUSTIFICATION" ON "PR_1"."ID"="TW_V_JUSTIFICATION"."PR_ID") LEFT OUTER JOIN "TRACKWISE_OWNER"."PROJECT" "PROJECT_2" ON "PR_2"."PROJECT_ID"="PROJECT_2"."ID") INNER JOIN "TRACKWISE_OWNER"."TW_RPT_11263_7833_199916" "TW_RPT_11263_7833_199916" ON "PR"."ID"="TW_RPT_11263_7833_199916"."ID" WHERE  ("PROJECT"."NAME"='Quality Investigation - SC' OR "PROJECT"."NAME"='Quality Issue')

我正在寻找任何想法来帮助 Oracle 找出具有这种结构的查询的最佳连接顺序,而不管视图的名称如何 (TW_RPT_####-######)。可以肯定地假设视图的行数总是比 PR 表少得多。

以下是应用程序根据最终用户在运行报告之前在应用程序查询中指定的内容创建的示例视图:

**TW_RPT_11263_7833_199916:**
  CREATE OR REPLACE FORCE EDITIONABLE VIEW "TRACKWISE_OWNER"."TW_RPT_11263_7833_199916" ("ID") DEFAULT COLLATION "USING_NLS_COMP"  AS 
  SELECT DISTINCT PR.id 
FROM 
    pr, project , Project_member, Group_member 
WHERE 
    project.id = pr.project_id AND 
    pr.id IN (
        SELECT 
            pr_addtl_data.pr_id 
        FROM 
            pr_addtl_data 
        WHERE 
            pr_addtl_data.pr_id = pr.id AND 
            pr_addtl_data.data_field_id = 573 AND 
            pr_addtl_data.n_value IN (6164231)
    ) AND PR.project_parent_id IN(366,279,395,396) AND Project_member.project_id = PR.project_parent_id AND Group_member.project_member_id = Project_member.id AND Project_member.person_rel_id = 13836 AND ((Project_member.view_all = 1) OR (Project_member.view_self_created = 1 and PR.created_by_rel_id = 13836) OR (Project_member.view_assigned_to = 1 and PR.responsible_rel_id = 13836) OR (Project_member.view_group_created = 1 and PR.user_group_id = Group_member.user_group_id) OR (Project_member.view_by_entity = 1 and PR.entity_id = 1251));

视图的结果是两个记录 ID,如下所示,以毫秒为单位返回: 2012202 和 2012397

【问题讨论】:

  • 而不是使用提示,您应该首先问为什么 Oracle 不使用 HASH JOIN。是否经常正确地计算统计数据?如果您定期计算统计数据并且计划仍然是问题,那么 Oracle 可能出于某种原因使用 NESTED LOOPS 而不是 HASH JOIN(可能是索引?)。另一方面,虽然视图名称发生了变化,但如果后面的查询是相同的,还有其他比 SQL Profiles 更好的技术来强制执行不同的计划,而无需触及视图或 Cristal Reports 中的代码....跨度>
  • ... 一个想法是使用 SQL 基线。我自己这样做是为了在不触及查询的情况下更改关闭产品的查询计划
  • 您可以控制查询生成过程吗?您可以使用一些常量表别名并在提示中指定它。那么你就不需要关心表名了
  • 您是否考虑过向 Crystal 的客户支持团队询问此事?这是一个昂贵的软件产品,他们确实有称职的支持人员。值得一试。
  • 统计数据是最近计算的,不会过时。 8 小时长的查询 SQL 调优建议没有提供额外的推荐索引。视图后面的查询不断变化,视图名称也不断变化,因此我不知道 sql 基线是否可以在这里工作,一次只有一个查询。如果我们无法通过应用程序供应商获得支持,我喜欢询问 Crystal Reports 供应商的想法。

标签: oracle query-optimization crystal-reports-2016


【解决方案1】:

一种选择是使用命令作为报告的数据源。 一个参数可以控制Command语法中使用的Table/View。

【讨论】:

  • 这是一个有趣的想法,谢谢。您知道在构建命令时是否可以在 SQL 中包含 Oracle SQL 查询提示?我不知道这是否可能。
【解决方案2】:

只需为别名使用更好的命名:使用比TW_RPT_11263_7833_199916 更常见的名称。例如,不要使用 INNER JOIN "TRACKWISE_OWNER"."TW_RPT_11263_7833_199916" "TW_RPT_11263_7833_199916" 而是使用 INNER JOIN "TRACKWISE_OWNER"."TW_RPT_11263_7833_199916" "TW_RPT_JOINED" 并将其用于提示

SELECT /*+ USE_HASH(TW_RPT_JOINED)*/ 
    "PR"."ID", 
    "PR"."NAME", 
    "TW_V_IMPACT_LEVEL"."S_VALUE", 
    "PROJECT"."NAME", 
    "PR_1"."ID", 
    "PROJECT_1"."NAME", 
    "PR_1"."NAME", 
    "PR_STATUS_TYPE_1"."NAME", 
    "PR_STATUS_TYPE"."NAME", 
    "PR_1"."PARENT_ID", 
    "PROJECT_2"."NAME", 
    "TW_RPT_JOINED"."ID", 
    "TW_V_DESCRIPTION"."TEXT", 
    "TW_V_MATERIAL_CONTINUATION_DEC"."TEXT", 
    "TW_V_DESCRIPTION_1"."TEXT", 
    "TW_V_JUSTIFICATION"."TEXT", 
    "TW_V_CLOSURE_SUMMARY"."TEXT", 
    "TW_V_QI_CLOSURE_SUMMARY"."TEXT" 
FROM   
    (
        (
            (
                (
                    (
                        (
                            (
                                (
                                    (
                                        (
                                            (
                                                (
                                                    (
                                                        ("TRACKWISE_OWNER"."PR" "PR" 
                                                        LEFT OUTER JOIN "TRACKWISE_OWNER"."PR" "PR_1" 
                                                            ON "PR"."ID"="PR_1"."ROOT_PARENT_ID"
                                                        ) 
                                                    LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_DESCRIPTION" "TW_V_DESCRIPTION" 
                                                        ON "PR"."ID"="TW_V_DESCRIPTION"."PR_ID"
                                                    ) 
                                                    LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_MATERIAL_CONTINUATION_DEC" "TW_V_MATERIAL_CONTINUATION_DEC" 
                                                        ON "PR"."ID"="TW_V_MATERIAL_CONTINUATION_DEC"."PR_ID"
                                                ) 
                                                LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_IMPACT_LEVEL" "TW_V_IMPACT_LEVEL" 
                                                    ON "PR"."ID"="TW_V_IMPACT_LEVEL"."PR_ID"
                                            ) 
                                            LEFT OUTER JOIN "TRACKWISE_OWNER"."PROJECT" "PROJECT" 
                                                ON "PR"."PROJECT_ID"="PROJECT"."ID"
                                        ) 
                                        LEFT OUTER JOIN "TRACKWISE_OWNER"."PR_STATUS_TYPE" "PR_STATUS_TYPE" 
                                            ON "PR"."STATUS_TYPE"="PR_STATUS_TYPE"."ID"
                                    ) 
                                    LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_CLOSURE_SUMMARY" "TW_V_CLOSURE_SUMMARY" 
                                        ON "PR"."ID"="TW_V_CLOSURE_SUMMARY"."PR_ID"
                                ) 
                                LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_QI_CLOSURE_SUMMARY" "TW_V_QI_CLOSURE_SUMMARY" 
                                    ON "PR"."ID"="TW_V_QI_CLOSURE_SUMMARY"."PR_ID"
                            ) 
                            LEFT OUTER JOIN "TRACKWISE_OWNER"."PROJECT" "PROJECT_1" 
                                ON "PR_1"."PROJECT_ID"="PROJECT_1"."ID"
                        ) 
                        LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_DESCRIPTION" "TW_V_DESCRIPTION_1" 
                            ON "PR_1"."ID"="TW_V_DESCRIPTION_1"."PR_ID"
                    ) 
                    LEFT OUTER JOIN "TRACKWISE_OWNER"."PR_STATUS_TYPE" "PR_STATUS_TYPE_1" 
                        ON "PR_1"."STATUS_TYPE"="PR_STATUS_TYPE_1"."ID"
                ) 
                LEFT OUTER JOIN "TRACKWISE_OWNER"."PR" "PR_2" 
                    ON "PR_1"."PARENT_ID"="PR_2"."ID"
            ) 
            LEFT OUTER JOIN "TRACKWISE_OWNER"."TW_V_JUSTIFICATION" "TW_V_JUSTIFICATION" 
                ON "PR_1"."ID"="TW_V_JUSTIFICATION"."PR_ID"
        ) 
        LEFT OUTER JOIN "TRACKWISE_OWNER"."PROJECT" "PROJECT_2" 
            ON "PR_2"."PROJECT_ID"="PROJECT_2"."ID"
    ) 
    INNER JOIN "TRACKWISE_OWNER"."TW_RPT_11263_7833_199916" "TW_RPT_JOINED" 
        ON "PR"."ID"="TW_RPT_JOINED"."ID" 
WHERE  ("PROJECT"."NAME"='Quality Investigation - SC' OR "PROJECT"."NAME"='Quality Issue')

PS。 “精彩”的 SQL 生成器 - 为什么有这么多 (((()))))...

【讨论】:

  • 那是 Cristal Reports 的 Java 生成器。我在 SAP Business Objects 中也看到了这一点。确实很棒:)
  • 我尝试了通用别名而不是特定的视图名称,它成功了!现在我需要弄清楚如何让 Crystal 报表使用通用别名,并将提示嵌入到查询中。有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
  • 2020-01-24
  • 1970-01-01
  • 2019-08-08
  • 1970-01-01
  • 2015-08-10
  • 1970-01-01
相关资源
最近更新 更多