【问题标题】:SQL Multiple Joins Query-Query tuningSQL 多连接查询-查询调优
【发布时间】:2023-04-08 05:49:01
【问题描述】:

请告诉我如何调整此查询以获得更好的性能/执行时间。

PS-它是别人开发的,交给我的。

附加了查询(我知道这是一个巨大的!)--

任何关于如何使用聚合处理连接和子查询的想法都会非常有帮助。

SELECT /*+MONITOR*/ gcibjdnf.danfe,
                         gcibjdnf.bjd_situacao,
                         gcibjdnf.obs_rejeicao,
                         gcibjdnf.bjd_tipo_cobranca,
                         gcibjdnf.bjd_data_vencto_cbs,
  (SELECT SUM(gcinfitens.item_valor_contratar)
                            FROM gcinfitens
                           WHERE gcinfitens.danfe = gcibjdnf.danfe) AS nf_vl_contratar,

                         (SELECT Max(id_contgrupo) FROM gcrcontitens  WHERE gcrcontitens.danfe = gcibjdnf.danfe) AS id_contgrupo,

                         (SELECT MIN(nu_interv)
                            FROM gcrcondper
                           WHERE gcrcondper.id_cond = gcccond.id_cond
                         ) AS nu_min_prz,

                         (SELECT MAX(nu_interv)
                            FROM gcrcondper
                           WHERE gcrcondper.id_cond = gcccond.id_cond
                         ) AS nu_max_prz,

                         priper.vl_taxa AS nu_taxa,
                         priper.cd_tp_taxa,
                         priper.cd_indicador,
                         gcccond.nm_cond,
                         gcccond.cd_tp_ctr,
                         priper.sg_mod AS sg_mod_cond,
                         gcccond.dt_validade,
                         gcccond.cd_sit AS cd_sit_cond,
                         gcccond.nu_car_prz,
                         gcccond.cd_base_carencia,
                         gcccond.nu_car_desc,
                         apcconc.cd_loja,
                         apcconc.cd_concess,
                         apcconc.cd_conc_mat,
                         apcconc.nm_conc,
                         apcconc.nm_apelido,
                         apcconc.cd_tp_mercado,
                         dnccontrfundo.dt_emis_ctr
                    FROM gcibjdnf
               LEFT JOIN apcconc           ON TO_CHAR(apcconc.cd_sap_dealer) = gcibjdnf.dealer_sap
               LEFT JOIN gcccond           ON gcccond.id_cond                = gcibjdnf.id_cond
               LEFT JOIN dnccontrfundo     ON dnccontrfundo.danfe            = gcibjdnf.danfe
                                          AND dnccontrfundo.cd_sit      NOT IN ('CA','RE')
               LEFT JOIN gcrcondper priper ON priper.id_cond                 = gcccond.id_cond
                                          AND priper.sq_per = 1
                   WHERE ((    apcconc.cd_concess = '1586297'
                                      OR apcconc.cd_conc_mat = '1586297') AND gcibjdnf.bjd_situacao = 'I' AND bjd_sit_interna IN ('NO', 'SD'))

                ORDER BY apcconc.nm_apelido, danfe

【问题讨论】:

  • 你的问题不清楚..你有哪个错误? SQL Developer 中的“错误”%s:无效标识符“。” ???或““GCCCOND.ID_COND”,无效标识符“...第一个与查询中没有的参数有关..第二个是列名...确保您有...无论如何您正在使用聚合没有组的函数,这应该引发另一个错误
  • 请在代码问题中给出minimal reproducible example--剪切&粘贴&可运行代码;具有期望和实际输出的示例输入(包括逐字错误消息);标签和明确的规范和解释。这包括您可以提供的最少代码,即您显示的代码可以通过您显示的代码扩展为不可以。 (调试基础。) PS 你有一个语法错误。阅读语法。尽可能多地表明组成子表达式是可以的。明确说明您的问题是关于 那个错误 并在稍后的新帖子中询问您的总体目标。 PS 显然这里有非最小代码/数据。
  • (以下不是语法问题,而是--)了解 LEFT JOIN ON 返回的内容: INNER JOIN ON rows UNION ALL 不匹配的左表行,由 NULL 扩展。作为 OUTER JOIN 的一部分,始终知道您想要什么 INNER JOIN。 WHERE 或 INNER JOIN ON 在 OUTER JOIN ON 删除任何由 NULL 扩展的行后,需要右 [sic] 表列不为 NULL,即只留下 INNER JOIN ON 行,即“将 OUTER JOIN 转换为 INNER JOIN”。你有那个。
  • 请阅读this post on asking Oracle tuning questions。它不仅可以帮助您提出更好的问题,还可以帮助您自己调整查询。

标签: sql oracle performance query-optimization sql-tuning


【解决方案1】:

移动这一行:

LEFT JOIN gcccond ON gcccond.id_cond = gcibjdnf.id_cond

第一个连接:

FROM
  gcibjdnf
  LEFT JOIN gcccond ON gcccond.id_cond = gcibjdnf.id_cond
..................................

因为您订购连接的方式,在这些行中:

