【问题标题】:Improve SELECT performance提高 SELECT 性能
【发布时间】:2016-04-19 13:25:50
【问题描述】:

现在我有一个选择查询,它基本上是 Table1 减去 table2(包括不同的记录),左连接和过滤空值。

我的查询是:

SELECT table1.serial_number, 
       table1.equip_account_number, 
       table1.equip_service_address_id, 
       table1.equip_ani_phone_number, 
       table1.equip_part_number, 
       table1.equip_polled_date, 
       table1.equip_zone_map, 
       table1.equip_return_value, 
       table1.equip_renewal_frequency, 
       table1.equip_last_renewal_date, 
       table1.equip_in_stock_date, 
       table1.equip_assigned_addresses, 
       table1.equip_link_to_serial_number, 
       table1.equip_converter_type, 
       table1.equip_converter_id, 
       table1.equip_converter_model, 
       table1.equip_converter_options, 
       table1.equip_converter_value, 
       table1.equip_emp_code, 
       table1.equip_vendor_code, 
       table1.equip_headend_code, 
       table1.equip_distributor_code, 
       table1.equip_manufacturer_code, 
       table1.equip_location_code, 
       table1.equip_group_code, 
       table1.equip_ownership_code, 
       table1.equip_secondary_conv_info, 
       table1.equip_secondary_conv_type, 
       table1.equip_second_conv_manufacturer, 
       table1.equip_second_conv_install_date, 
       table1.call_back_cycle_day, 
       table1.call_back_last_date, 
       table1.call_back_request_date, 
       table1.trx_equip_status_code, 
       table1.trx_equip_reason_code, 
       table1.tv_ind, 
       table1.int_ind, 
       table1.tel_ind, 
       table1.dwh_create_date, 
       table1.dwh_update_date, 
       table1.equip_outlet_location_code, 
       table1.equip_return_date_due, 
       table1.equip_unrecovered_ind, 
       table1.equip_delete_date, 
       table1.install_date, 
       table1.work_order_number, 
       table1.ds_work_order_number, 
       table1.disconnect_emp_code, 
       table1.disconnect_date, 
       table1.ds_equip_location, 
       table1.equip_active_in_tv_ind, 
       table1.equip_active_in_tel_ind, 
       table1.equip_active_in_int_ind, 
       table1.equip_active_intv_change_date, 
       table1.equip_active_intel_change_date, 
       table1.equip_active_inint_change_date, 
       table1.pirat_ind, 
       table1.pirat_ind_change_date, 
       table1.equip_owner 
FROM   dim_equip, 
       scd_equip 
