Я боролся с удалением огромного количества старых данных из базы данных. Каждая из 5 разных таблиц содержит до 50 миллионов строк, которые необходимо удалить. Ни один оператор удаления не может обработать такое количество данных, поэтому мне приходится последовательно удалять несколько записей одновременно. Мой вопрос заключается в том, есть ли заметное увеличение производительности зацикливания внутри хранимой процедуры вместо зацикливания в коде приложения. Теперь для конкретики я использую DB2 (9.7 CE) и пишу на C #. Для моей хранимой процедуры я использую:
--#SET TERMINATOR ;
DROP PROCEDURE myschema.purge_orders_before;
--#SET TERMINATOR @
CREATE PROCEDURE myschema.purge_orders_before (IN before_date TIMESTAMP)
DYNAMIC RESULT SETS 1
P1: BEGIN
DECLARE no_data SMALLINT DEFAULT 0;
DECLARE deadlock_encountered SMALLINT DEFAULT 0;
DECLARE deadlock_condition CONDITION FOR SQLSTATE '40001';
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_data = 1;
-- The deadlock_encountered attribute is throw-away,
-- but a continue handler needs to do something,
-- i.e., it's not enough to just declare a handler,
-- it has to have an action in its body.
DECLARE CONTINUE HANDLER FOR deadlock_condition
SET deadlock_encountered = 1;
WHILE (no_data = 0 ) DO
DELETE FROM
(SELECT 1 FROM myschema.orders WHERE date < before_date FETCH FIRST 100 ROWS ONLY );
COMMIT;
END WHILE;
END P1
@
--#SET TERMINATOR ;
Чей подход был бесцеремонно снят с этой темы . Мой программный подход заключается в следующем:
public static void PurgeOrdersBefore( DateTime date ) {
using ( OleDbConnection connection = DatabaseUtil.GetInstance( ).GetConnection( ) ) {
connection.Open( );
OleDbCommand command = new OleDbCommand( deleteOrdersBefore, connection );
command.Parameters.Add( "@Date", OleDbType.DBTimeStamp ).Value = date;
int rows = 0;
int loopRows = 0;
int loopIterations = 0;
log.Info( "starting PurgeOrdersBefore loop" );
while ( true ) {
command.Transaction = connection.BeginTransaction( );
loopRows = command.ExecuteNonQuery( );
command.Transaction.Commit( );
if ( loopRows <= 0 ) {
break;
}
if ( log.IsDebugEnabled ) log.Debug( "purged " + loopRows + " in loop iteration " + loopIterations );
loopIterations++;
rows += loopRows;
}
if ( log.IsInfoEnabled ) log.Info( "purged " + rows + " orders in " + loopIterations + " loop iterations" );
}
}
Я выполнил примитивный тест ОЧЕНЬ , в котором я напечатал метку времени в начале и в конце и вышел из цикла после 10000 в каждом. Результатом указанного теста было то, что хранимой процедуре потребовалось чуть более 6 минут, чтобы удалить 10000 строк, а программный подход занял чуть менее 5 минут. Будучи столь же примитивным, как и раньше, я думаю, что единственный вывод, который я могу сделать, состоит в том, что на практике они, скорее всего, будут иметь минимальное различие, а сохранение цикла в коде C # обеспечивает гораздо более динамичный мониторинг.
Все это говорит, кто-нибудь еще имеет какие-либо материалы по этому вопросу? Не могли бы вы объяснить, какие скрытые выгоды я мог бы получить, если бы использовал подход хранимых процедур? В частности, если Серж Риелау присматривает за этим сайтом, мне бы хотелось услышать, что вы скажете (похоже, он - ниндзя, на которого все остальные ссылаются, когда речь заходит о бессмыслице DB2, подобной этой ...)
-------------- Редактировать ---------------------
Как насчет экспорта какого-либо вида, за которым следует ЗАМЕНА ЗАГРУЗКИ? Кто-нибудь делал это раньше? Есть ли пример, которому я мог бы следовать? Какие последствия это будет иметь?