2009-12-29 2 views
3

Я часто пишу datascrubs, которые обновляют миллионы строк данных. Данные хранятся в базе данных OLTP MySQL 24x7x365 с использованием InnoDB. Обновления могут счищать каждую строку таблицы (в которой БД заканчивается приобретением блокировки на уровне таблицы) или может просто очищать 10% строк в таблице (которая все еще может быть в миллионах).Операция MySQL UPDATE, чтобы избежать массивных размеров TRX

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

(предупреждение: это просто псевдо-код, чтобы получить точку в поперечнике)

@batch_size=10000; 
@max_primary_key_value = select max(pk) from table1 

for (int i=0; i<[email protected]_primary_key_value; [email protected]_size) 
{ 
start transaction; 

update IGNORE table1 
set col2 = "flag set" 
where col2 = "flag not set" 
and pk > i 
and pk < [email protected]; 

commit; 
} 

Такой подход просто отстой так много причин.

Я хотел бы выпустить инструкцию UPDATE без базы данных, которая пытается сгруппировать все обновляемые записи в единый блок транзакций. Я не хочу, чтобы UPDATE преуспел или потерпел неудачу как единое целое. Если 1/2 строки не обновляются ... нет проблем, просто дайте мне знать. По сути, каждая строка - это собственная единица работы, но дозирование или курсор - единственный способ понять, как представить это для механизма базы данных.

Я рассмотрел установки уровней изоляции для своей сессии, но это, похоже, не помогает мне в этом конкретном случае.

Любые другие идеи?

ответ

2

Возможно, не ответ, который вы ищете, но вы можете немного упростить свой код, используя LIMIT в обновлении.

Псевдо-код:

do { 
    update table1 set col2 = 'flag set' where col2 = 'flat not set' LIMIT 10000 
} while (ROW_COUNT() > 0) 
+0

Интересный подход Эрик. Мне нравится идея, но она ограничена обновлениями, которые фактически изменяют значения полей, которые заданы в предложении WHERE (например, в примере, который я дал). Однако у меня такая же проблема с большими обновлениями, которые не соответствуют этому шаблону (например, установите col1 = "foo", где col2 = "bar"). – 2010-01-06 15:10:58

+0

@Matthew - если это так, вы всегда можете изменить свой запрос, чтобы быть чем-то вроде «set col1 = 'foo», где col2 = «bar» и col1! =' Foo », что позволило бы избежать проблемы с пакетом non -модулирование обновлений, выбивающих вас из цикла. –

0

Да Эрик ... ты прав (для простых случаев, которые не включают в себя положения, где это, как «где не»). Я написал небольшую процедуру, которая позволяет мне предоставлять инструкцию SQL update и номер предела в качестве параметров.

создать процедуру mass_update (IN updatestmt TEXT, IN batchsiz INT) НАЧАТЬ - ЦЕЛЬ: ломаются крупные операторы обновления в партии, чтобы ограничить размер сделки и уменьшить конкуренцию - ОГРАНИЧЕНИЕ: работает только с уточнениями, которые дали бы " 0 строк затронуты "при выполнении TWICE!

SET @sql = CONCAT(updatestmt," LIMIT ", batchsiz); 
-- had to use CONCAT because "PREPARE stmt FROM" cannot accept dynamic LIMIT parameter 
-- reference: http://forums.mysql.com/read.php?98,75640,75640#msg-75640 
PREPARE stmt FROM @sql; 

select @sql; --display SQL to screen 
SET @cumrowcount=0; 
SET @batchnum=0; 
SET @now := now(); -- @now is a STRING variable... not a datetime 

    increment: repeat 
     SET @[email protected]+1; 
     EXECUTE stmt; 
     set @rowcount = ROW_COUNT(); 
     set @cumrowcount = @cumrowcount + @rowcount; 
     select @batchnum as "Iteration", 
       @cumrowcount as "Cumulative Rows", 
       TIMESTAMPDIFF(SECOND,STR_TO_DATE(@now,"%Y-%m-%d %H:%i:%s"),now()) as "Cumulative Seconds", 
       now() as "Timestamp"; 
     until @rowcount <= 0 
    end repeat increment; 

    DEALLOCATE PREPARE stmt; -- REQUIRED 
END 

Это, кажется, работает достаточно хорошо, и я могу запустить его с любым старым заявлением UPDATE, который прилипает к правилу «работает в два раза приводит к 0 затронутых строкам».

Спасибо за идею Эрика!

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