如何加速 Oracle SQL Developer 上的 REGEX LEVEL 查询
How to speed up REGEXP LEVEL query on Oracle SQLDeveloper
我有一个 INSERT INTO SELECT
语句,它使用源 table:
中的 ;
解析的值填充 table
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);
因此,源中的数据 table
ID MATERIAL_NAME
1 paper
2 paper; plastic
将显示为
MATERIAL_BRIDGE_ID MATERIAL_NAME
1 paper
2 paper
3 plastic
在目标中table。
脚本运行良好;然而,它非常昂贵,因为源 table 有近 40,000 条记录,有些有三个值,例如 paper; plastic; rubber
。我知道 LEVEL
很贵。我将 MATERIAL_NAME
设置为 VARCHAR2(255 BYTE)
。除了编写另一种类型的查询(例如,递归,但这可能很困难)之外,不确定如何改进。 DISTINCT
是否也导致它变慢? DISTINCT
可能不再需要,因为 e.VARIABLE_ID
现在是主键。
这是一种非常低效的方法。您可以在下面的简单演示中观察为什么在删除 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 <= 100
子句。
我有一个 INSERT INTO SELECT
语句,它使用源 table:
;
解析的值填充 table
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);
因此,源中的数据 table
ID MATERIAL_NAME
1 paper
2 paper; plastic
将显示为
MATERIAL_BRIDGE_ID MATERIAL_NAME
1 paper
2 paper
3 plastic
在目标中table。
脚本运行良好;然而,它非常昂贵,因为源 table 有近 40,000 条记录,有些有三个值,例如 paper; plastic; rubber
。我知道 LEVEL
很贵。我将 MATERIAL_NAME
设置为 VARCHAR2(255 BYTE)
。除了编写另一种类型的查询(例如,递归,但这可能很困难)之外,不确定如何改进。 DISTINCT
是否也导致它变慢? DISTINCT
可能不再需要,因为 e.VARIABLE_ID
现在是主键。
这是一种非常低效的方法。您可以在下面的简单演示中观察为什么在删除 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 <= 100
子句。