SQL:如何使用 CASE 提高 INNER JOIN 的性能
Posted
技术标签:
【中文标题】SQL:如何使用 CASE 提高 INNER JOIN 的性能【英文标题】:SQL : How to improve performance for INNER JOIN with CASE 【发布时间】:2018-03-31 04:52:13 【问题描述】:对于需要读取过滤器的过滤器表并读取与该过滤器相关的源数据表的查询,我有一个很大的性能问题。 所以我的过滤器表看起来像这样;
FILTER_ID CUSTOMER COUNTRY DEPARTMENT
1 UK DEP1
2 CUS1 US DEP1
3 CUS1
这是我的源数据表;
ROW_NO CUSTOMER COUNTRY DEPARTMENT
1 CUS1 UK DEP1
2 CUS2 UK DEP1
3 CUS3 UK DEP1
4 CUS1 US DEP1
5 CUS1 SG DEP3
6 CUS1 UK DEP3
对于过滤表上的每个过滤器,我需要从源数据表中获取行。但是如果 FILTER 表上的列是 EMPTY,我们需要读取源数据表中存在的该列的所有成员。假设对于 FILTER_ID 1,我们需要从源表中读取 COUNTRY = UK 和 DEPARTMENT = DEP1 的所有客户。
结果表应该是这样的;
FILTER_ID ROW_NO CUSTOMER COUNTRY DEPARTMENT
1 1 CUS1 UK DEP1
1 2 CUS2 UK DEP1
1 3 CUS3 UK DEP1
2 4 CUS1 US DEP1
3 1 CUS1 UK DEP1
3 4 CUS1 US DEP1
3 5 CUS1 SG DEP3
3 6 CUS1 UK DEP3
我正在使用条件连接,它工作正常,但问题是,它非常慢!
select t1.FILTER_ID, t2.* from FILTER_TABLE as t1
inner join SOURCE_DATA as t2 on
CASE WHEN t1.CUSTOMER = '' THEN t2.CUSTOMER ELSE t1.CUSTOMER END = t2.CUSTOMER and
CASE WHEN t1.DEPARTMENT = '' THEN t2.DEPARTMENT ELSE t1.DEPARTMENT END = t2.DEPARTMENT and
CASE WHEN t1.COUNTRY = '' THEN t2.COUNTRY ELSE t1.COUNTRY END = t2.COUNTRY
有没有办法优化这段代码?
【问题讨论】:
FILTER_TABLE 修复了吗?从某种意义上说,它总是只有 3 行吗? 不,它不是固定的,它有 12K 行。源表有 85K 行,具体取决于条件。 您可以将您的CASE
语句重写为OR
的组合(因为t2.CUSTOMER = t2.CUSTOMER
几乎每次都可以(除非t2.CUSTOMER
是NULL
)),例如:@987654330 @。请检查并告诉我们结果。
你能把你的 FILTER_TABLE 分成 9 个只包含“非空”列的表吗?然后写 9 SELECT 与它们之间的联合,每个选择只连接固定列而没有任何 CASE?
@AlbertoMartinez 尝试使用“动态”参数创建一个大型“智能”查询实际上是一个非常常见的错误。结果总是令人失望,因为那些“智能”查询会导致执行计划效率低下和/或无法使用索引
【参考方案1】:
这样试试,我想,很快:
select t1.FILTER_ID, t2.* from FILTER_TABLE as t1
inner join SOURCE_DATA as t2 on
t1.CUSTOMER = t2.CUSTOMER and
t1.DEPARTMENT = t2.DEPARTMENT and
t1.COUNTRY = t2.COUNTRY
where t1.CUSTOMER <> '' and t1.DEPARTMENT <>'' and t1.COUNTRY <> ''
union all
select t1.FILTER_ID, t2.* from FILTER_TABLE as t1
inner join SOURCE_DATA as t2 on
CASE WHEN t2.CUSTOMER = t2.CUSTOMER
where t1.CUSTOMER = '' and t1.DEPARTMENT <>'' and t1.COUNTRY <> ''
union all
select t1.FILTER_ID, t2.* from FILTER_TABLE as t1
inner join SOURCE_DATA as t2 on
CASE WHEN t2.DEPARTMENT = t2.DEPARTMENT
where t1.CUSTOMER <> '' and t1.DEPARTMENT = '' and t1.COUNTRY <> ''
union all
select t1.FILTER_ID, t2.* from FILTER_TABLE as t1
inner join SOURCE_DATA as t2 on
CASE WHEN t2.COUNTRY = t2.COUNTRY
where t1.CUSTOMER <> '' and t1.DEPARTMENT <> '' and t1.COUNTRY = ''
【讨论】:
感谢您的回答,但您的解决方案也与上述类似。同时不同的列可以为空。假设 CUSTOMER = ' ' 和 DEPARTMENT = ' ' 我在产品服务器中有 12 列,如果我尝试使用所有组合,组合将会很疯狂。【参考方案2】:试试这样:
select t1.FILTER_ID, t2.* from FILTER_TABLE as t1
inner join SOURCE_DATA as t2 on
IIF(t1.CUSTOMER = '',t2.CUSTOMER, t1.CUSTOMER) = t2.CUSTOMER and
IIF(t1.DEPARTMENT = '', t2.DEPARTMENT,t1.DEPARTMENT) = t2.DEPARTMENT and
IIF(t1.COUNTRY = '',t1.COUNTRY,t2.COUNTRY) = t2.COUNTRY
【讨论】:
以上是关于SQL:如何使用 CASE 提高 INNER JOIN 的性能的主要内容,如果未能解决你的问题,请参考以下文章
SQL优化--使用 EXISTS 代替 IN 和 inner join来选择正确的执行计划
如何在 SQL Server 中使用 INNER JOIN 从多个表中删除