需要帮助优化涉及数百万条记录的非常慢的 DB2 SQL 查询
Posted
技术标签:
【中文标题】需要帮助优化涉及数百万条记录的非常慢的 DB2 SQL 查询【英文标题】:Need help optimizing very slow DB2 SQL query touching millions of records 【发布时间】:2013-02-28 21:24:42 【问题描述】:我正在尝试优化以下 SQL,但我对 SQL 优化的了解还很浅,而且我没有取得太大进展。(由于公司政策,我概括了列和其他标识符)在当前状态下,此 SQL需要 1 到 2 分钟才能运行,具体取决于负载。 VKTINFO 表包含大约 100 万条记录,GNTINFO 表包含大约 300 万条记录。如果这是一个批处理过程,通常 1-2 分钟不会有什么大不了的,但我们有代理需要这些信息,并且尽快 - 更糟糕的是,我们的系统最终会超时并返回一个抱歉的错误用户。但是,延长超时窗口不是一种选择。我们还有其他搜索条件,例如名字、邮政编码、帐户类型、帐户状态等,但是当执行如下广泛搜索时,查询会变得相当慢。
如果有任何关于如何操纵此 SQL 以加快选择速度的建议/技术,我将非常感谢您对此事的任何想法。如果需要更多信息,我很乐意提供符合我们公司政策的尽可能多的信息。
编辑: 这里要求的是 VKTINFO 和 GNTINFO 表的索引。
account_number expiration_date 有效日期gnt_account_info 和 vkt_account_info 的索引:
pi_account_num pi_policy_num_gidgntnad 和 vktnad 表的索引:
nad_account_number nad_name_typegntpolrf 和 vktpolrf 表的索引:
xrf_account_numberselect
processing_system,
total_premium,
quote_by,
email_address,
account_number,
expiration_date,
account_state,
xrf_file,
customer_name
from
(
select
'ABCD' as processing_system,
total_premium,
quote_by,
email_address,
account_number,
expiration_date,
account_state,
xrf_file,
customer_name
from vktinfo
left outer join vkt_account_info on account_number = pi_account_number
left outer join vktpolrf on account_number = xrf_account_number
left outer join VKTNAD on account_number = nad_account_number
and history_expiration_date=nad_history_expiration_date
and nad_name_type='HA'
WHERE effective_date >= '2013-02-01'
AND effective_date <= '2013-02-28'
AND customer_name like '_SMITH%'
AND account_state = 'South Carolina'
union all
select
'EFGH' as processing_system,
total_premium,
quote_by,
email_address,
account_number,
expiration_date,
account_state,
xrf_file,
customer_name
from gntinfo
left outer join gnt_account_info on account_number = pi_account_number
left outer join vktpolrf on account_number = xrf_account_number
left outer join GNTNAD on account_number = nad_account_number
and history_expiration_date=nad_history_expiration_date
and nad_name_type='HA'
WHERE effective_date >= '2013-02-01'
AND effective_date <= '2013-02-28'
AND customer_name like '_SMITH%'
AND account_state = 'South Carolina'
)
a
order by customer_name ASC fetch first 1000 rows only WITH UR
【问题讨论】:
请发布(添加到问题中)您拥有的索引。 您可以将执行计划粘贴到您的问题中吗?联合 SELECT 语句中的 WHERE 子句是相同的;值得测试优化器是否会通过从子查询中删除两个 WHERE 子句并将其中一个粘贴到外部查询中来做出更好的决策。不过先看看执行计划。 “effective_date”和“nad_name_type”在哪些表中?这些表可能能够使用内连接而不是左连接。 同意 Mike 的观点,为了清楚你之后的任何人,或者你试图获得帮助的人,在对其他表进行任何连接时,你应该始终将列称为 table.field,以便其他人可以提供帮助,例如这种情况。将与各个列关联的表上的复合索引作为 JOIN 的一部分会得到更好的优化。 "order by customer_name" 如果您在此列上没有索引,将需要 O(n log(n)) 时间(其中 n 是应用“前 1000 个”之前结果集的大小",这可能不是问题,当然取决于结果集的大小......) 【参考方案1】:我没有可靠的答案给你。但我确实有一些你可以尝试的东西。我了解您无权获取执行计划。
请咨询已经有一段时间的人,并询问您是否应该能够运行 EXPLAIN。 您可能需要关于 account_state 的索引。经验法则:索引连接条件或 WHERE 子句中使用的每一列。有时,多列索引的性能优于多个单列索引。 尝试将您可以移动到外部查询的子查询的 WHERE 子句的每一部分,并测试两件事。 在外部查询的普通 WHERE 子句中使用这些部分。 重新排列外部查询,以便您在其上执行内部联接,而不是选择 from UNIONed 子查询。 确定是否有任何左外连接可以替换为内连接。存储“nad_name_type”的表可能是内部连接的候选者。 (你明白为什么吗?) 测试子查询作为视图实现时的性能。您可能需要 DBA 帮助。 (如果他们不允许您运行 EXPLAIN,他们可能也不允许您创建视图。) 测试子查询在实现为具体化查询表时的性能。您可能还需要 DBA 帮助。【讨论】:
迈克,谢谢你的建议。今天早上,我根据您的要点进一步深入研究了这个问题,并注意到了一个特殊性。我们有两列引用美国州 - 您建议我们放置索引的 account_state 和代表客户家庭住址状态的另一列。家庭地址状态有一个索引,而 account_state 没有(尽管在我们的 SQL 中使用)。作为概念证明,我在索引状态列中交换以代替非索引搜索 - 160 秒减少到 1.5 秒。我会考虑让 DBA 创建索引。以上是关于需要帮助优化涉及数百万条记录的非常慢的 DB2 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章