在oracle中过滤左连接结果的最佳方法
Posted
技术标签:
【中文标题】在oracle中过滤左连接结果的最佳方法【英文标题】:Optimal way to filter the left join result in oracle 【发布时间】:2017-12-08 20:04:18 【问题描述】:我正在使用 4 个表进行选择,其中一个有 670 万行。在 table_1 我有一些主要代码,在 table_2(有 670 万行的那个)我有主要代码的子代码,如下所示:
Table_1 Table_2
| code | | code |
| A1 | | A1A |
| A11 | | A1B |
| A2 | | A2A |
| A22 | | A22 |
规则是,代码总是有一个或两个字母和一个数字(有1、2或3位数字),子代码是相同的代码,或者是相同的代码+一个字母。所以,我做了这样的左连接:
SELECT t1.code, t2.subcode
FROM table_1 t1
LEFT JOIN table_2 t2
ON t2.subcode LIKE t1.code || '%' AND
substr(replace(t2.subcode, t1.code, ''), 1, 1) not in ('0', '1', '2', '3',
'4', '5', '6', '7', '8', '9')
这是可行的,但是,因为 Table_2 有 6.7M 的结果,即使 2 列有索引,查询(与其他 2 个表连接)需要 6~7 分钟才能解决,我需要在更短的时间内完成. 那么,有人知道如何优化这个查询吗?
【问题讨论】:
【参考方案1】:就在代码上的table2
上创建一个索引:
create index idx_table2_code
on table2(case when substr(code, 3, 1) between 'A' and 'Z'
then substr(code, 1, 2) else code
end);
然后用这个作为join
中的表达式:
select t1.code, t2.subcode
from table_1 t1 left join
table_2 t2
on t1.code = (case when substr(code, 3, 1) between 'A' and 'Z'
then substr(code, 1, 2) else code
end);
join
应该可以使用索引。
【讨论】:
或者更好的是,将其分成两个单独的字段。将两个字段合二为一,这让我大错特错。 我做了一些简单的例子,但代码不是那么标准。代码可以是 A10 和子代码 A10_B2。我在列上有一个索引,但只是一个简单的索引,因为子代码的变体太多了。但我会尝试考虑另一个索引,如果我成功了,我会来这里回应 我编辑了这个问题的“代码规则”,因为它们比我想的更复杂【参考方案2】:我不喜欢在您的加入条件中使用like
和in
。使用类似的东西怎么样:
SELECT t1.code, t2.subcode
FROM table_1 t1
LEFT JOIN table_2 t2
ON t2.subcode = t1.code || 'A' OR
t2.subcode = t1.code || 'B' OR ...
如果您只有几个子代码,只有字母表的前几个字母,那么这样做可能会快很多。或者,你可以试试
SELECT t1.code, t2.subcode
FROM table_1 t1
LEFT JOIN table_2 t2
ON SUBSTR(t2.subcode, 0, LENGTH(t1.code)) == t1.code AND
SUBSTR(t2.subcode, LENGTH(t1.code) + 1, LENGTH(t2.subcode)-LENGTH(t1.code)) IN ('A', 'B', 'C', 'D'...)
【讨论】:
以上是关于在oracle中过滤左连接结果的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
SQL左连接与JOIN条件中的过滤器与WHERE子句中的过滤器[重复]