2016-02-05 2 views
0

Мне нужно удалить 10 000 записей из таблицы, содержащей 9 миллионов записей. Идентификаторы, которые должны быть удалены, будут получены из сложного запроса и сохранены в коллекции Java.Удаление записей из Oracle 11g с помощью JDBC

У меня есть 3 подхода к осуществлению этого

1) Создайте подготовленное заявление, и добавить 10000 заявлений в партии и выполнить его.

заявление будет выглядеть следующим образом

Delete from <table_name> where id=?; 

2) Написать в «» запрос, а не использовать «=» в пакете.

При этом 10 000 идентификаторов могут быть созданы как значения, разделенные запятой, в Java-коде и добавлены в запрос. Или 10000 идентификаторов вставляются во временную таблицу и делают выбор из этой таблицы в подзапросе.

Delete from <table_name> where id in (<CSV>); 
       or 
Delete from <table_name> where id in (select id from <temp_table>); 

В таблице нет ограничений и указателей. И я не могу добавить его, потому что я работаю над существующей таблицей.

Первый вариант требует времени для завершения. Он работал в течение 15 часов и до сих пор не завершен.

+0

Вы говорите, что таблица не имеет первичного ключа в столбце 'id'? – Andreas

+0

Это может показаться странным, но да! нет первичного ключа на id :) –

+1

Таблица с идентификатором «id», но без первичного ключа. Это просто ужасный дизайн базы данных. На таком столе не может быть никакого поиска, так что в чем смысл? – Andreas

ответ

0

ГДЕ ... В (...) - это путь.

Предложение IN может ссылаться на временную таблицу, которую вы заполнили (ваша оригинальная идея), или может содержать любое выбранное (фиксированное) число? параметры. Это уменьшит количество обращений в db на коэффициент, равный выбранному числу, но не обязательно одному. Идите по своей коллекции и обработайте ее кусками.

+0

, поэтому вы хотите добавить 10 000 вопросительных знаков в подготовленный оператор и использовать java loop preparestatement.setString (1, value), подготовленный файл.setString (2, value)? –

+0

Нет, я имел в виду любое выбранное количество вопросительных знаков. Скажем, 50. Или 100. Или 200. По-видимому, другие ответы показывают, что 10000 будет невозможно из-за установленных ограничений. –

0

Попробуйте вот так.

Delete from <table_name> where 
    id in (1, 2, 3, ... ,1000) 
    or id in (1001, 1002, ... , 2000) 
    .... 
2

У вас первая версия имеет предел 1000 значений и имеет тенденцию не работать хорошо. Второй подход может работать лучше, но вы должны иметь глобальную временную таблицу и заполнять ее, это дополнительный шаг.

Вы можете преобразовать свою коллекцию Java в коллекцию Oracle. Вы можете создать свой собственный тип таблицы для этого, но есть встроенные, такие как ODCINUMBERLIST, которые вы можете использовать здесь. Вы можете считать, что в качестве таблицы собираете экспрессию.

Детали могут незначительно отличаться в зависимости от типа коллекции Java, но план есть что-то вроде:

ArrayDescriptor aDesc = ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", 
    conn); 
oracle.sql.ARRAY oraIDs = new oracle.sql.ARRAY(aDesc, conn, yourJavaCollectinOfIDs); 

cStmt = (OracleCallableStatement) conn.prepareCall(
    "Delete from <table_name> 
    where id in (select column_value from table(?))"); 
cStmt.setArray(1, oraIDs); 
cStmt.execute(); 

Если он уже не простой массив, Вам нужно будет преобразовать коллекцию Java в массив в вызов; например если вы используете ArrayList под названием yourArrayList, вы могли бы сделать:

oracle.sql.ARRAY oraIDs = new oracle.sql.ARRAY(aDesc, conn, yourArrayList.toArray()); 

Вы по-прежнему страдают от отсутствия первичного ключа или индекса, но это даст Oracle лучший шанс, чтобы оптимизировать его, чем список CSV (или несколько списков CSV OR'd вместе, так как у вас более 1000 идентификаторов).

+0

Спасибо Алекс за ответ. Пытался реализовать ваш подход со встроенными типами, но закончил с «java.sql.SQLException: не удалось преобразовать во внутреннее представление». Используемые типы, такие как «ODCINUMBERLIST» и «ODCIVARCHAR2LIST». Любая помощь? Мои идентификаторы не являются номерами, это строки. Они выглядят как ** 1: 123 **. –

+0

@ShivaMothkuri - в вызове createDescriptor вы используете ODCIVARCHAR2LIST или SYS.ODCIVARCHAR2LIST? Как определяется ваша коллекция Java? –

+0

Используется SYS.ODCIVARCHAR2LIST. Моя коллекция ArrayList . Может ли двоеточие (:) в строке повлиять? –

1

Вы не должны использовать первый вариант, выполнив 10000 операторов из вашего java-кода.

Создание временной таблицы - хорошая идея.Но большую часть времени вы не можете иметь предложение IN (...) с более чем 1000 наименованиями. Таким образом, ваш подход с CSV может не сработать.

Вы можете пойти на

Delete from <table_name> where id in (select id from <temp_table>); 

, но этот путь не оптимизирован либо. Было бы лучше, чтобы изменить delete заявления в этом:

Delete from <table_name> m where exists (select id from <temp_table> t where m.id = t.id); 

Но если вы делаете такие операции часто настоятельно рекомендуется добавить некоторые ограничения и индексы к вам <table_name> и даже к вашим <temp_table>. Это увеличит время выполнения вашей операции, как очарование.

+0

Для Oracle [предел всегда 1000] (http://stackoverflow.com/a/19003103/266304) и не связан с размером элементов. –

+0

@AlexPoole: Спасибо за подсказку. Правильно, я отредактирую свой ответ. – STaefi

+0

Я был бы очень удивлен, если бы версия 'IN' отличалась от версии EXISTS. – gpeche

Смежные вопросы