使用 REGEXP_SUBSTR(AGGREGATOR,'[^;]+',1,LEVEL) 时 Oracle 查询速度变慢

use*_*275 4 sql oracle

我正在使用查询来获取不同的行而不是分号分隔的值。

该表如下所示:

row_id  aggregator
1       12;45
2       25
Run Code Online (Sandbox Code Playgroud)

使用查询我希望输出如下所示:

row_id  aggregator
1       12
1       45
2       25
Run Code Online (Sandbox Code Playgroud)

我正在使用以下查询:

SELECT
DISTINCT ROW_ID,
REGEXP_SUBSTR(AGGREGATOR,'[^;]+',1,LEVEL) as AGGREGATOR
FROM DUMMY_1
CONNECT BY REGEXP_SUBSTR(AGGREGATOR,'[^;]+',1,LEVEL) IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)

即使对于 300 条记录,它也非常慢,而且我必须处理 40000 条记录。

Vin*_*rat 5

众所周知,正则表达式是昂贵的函数,因此当性能至关重要时(例如在子句中使用标准函数CONNECT BY),您应该尽量减少它们的使用。

使用标准函数(INSTRSUBSTRREPLACE)会更高效,但生成的代码将难以阅读/理解/维护。

我无法抗拒写一个递归 QTE,它比正则表达式和标准函数都高效得多。此外,递归 QTE 查询可以说具有一定的优雅性。您需要 Oracle 11.2:

WITH rec_sql(row_id, aggregator, lvl, tail) AS (
SELECT row_id, 
       nvl(substr(aggregator, 1, instr(aggregator, ';') - 1), 
           aggregator),
       1 lvl,
       CASE WHEN instr(aggregator, ';') > 0 THEN
          substr(aggregator, instr(aggregator, ';') + 1)
       END tail
  FROM dummy_1 initialization
UNION ALL
SELECT r.row_id, 
       nvl(substr(tail, 1, instr(tail, ';') - 1), tail), 
       lvl + 1, 
       CASE WHEN instr(tail, ';') > 0 THEN
          substr(tail, instr(tail, ';') + 1)
       END tail
  FROM rec_sql r
 WHERE r.tail IS NOT NULL
)
SELECT * FROM rec_sql;
Run Code Online (Sandbox Code Playgroud)

您可以在SQLFiddle上看到该解决方案性能非常好,与@ABCade 的解决方案相当。(感谢 ABCade 提供的测试用例)。