WHERE  table2.dwh_end_date(+) = To_date('31/12/2999', 'DD/MM/YYYY') 
       AND ( table2.serial_number IS NULL 
              OR ( table1.equip_account_number <> table2.equip_account_number 
                    OR table1.equip_service_address_id <> 
                       table2.equip_service_address_id 
                    OR table1.equip_ani_phone_number <> 
                       table2.equip_ani_phone_number 
                    OR table1.equip_part_number <> table2.equip_part_number 
                    OR table1.equip_polled_date <> table2.equip_polled_date 
                    OR table1.equip_zone_map <> table2.equip_zone_map 
                    OR table1.equip_return_value <> table2.equip_return_value 
                    OR table1.equip_renewal_frequency <> 
                       table2.equip_renewal_frequency 
                    OR table1.equip_last_renewal_date <> 
                       table2.equip_last_renewal_date 
                    OR table1.equip_in_stock_date <> table2.equip_in_stock_date 
                    OR table1.equip_assigned_addresses <> 
                       table2.equip_assigned_addresses 
                    OR table1.equip_link_to_serial_number <> 
                       table2.equip_link_to_serial_number 
                    OR table1.equip_converter_type <> 
                       table2.equip_converter_type 
                    OR table1.equip_converter_id <> table2.equip_converter_id 
                    OR table1.equip_converter_model <> 
                       table2.equip_converter_model 
                    OR table1.equip_converter_options <> 
                       table2.equip_converter_options 
                    OR table1.equip_converter_value <> 
                       table2.equip_converter_value 
                    OR table1.equip_emp_code <> table2.equip_emp_code 
                    OR table1.equip_vendor_code <> table2.equip_vendor_code 
                    OR table1.equip_headend_code <> table2.equip_headend_code 
                    OR table1.equip_distributor_code <> 
                       table2.equip_distributor_code 
                    OR table1.equip_manufacturer_code <> 
                       table2.equip_manufacturer_code 
                    OR table1.equip_location_code <> table2.equip_location_code 
                    OR table1.equip_group_code <> table2.equip_group_code 
                    OR table1.equip_ownership_code <> 
                       table2.equip_ownership_code 
                    OR table1.equip_secondary_conv_info <> 
                       table2.equip_secondary_conv_info 
                    OR table1.equip_secondary_conv_type <> 
                       table2.equip_secondary_conv_type 
                    OR table1.equip_second_conv_manufacturer <> 
                       table2.equip_second_conv_manufacturer 
                    OR table1.equip_second_conv_install_date <> 
                       table2.equip_second_conv_install_date 
                    OR table1.call_back_cycle_day <> table2.call_back_cycle_day 
                    OR table1.call_back_last_date <> table2.call_back_last_date 
                    OR table1.call_back_request_date <> 
                       table2.call_back_request_date 
                    OR table1.trx_equip_status_code <> 
                       table2.trx_equip_status_code 
                    OR table1.trx_equip_reason_code <> 
                       table2.trx_equip_reason_code 
                    OR table1.tv_ind <> table2.tv_ind 
                    OR table1.int_ind <> table2.int_ind 
                    OR table1.tel_ind <> table2.tel_ind 
                    OR table1.equip_outlet_location_code <> 
                       table2.equip_outlet_location_code 
                    OR table1.equip_return_date_due <> 
                       table2.equip_return_date_due 
                    OR table1.equip_unrecovered_ind <> 
                       table2.equip_unrecovered_ind 
                    OR table1.equip_delete_date <> table2.equip_delete_date 
                    OR table1.install_date <> table2.install_date 
                    OR table1.work_order_number <> table2.work_order_number 
                    OR table1.ds_work_order_number <> 
                       table2.ds_work_order_number 
                    OR table1.disconnect_emp_code <> table2.disconnect_emp_code 
                    OR table1.disconnect_date <> table2.disconnect_date 
                    OR table1.ds_equip_location <> table2.ds_equip_location 
                    OR table1.equip_active_in_tv_ind <> 
                       table2.equip_active_in_tv_ind 
                    OR table1.equip_active_in_tel_ind <> 
                       table2.equip_active_in_tel_ind 
                    OR table1.equip_active_in_int_ind <> 
                       table2.equip_active_in_int_ind 
                    OR table1.equip_active_intv_change_date <> 
                       table2.equip_active_intv_change_date 
                    OR table1.equip_active_intel_change_date <> 
                       table2.equip_active_intel_change_date 
                    OR table1.equip_active_inint_change_date <> 
                       table2.equip_active_inint_change_date 
                    OR table1.pirat_ind <> Nvl(table2.pirat_ind, 0) 
                    OR table1.pirat_ind_change_date <> 
                       NVL(table2.pirat_ind_change_date, 
                       TO_DATE('01/01/0001', 'DD/MM/YYYY')) 
                    OR table1.equip_owner <> table2.equip_owner) )  
       AND table1.serial_number = table2.serial_number(+) 

Table1 只有唯一索引和 PK - SERIAL_NUMBER

Table2 具有唯一索引和 PK - DWH_SERIAL_KEY 和普通索引 - DWH_END_DATE, EQUIP_ACCOUNT_NUMBER, SERIAL_NUMBER

Table1 有 13MIL 记录,table2 有更多记录,但在第一个条件(END_DATE=2999) 之后,它返回 13MIL 记录。

查询大约需要 10-25 分钟,具体取决于每天到达的数据量。

任何关于如何使其更快的想法都会被应用。

【问题讨论】:

  • 您不能简单地检查 dwh_update_date 是否比您上一次 ETL 处理日期更新吗?
  • 不,不能转发@mef

标签: sql oracle performance plsql etl


【解决方案1】:

查看您的代码似乎您想要选择不在其他集合中的集合的值 如果您使用的是 Oracle,您还可以在集合上的每个操作中使用减号子句。

