Более быстрый способ обновления в Oracle - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть таблица со столбцом recordid, например

recordid
----------
1001
1002
1003...

, и другая таблица, в которой записи сохраняются в пользовательском |разделенная строка как

col1
-------
1001|1002|...
|1003|1001|...
|||1002|...

Я хочу удалить все вхождения некоторых идентификаторов записей во второй таблице - например, 1001. В настоящее время я делаю обновление, используя замену из сценария PHP, но время ожидания истекло из-заобъем записей - во второй таблице более 20 миллионов записей.

Есть ли альтернативный более быстрый способ добиться того же? Я пытаюсь использовать регулярные выражения в настоящее время, но не уверен, что это будет быстрее. Любые предложения / указатели приветствуются.

Edit1: текущий код для обновления - который истекает -

update table2 set col1 = replace(col1, '1001', '')
where  col1 like '%|1001|%'
or     col1 like '1001|%'

1 Ответ

2 голосов
/ 01 ноября 2019

Это всего лишь пример;поскольку есть миллионы строк, я понятия не имею, как он будет работать, то есть будет ли он хотя бы немного быстрее, чем ваш REPLACE. В любом случае - посмотрите, попробуйте, если хотите.

Сначала тестовый пример:

SQL> create table first (id number);

Table created.

SQL> create table second (id number, col1 varchar2(30));

Table created.

SQL> insert all
  2    into first values (1001)
  3    into first values (1002)
  4    into first values (1003)
  5    --
  6    into second values (1, '1001|1002|1006')
  7    into second values (2, '|1003|1001|1004')
  8    into second values (3, '|||1002|1007|1008')
  9  select * from dual;

6 rows created.

SQL>

Так как есть столбец ID, который однозначно определяет строки во второй таблице (как вы сказали вкомментарием), затем его можно использовать для создания новой временной таблицы, в которой столбец COL1 будет разбит на строки. ID позже будет использоваться для возврата оставшихся значений (в LISTAGG).

SQL> create table second_temp as
  2  select id,
  3         column_value rn,
  4         regexp_substr(col1, '[^|]+', 1, column_value) val
  5  from second cross join table(cast(multiset(select level from dual
  6                                             connect by level <= regexp_count(col1, '\|') + 1
  7                                            ) as sys.odcinumberlist));

Table created.

SQL>

В результате получается

SQL> select * from second_temp order by id, rn;

        ID         RN VAL
---------- ---------- ----------
         1          1 1001
         1          2 1002
         1          3 1006
         2          1 1003
         2          2 1001
         2          3 1004
         2          4
         3          1 1002
         3          2 1007
         3          3 1008
         3          4
         3          5
         3          6

13 rows selected.

SQL>

Теперь это простая задачаудаление значений, которые существуют в первой таблице;проверь, какие реамины:

SQL> delete from second_temp t where t.val in (select f.id from first f);

5 rows deleted.

SQL> select * from second_temp order by id, rn;

        ID         RN VAL
---------- ---------- ----------
         1          3 1006
         2          3 1004
         2          4
         3          2 1007
         3          3 1008
         3          4
         3          5
         3          6

8 rows selected.

SQL>

Давайте агрегируем оставшиеся значения обратно в col1:

SQL> select t.id, listagg(t.val, '|') within group (order by t.rn) col1
  2  from second_temp t
  3  group by t.id;

        ID COL1
---------- --------------------
         1 1006
         2 1004
         3 1007|1008

SQL>

Теперь, для чего это будет использоваться? Я не знаю;Вы можете использовать его как CTAS (Создать таблицу как выбор) и создать новую вторую таблицу. Или вы можете обрезать исходную вторую таблицу и вставить эти значения в нее. Или ... что-то еще.

...