Как удалить большое количество записей из таблицы Oracle, которые не имеют первичного ключа - PullRequest
0 голосов
/ 20 февраля 2019

Ситуация: я загружаю всю таблицу SQL в свою программу.Для удобства я использую панды для поддержки данных строк.Затем я создаю кадр данных строк, которые я хотел бы удалить из таблицы SQL.К сожалению ( и я не могу изменить это ), таблица не имеет никаких первичных ключей, кроме встроенного Oracle ROWID (который не является реальным столбцом таблицы, а псевдостолбцом), но я могу сделатьROWID часть моего фрейма данных, если мне нужно.

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

Вопрос: Используя Cx_Oracle, каков наилучший метод удаления нескольких строк / записей, у которых нет первичного ключа? Я не думаю, что создание цикла для отправки тысяч операторов delete является очень эффективным или питонным.Хотя я обеспокоен созданием отдельного оператора удаления SQL с ключом ROWID, который содержит предложение с тысячами элементов:

Where ROWID IN ('eg1','eg2',........, 'eg2345')

Является ли эта проблема действительной?Есть предложения?

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Использование ROWID

Поскольку вы можете использовать ROWID, это будет идеальный способ сделать это.И в зависимости от версии Oracle ограничение длины запроса может быть достаточно большим для запроса с таким количеством элементов в предложении IN.Проблема заключается в количестве элементов в списке выражений IN - ограничено 1000 .

Так что вам придется разбить список RowIDв наборы по 1000 за раз или удалите только одну строку за раз;с или без executemany().

>>> len(delrows)  # rowids to delete
5000
>>> q = 'DELETE FROM sometable WHERE ROWID IN (' + ', '.join(f"'{row}'" for row in delrows) + ')'
>>> len(q)  # length of the query
55037
>>> # let's try with just the first 1000 id's and no extra spaces
... q = 'DELETE FROM sometable WHERE ROWID IN (' + ','.join(f"'{row}'" for row in delrows[:1000]) + ')'
>>> len(q)
10038

Возможно, вы находитесь в пределах длины запроса и можете даже сохранить некоторые символы с минимальным разделителем элементов ','.

Без ROWID

Без первичного ключа или ROWID единственный способ идентифицировать каждую строку состоит в том, чтобы указать все столбцы в предложении WHERE и сделать много строк за один раз, их необходимо объединить в OR:

DELETE FROM sometable
WHERE  ( col1 = 'val1'
         AND col2 = 'val2'
         AND col3 = 'val3' )  -- row 1
    OR ( col1 = 'other2'
         AND col2 = 'value2'
         AND col3 = 'val3' )  -- row 2
    OR ( ... )                -- etc

Как видите, это не самый хороший запрос для создания, но он позволяет вам делать это без ROWID.


И в обоих случаях вам, вероятно, не нужноиспользование параметризованных запросов, поскольку список IN в 1 или OR, группировка в 2 является переменной.(Да, вы могли бы создать его параметризованный после построения всего расширенного SQL с тысячами параметров. Не уверен, каков этот предел.) Способ executemany() определенно проще писать и делать, но для скорости - одиночные большие запросы (любой из вышеперечисленных двух), вероятно, превзойдет executemany с тысячами элементов.

0 голосов
/ 21 февраля 2019

Вы можете использовать cursor.executemany () для удаления нескольких строк одновременно.Должно работать что-то вроде следующего:

dataToDelete = [['eg1'], ['eg2'], ...., ['eg2345']]
cursor.executemany("delete from sometable where rowid = :1", dataToDelete)
...