您的第二部分查询...

  AND ( table2.serial_number IS NULL 
          OR ( table1.equip_account_number <> table2.equip_account_number 
                OR table1.equip_service_address_id <> 
                   table2.equip_service_address_id 
                OR table1.equip_ani_phone_number <> 
                   table2.equip_ani_phone_number ...
                 ......

可以很容易地更改表 2 中数据的减号选择,尊重表 1 中的数据

以下代码只是部分示例(建议)

SELECT table1.serial_number, 
   table1.equip_account_number, 
   table1.equip_service_address_id, 
   table1.equip_ani_phone_number, 
   table1.equip_part_number, 
   ......
   ......
   table1.pirat_ind, 
   table1.pirat_ind_change_date, 
   table1.equip_owner 
FROM   table1, 


minus 

select table2.serial_number, 
   table2.equip_account_number, 
   table2.equip_service_address_id, 
   table2.equip_ani_phone_number, 
   table2.equip_part_number, 

WHERE  table2.dwh_end_date(+) = To_date('31/12/2999', 'DD/MM/YYYY') 
   AND table2.serial_number IS NULL;

【讨论】:

  • 不幸的是,它比我的查询多花 1 分钟:\
  • 奇怪,很奇怪,也尝试在日期上使用适当的索引(如果可能没有转换日期。)和序列号..也是@Raffaello.D.H.很有用。
【解决方案2】:

基本上 Edge 是对的,但大约减去了一点,他有一点错误,不需要串行 nuber IS NULL 并且在 table1 之后没有逗号我认为应该是:

  SELECT table1.serial_number, 
     table1.equip_account_number, 
     table1.equip_service_address_id, 
     table1.equip_ani_phone_number, 
     table1.equip_part_number, 
     ......
     ......
     table1.pirat_ind, 
     table1.pirat_ind_change_date, 
     table1.equip_owner 
   FROM   table1

    minus 

  select table2.serial_number, 
         table2.equip_account_number, 
         table2.equip_service_address_id, 
         table2.equip_ani_phone_number, 
         table2.equip_part_number, 
         ......
         table2.equip_owner
  From   table2
  WHERE  table2.dwh_end_date(+) = To_date('31/12/2999', 'DD/MM/YYYY'); 

但我不确定这能快多少。 希望这可以帮助你,如果你有结果,请告诉我们,对这个问题真的很感兴趣:)

【讨论】:

  • 和“(+)”也不再相关
  • 不幸的是,它比我的查询多花 1 分钟:\
【解决方案3】:

您编写的查询和使用MINUS 的变体需要比较所有列,导致性能问题。

推荐方法

我建议更新表格的建模方式,以便更轻松、更快速地识别修改过的记录。

例如,您可以跟踪每条记录的最后修改日期,以及最后一次执行数据更新过程的日期。将最后一个修改列与您的时间戳进行比较会更快地为您提供所需的记录,因为只需要比较一个列。

解决方法

如果这不适合您,您可能需要执行以下操作:

(但真的,试试推荐的方法,这是业界使用的方法,这是有原因的)。

向 table1 和 table2 添加额外的列 record_hash,填充以下内容:

ora_hash(equip_account_number||equip_service_address_id||equip_ani_phone_number||...||equip_owner)

只需确保以您想要比较记录的相同方式映射 ora_hash 中的所有列(在适当的情况下使用nvls)。

然后你可以用更简单的方式做减法逻辑:

SELECT *
FROM table1 tb1, 
   ( -- this subquery compares record from both tables and returns the serial_number of all new/modified records inside table1
    SELECT table1.serial_number, 
       table1.record_hash 
     FROM   table1
  
      minus 
  
    select table2.serial_number, 
       table2.record_hash
    From   table2
    WHERE  table2.dwh_end_date = to_date('31/12/2999', 'DD/MM/YYYY')
    ) diff
 where diff.serial_number = tb1.serial_number

ora_hashdocumented here

另外:阅读collisions

【讨论】:

  • 同意推荐的方法。在我第一次看到这个的时候,我猜它是一个普通的暗表和它的 SCD 表,所以我真的怀疑当你将结束日期设置为 2999 时仍然会得到多条记录,我认为应该有办法得到 1到 1 个序列号,这将使您的查询更快
猜你喜欢
  • 2018-09-06
  • 1970-01-01
  • 2014-06-11
  • 1970-01-01
  • 1970-01-01
  • 2016-08-25
  • 2020-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多