在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】:

我不喜欢在您的加入条件中使用likein。使用类似的东西怎么样:

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中过滤左连接结果的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

中级测试工程师面试总结_1

SQL左连接与JOIN条件中的过滤器与WHERE子句中的过滤器[重复]

mysql左连接没有数据还会查出来吗

如何使用 group_concat 和左连接计算 mysql 查询的结果

Oracle左连接(+在等号右边),右连接(+在等号左边)

Hibernate HQL ③