2013-02-16 3 views
1

Я пытаюсь объяснить свою проблему примерами. Я с тех пор работает оператор вродеLarge UPDATE [...] SELECT FROM вызывает параллельное UPDATE/DELETE, чтобы умереть

UPDATE <table_A> 
INNER JOIN <table_B> ON [...] 
LEFT JOIN <table_C> ON [...] 
LEFT JOIN <table_D> ON [...] 
LEFT JOIN <table_E> ON [...] 
SET <table_A>.<col_A>=X 
WHERE <table_A>.<col_A>=Y AND COALESCE(<table_C>.<id>,<table_D>.<id>,<table_E>.<id> IS NULL 

Это утверждение работает на больших таблиц (два из них содержат 7+ миллиона строк в таблице). Обновление выполняется 3-5 минут. В другой сессии там делается в высокой параллельности

UPDATE <table_C> SET <col_A>=Z WHERE <id> IN ([...]) 

или

DELETE FROM <table_C> WHERE <id> IN ([...]) 

Когда большие UPDATE работает, то они одновременно UPDATE и DELETES умереть с тайм-аут или ожидания блокировки тупиков после одной или двух минут. Все столбцы JOIN индексируются (стандартные индексы). Я уже пытался сделать

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 
[BIG UPDATE]; 
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; 

, но это не помогает. Консистенция данных на <table_A> не так важна (это не проблема, если она содержит строки, которые не существуют в <table_C> ... <table_E>). Самое главное, что обрабатываются мелкие UPDATE/DELETE с на <table_C> ... <table_E>.

+0

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

+0

Это не вариант для меня, потому что я должен знать, что «product_id» должен быть ни в одной из таблиц '' ... ''. Я уже пробовал ваше предложение, но самая большая таблица из них содержит 7+ миллионов строк, и этого достаточно, чтобы вызвать тайм-ауты блокировки (независимо от того, были ли другие две таблицы также «JOIN'ed) – rabudde

+0

Проверьте, есть ли мой ответ в отличие от того, что вы пробовали. – Anri

ответ

0

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

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

Запуск цикла:

  1. SELECT Id, ColA FROM TableA ORDER BY Id DESC LIMIT 10 OFFSET (iteration)*10
  2. Второй контур, возьмите строки из предыдущего результата, где tableA.colA=Y
    2.1. SELECT Id FROM TableB WHERE ID=id_from_current_iteration
    2.2. SELECT Id FROM TableC WHERE ID=id_from_current_iteration
    2.3 Если оба предыдущего запрос, возвращающий нуля перейти к следующему шагу, в противном случае перейти к следующей итерации 2,4 UPDATE TableA SET ColA=X WHERE ID=id_from_current_iteration

Других слова - избежать присоединяется.
Это займет больше времени, чем одно обновление, но оно будет работать.
Первым шагом для его оптимизации будет пакетный запрос.

+0

Хорошо, вы разделили 'JOIN', это не мое намерение, но мы должны решить теоретическую задачу, поэтому ваш ответ будет принят. Проблема возникает из-за того, что я совмещаю 'UPDATE' с' JOIN ', который блокирует строки. Я изменил 'UPDATE', чтобы перебрать' id' с шагом в 10 000.Это выполняется в течение 2-3 секунд для каждого цикла, и мой опыт намного лучше. – rabudde

+0

Будет хорошо, если вы добавите свое решение в качестве ответа. – Anri

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