.....................
  LEFT JOIN gcrcondper gmin ON gmin.id_cond = gcccond.id_cond
  LEFT JOIN gcrcondper gmax ON gmax.id_cond = gcccond.id_cond
.........................................................

您正在尝试使用尚未在查询中定义的表的列 gcccond.id_cond
所以FROM 子句必须是:

FROM
  gcibjdnf
  LEFT JOIN gcccond ON gcccond.id_cond = gcibjdnf.id_cond
  LEFT JOIN gcinfitens ON gcinfitens.danfe = gcibjdnf.danfe
  LEFT JOIN gcrcontitens ON gcrcontitens.danfe = gcibjdnf.danfe
  LEFT JOIN gcrcondper gmin ON gmin.id_cond = gcccond.id_cond
  LEFT JOIN gcrcondper gmax ON gmax.id_cond = gcccond.id_cond
  LEFT JOIN apcconc ON TO_CHAR(apcconc.cd_sap_dealer) = gcibjdnf.dealer_sap
  LEFT JOIN dnccontrfundo ON dnccontrfundo.danfe = gcibjdnf.danfe
  AND dnccontrfundo.cd_sit NOT IN ('CA', 'RE')
  LEFT JOIN gcrcondper priper ON priper.id_cond = gcccond.id_cond
  AND priper.sq_per = 1

同样在ORDER BY 子句中,您有不合格的列danfe。 您必须使用表的名称/别名来限定它,例如 dnccontrfundo.danfegcibjdnf.danfe

【讨论】:

  • 感谢您的回复:)..我试过了,错误已删除。但是我现在收到一个新错误:“不是单组功能”。这显示在查询的第一行,即“SELECT gcibjdnf.danfe”,
  • 这个问题是由您的聚合列 SUM()、MIN()、MAX() 引起的。我不知道你想做什么,但我认为你需要一个 group by 子句。
  • 所有未聚合的列都必须在 GROUP BY 子句中(所以它会是一个巨大的)。
  • 真的很大,但我不确定要求。该查询涉及许多表,它获取的列太多,我看不到聚合点。
  • @SugandhaMishra 请在新帖子中提出新问题。但是写一个minimal reproducible example,因为这将确定引入错误的代码并帮助您自己发现错误并减少提问的需要。
【解决方案2】:

我喜欢将这样的查询分解成更小的部分,修复一个部分,然后一点一点地添加另一个部分来修复问题。

我将从 FROM 位开始:

select *
FROM gcibjdnf
LEFT JOIN apcconc
  ON TO_CHAR(apcconc.cd_sap_dealer) = gcibjdnf.dealer_sap
LEFT JOIN gcccond 
  ON gcccond.id_cond = gcibjdnf.id_cond
LEFT JOIN dnccontrfundo
  ON dnccontrfundo.danfe = gcibjdnf.danfe
  AND dnccontrfundo.cd_sit NOT IN ('CA','RE')
LEFT JOIN gcrcondper priper
  ON priper.id_cond = gcccond.id_cond
  AND priper.sq_per = 1
WHERE (
  (apcconc.cd_concess = '1586297' OR apcconc.cd_conc_mat = '1586297')
  AND gcibjdnf.bjd_situacao = 'I'
  AND gcibjdnf.bjd_sit_interna IN ('NO', 'SD') -- assume bjd_sit_interna is in gcibjdnf
)

您应该完全限定 bjd_sit_interna,以便每个人都知道它在哪个表中。

我创建的表只包含此处命名的列。这部分查询似乎“工作”,只是逻辑不一致。

  • 您对 apcconc 进行了 LEFT JOIN,因此即使 apcconc 上没有匹配项,您也应该返回一行。
  • 您有一个需要 apccon 行的 WHERE 子句,因此任何与 apcconc 不匹配的结果都将被过滤掉。实质上,您的 LEFT JOIN 已成为 INNER JOIN。

接下来,我添加了 ORDER BY 子句。

ORDER BY apcconc.nm_apelido, gcibjdnf.danfe; -- danfe must be fully qualified, else ambiguous

现在在 SELECT 列表中,您没有任何 直接 聚合函数;您只能在标量子查询中使用它们。因此,您不需要也不能在整个查询的末尾有 GROUP BY!

事实上,您的查询将按原样运行,除了 ORDER BY 中的模棱两可的列。

但是,您可能会得到奇怪的结果,因为 gcrcondper 上的 MIN 和 MAX 子查询可以访问不满足 JOIN 条件的行。你确定这是你想要的吗?

在不一致的 JOIN 逻辑和这种 MIN/MAX 怪异之外,您的查询应该可以工作。在谈论性能之前,请检查逻辑以确保查询提供了您想要的结果。

【讨论】:

  • 我对聚合函数也有同样的感觉,虽然我不确定,因为我不是 SQL 专家。由于此查询已移交给我,因此我将首先分析逻辑。谢谢:)
猜你喜欢
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
  • 2018-12-27
  • 1970-01-01
  • 1970-01-01
  • 2020-01-02
  • 2021-12-11
相关资源
最近更新 更多