如何加快 Oracle SQL Developer 上的 REGEX LEVEL 查询

Posted

技术标签:

【中文标题】如何加快 Oracle SQL Developer 上的 REGEX LEVEL 查询【英文标题】:How to speed up REGEXP LEVEL query on Oracle SQLDeveloper 【发布时间】:2017-11-16 19:41:30 【问题描述】:

我有一个 INSERT INTO SELECT 语句,它使用源表中的 ; 解析的值填充表:

INSERT INTO PC_MATERIALS_BRIDGE (MATERIAL_BRIDGE_ID, VARIABLE_ID, MATERIAL_NAME)
   SELECT PC_VAR_MATERIALS_BRIDGE_SEQ.NEXTVAL, VARIABLE_ID, MATERIAL_NAME FROM (SELECT DISTINCT E.VARIABLE_ID, LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) MATERIAL_NAME
        FROM (SELECT VARIABLE_ID, MATERIALS FROM SRC_VARS_OCEAN_ALL WHERE MATERIALS IS NOT NULL AND MATERIALS != 'N/A) e
        CONNECT BY LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) IS NOT NULL);

所以,源表中的数据

ID     MATERIAL_NAME
1      paper
2      paper; plastic

将显示为

MATERIAL_BRIDGE_ID     MATERIAL_NAME   
1                      paper
2                      paper
3                      plastic

在目标表中。

脚本运行良好;但是,它非常昂贵,因为源表有近 40,000 条记录,有些记录具有三个值,例如,paper; plastic; rubber。我知道LEVEL 很贵。我将MATERIAL_NAME 设置为VARCHAR2(255 BYTE)。除了编写另一种类型的查询(例如,递归但可能很困难)之外,不确定如何改进。 DISTINCT 是否也会导致它变慢? DISTINCT 可能不再需要,因为 e.VARIABLE_ID 现在是主键。

【问题讨论】:

【参考方案1】:

这是一种非常低效的方法。您可以在下面的简单演示中观察为什么在删除 DISTINCT 时会导致问题:

create table SRC_VARS_OCEAN_ALL(
  VARIABLE_ID int, 
  MATERIALS varchar2(200)
);

insert into SRC_VARS_OCEAN_ALL values( 1, 'ala;ma;kota' );
insert into SRC_VARS_OCEAN_ALL values( 2, 'as;to;pies' );
insert into SRC_VARS_OCEAN_ALL values( 3, 'baba;jaga' );
insert into SRC_VARS_OCEAN_ALL values( 4, 'zupa;obiad' );

和:

SELECT  E.VARIABLE_ID, level,
        LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) MATERIAL_NAME
FROM (
    SELECT VARIABLE_ID, MATERIALS 
    FROM SRC_VARS_OCEAN_ALL 
    WHERE MATERIALS IS NOT NULL 
    AND MATERIALS != 'N/A'
) e
CONNECT BY LOWER(TRIM(REGEXP_SUBSTR(e.MATERIALS, '[^;]+', 1, LEVEL))) IS NOT NULL
order by 1,2;

VARIABLE_ID      LEVEL MATERIAL_NAME     
----------- ---------- -----------------
          1          1 ala               
          1          2 ma                
          1          2 ma                
          1          2 ma                
          1          2 ma                
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          1          3 kota              
          2          1 as                
          2          2 to                
          2          2 to                
          2          2 to                
          2          2 to                
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          2          3 pies              
          3          1 baba              
          3          2 jaga              
          3          2 jaga              
          3          2 jaga              
          3          2 jaga              
          4          1 zupa              
          4          2 obiad             
          4          2 obiad             
          4          2 obiad             
          4          2 obiad             

52 rows selected. 

此查询仅针对具有 10 个值的 4 个输入行生成 52 条输出记录。您可以猜出 4 万的数量。 该查询生成数百甚至数百万行,然后 DISTINCT 对这个庞大的结果集进行排序以消除重复。


下面的查询应该执行得更好,因为它只生成 10 条记录,不多也不少,就像完成这项任务所需的一样多:

SELECT  a.VARIABLE_ID, b.lev_el,
       trim( regexp_substr( a.MATERIALS, '[^;]+', 1, b.lev_el )) as MATERIAL_NAME
FROM SRC_VARS_OCEAN_ALL a
JOIN (
  SELECT level as lev_el
  FROM dual CONNECT BY level <= 100
) b
ON b.lev_el <= regexp_count( a.MATERIALS, ';' ) + 1

VARIABLE_ID     LEV_EL MATERIAL_NAME 
----------- ---------- --------------
          1          1 ala           
          2          1 as            
          3          1 baba          
          4          1 zupa          
          1          2 ma            
          2          2 to            
          3          2 jaga          
          4          2 obiad         
          1          3 kota          
          2          3 pies          

10 rows selected. 

我假设每个列表中的值不超过 100 个(每个单独的行都有一个列表中的值不超过 100 个),所以有 FROM dual CONNECT BY level &lt;= 100 子句。

【讨论】:

太好了,谢谢。我一直在使用DISTINCT,但忽略了在检索到所有可能的行后对行进行排序的事实。干杯。

以上是关于如何加快 Oracle SQL Developer 上的 REGEX LEVEL 查询的主要内容,如果未能解决你的问题,请参考以下文章

如何安装pl/sql developer

如何安装pl/sql developer

Oracle Sql Developer如何在Oracle中创建和设置角色?

oracle 客户端 sql developer 如何修改jdk版本

oracle 客户端 sql developer 如何修改jdk版本

如何从 Oracle sql developer 生成数据模型图