【问题标题】:How to optimize mapping over several tables如何优化多个表的映射
【发布时间】:2018-06-11 22:31:04
【问题描述】:

我正在尝试优化我的代码。下面描述的解决方案工作正常,但我很确定有更好的方法来做到这一点。你有什么建议吗?

我有一张包含商业合同和一些特征属性的表格:

table_contracts
contract_number       attribute_1        attribute_2        attribute_3
123                         a                  e                   t
456                         a                  f                   s
789                         b                  g                   s

第二个表将每个合同映射到一个特定的组。这些组有不同的优先级(数字越大 => 优先级越高)。如果属性列为空,则表示不需要(=> m3 是捕获所有映射)

table_mappings
map_number    priority    attribute_1        attribute_2        attribute_3
m1                5           a                  e                   t
m2                4           a
m3                3    

因此,我需要具有最高优先级的 contract_number 和相应的 map_number。

我就是这样做的,它可以工作,但有人知道如何优化它吗?

with 
first_selection as 
  (
    select
    table_contracts.contract_number
    ,table_mappings.priority
    ,row_number() over(partition by table_contracts.contract_number order by table_mappings.priority desc)
    from table_contracts
    left join table_mappings
        on (table_contracts.attribute_1 = table_mappings.attribute_1 or table_mappings.attribute_1 is null)
        and (table_contracts.attribute_2 = table_mappings.attribute_2 or table_mappings.attribute_2 is null)
        and (table_contracts.attribute_3 = table_mappings.attribute_3 or table_mappings.attribute_3 is null)
   ),
second_selection as
   (
    select
    table_contracts.contract_number
    ,table_mappings.priority
    ,table_mappings.map_number
    from table_contracts
    left join table_mappings
        on (table_contracts.attribute_1 = table_mappings.attribute_1 or table_mappings.attribute_1 is null)
        and (table_contracts.attribute_2 = table_mappings.attribute_2 or table_mappings.attribute_2 is null)
        and (table_contracts.attribute_3 = table_mappings.attribute_3 or table_mappings.attribute_3 is null)
   )
select
first_selection.contract_number 
,second_selection.map_number
from first_selection
join second_selection 
    on first_selection.contract_number = second_selection.contract_number and first_selection.priority = second_selection.priority 
where first_selection.rn = 1

这段代码的输出是:

Results
contract_number       map_number
123                       m1
456                       m2
789                       m3

【问题讨论】:

  • 请为上述输入添加示例输出,以便更好地理解问题。
  • @vCillusion:上面的帖子已编辑!
  • 您使用的是哪个 Oracle 版本?

标签: sql oracle query-performance


【解决方案1】:

我认为您只需要其中一个选项:

with prioritized as(
   select c.contract_number, c.attribute_1, c.attribute_2, c.attribute_3, m.map_number
         ,row_number() over(
            partition by c.contract_number
                order by m.priority desc
         ) as rn
     from table_contracts     c 
     left join table_mappings m on(
          (c.attribute_1 = m.attribute_1 or m.attribute_1 is null)
      and (c.attribute_2 = m.attribute_2 or m.attribute_2 is null)
      and (c.attribute_3 = m.attribute_3 or m.attribute_3 is null)       
     )
)
select * 
  from prioritized
 where rn = 1 

【讨论】:

    【解决方案2】:

    使用与您类似的 CTE 版本尝试以下逻辑。希望对您有所帮助!

    Demo

     WITH contracts AS
            (SELECT 123 AS contract_number, 'a' AS attribute_1, 'e' AS attribute_2, 't' AS attribute_3 FROM   dual 
             UNION 
             SELECT 456, 'a', 'f', 's' FROM   dual 
             UNION SELECT 789, 'b', 'g', 's' FROM   dual
            ), 
     mappings AS
            (SELECT 'm1' AS map_number, 5  AS priority, 'a'  AS attribute_1, 'e'  AS attribute_2, 't'  AS attribute_3 FROM   dual 
             UNION 
             SELECT 'm2', 4, 'a', NULL, NULL FROM   dual 
             UNION 
             SELECT 'm3', 3, NULL, NULL, NULL FROM   dual
            ), 
     prioritymap AS
            (SELECT contract_number, 
                    map_number, 
                    Rank() over(PARTITION BY contracts.contract_number ORDER BY mappings.priority DESC) AS rank 
              FROM contracts 
                   JOIN mappings 
                      ON ( contracts.attribute_1 = mappings.attribute_1 OR mappings.attribute_1 IS NULL ) 
                         AND ( contracts.attribute_2 = mappings.attribute_2 OR mappings.attribute_2 IS NULL ) 
                         AND ( contracts.attribute_3 = mappings.attribute_3 OR mappings.attribute_3 IS NULL )
            )
    SELECT contract_number, map_number 
    FROM   prioritymap 
    WHERE  prioritymap.rank = 1
    

    【讨论】:

      【解决方案3】:

      您可以在给定的条件下简单地连接表(映射表中的属性为空或必须与合同表中的属性匹配)。然后聚合每个合约编号以获得最佳 map_number。

      select
        c.contract_number,
        max(m.map_number) keep (dense_rank last order by m.priority) as map_number
      from table_contracts c
      join table_mappings m
        on  (m.attribute_1 is null or m.attribute_1 = c.attribute_1)
        and (m.attribute_2 is null or m.attribute_2 = c.attribute_2)
        and (m.attribute_3 is null or m.attribute_3 = c.attribute_3)
      group by c.contract_number
      order by c.contract_number;
      

      无论如何,您正在为所有合同执行此操作,并且映射可能匹配任何属性组合,因此这将导致全表扫描。我能看到更快的唯一方法是并行执行。也许 DBMS 设置为自动执行此操作,否则您可以使用提示:

      select /*+parallel(4)*/
      ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-20
        • 2016-01-29
        • 1970-01-01
        • 2019-02-04
        • 1970-01-01
        相关资源
        最近更新 更多