提高 SELECT 性能
Improve SELECT performance
现在我有一个 select 查询,它基本上执行 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
只有 Unique index 和 PK - SERIAL_NUMBER
Table2
有唯一索引和 PK - DWH_SERIAL_KEY
和普通索引 - DWH_END_DATE, EQUIP_ACCOUNT_NUMBER, SERIAL_NUMBER
.
Table1
有 1300 万条记录,表 2 有更多但在第一个条件 (END_DATE=2999)
之后它 returns 1300 万条记录到。
查询大约需要 10-25 分钟,具体取决于每天到达的数据量。
任何关于如何让它更快的想法都会得到应用。
看你的代码似乎你想选择一个集合的值而不是在其他集合中
如果您使用的是 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 ...
......
可以很容易地改变 table 中数据的负 select 2 尊重 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,
WHERE table2.dwh_end_date(+) = To_date('31/12/2999', 'DD/MM/YYYY')
AND table2.serial_number IS NULL;
基本上 Edge 是正确的,但关于减号,他犯了一点错误不需要序列号 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');
但我不确定这能快多少。
希望这能对您有所帮助,如果您有结果,请告诉我们,对这个问题真的很感兴趣:)
您编写的查询和使用 MINUS
的变体需要比较所有列,从而导致性能问题。
推荐方法
我建议更新表的建模方式,以便更轻松、更快速地识别已修改的记录。
例如,您可以跟踪每条记录的最后修改日期,以及上次执行数据更新过程的日期。将最后修改列与您的时间戳进行比较会让您更快地获得所需的记录,因为只需要比较一列。
解决方法
如果这不适合您,您可能需要执行以下操作:
(但真的,请尝试推荐的方法,这是行业中使用的方法,这是有原因的)。
向表 1 和表 2 添加一个额外的列 record_hash
,填充内容如下:
ora_hash(equip_account_number||equip_service_address_id||equip_ani_phone_number||...||equip_owner)
只需确保以与比较记录相同的方式映射 ora_hash 中的所有列(在适当的地方使用 nvl
s)。
然后你可以用更简单的方式来做减号逻辑:
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_hash
是 documented here。
另:了解 collisions。
现在我有一个 select 查询,它基本上执行 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
只有 Unique index 和 PK - SERIAL_NUMBER
Table2
有唯一索引和 PK - DWH_SERIAL_KEY
和普通索引 - DWH_END_DATE, EQUIP_ACCOUNT_NUMBER, SERIAL_NUMBER
.
Table1
有 1300 万条记录,表 2 有更多但在第一个条件 (END_DATE=2999)
之后它 returns 1300 万条记录到。
查询大约需要 10-25 分钟,具体取决于每天到达的数据量。
任何关于如何让它更快的想法都会得到应用。
看你的代码似乎你想选择一个集合的值而不是在其他集合中 如果您使用的是 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 ...
......
可以很容易地改变 table 中数据的负 select 2 尊重 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,
WHERE table2.dwh_end_date(+) = To_date('31/12/2999', 'DD/MM/YYYY')
AND table2.serial_number IS NULL;
基本上 Edge 是正确的,但关于减号,他犯了一点错误不需要序列号 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');
但我不确定这能快多少。 希望这能对您有所帮助,如果您有结果,请告诉我们,对这个问题真的很感兴趣:)
您编写的查询和使用 MINUS
的变体需要比较所有列,从而导致性能问题。
推荐方法
我建议更新表的建模方式,以便更轻松、更快速地识别已修改的记录。
例如,您可以跟踪每条记录的最后修改日期,以及上次执行数据更新过程的日期。将最后修改列与您的时间戳进行比较会让您更快地获得所需的记录,因为只需要比较一列。
解决方法
如果这不适合您,您可能需要执行以下操作:
(但真的,请尝试推荐的方法,这是行业中使用的方法,这是有原因的)。
向表 1 和表 2 添加一个额外的列 record_hash
,填充内容如下:
ora_hash(equip_account_number||equip_service_address_id||equip_ani_phone_number||...||equip_owner)
只需确保以与比较记录相同的方式映射 ora_hash 中的所有列(在适当的地方使用 nvl
s)。
然后你可以用更简单的方式来做减号逻辑:
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_hash
是 documented here。
另:了解 collisions。