Обновление с присоединением почему-то занимает от 9 до 30 часов?

У меня есть две таблицы, назовем их table_A и table_B. Table_A содержит около 10 миллионов строк. Table_B имеет 300 миллионов строк. Я создал индексы для столбцов Table_B X и Y.

Нормально ли, что обновления будут занимать так много времени с количеством строк, которые у меня есть? Мне это кажется очень длинным, учитывая, что у меня есть индекс

Вот как они выглядят

Таблица А:

ID   BCODE 
1    A1 
2    B1  
3    C1  
4    D1  
5    F1 

Таблица Б:

X    Y    IDX  IDY
A1   D1  
D1   F1  
C1   B1  

Table_B имеет столбцы «X» и «Y», значения которых находятся в столбце BCODE таблицы Table_A.

Я запускаю два оператора обновления, выполнение которых занимает от 9 до 30 часов.

 Update Table_B
join table_A a on table_B.X = a.BCODE
set
   table_B.IDX=a.Id ;

Update Table_B
join Table_A aa on table_B.Y = aa.BCODE
set
   table_B.IDY = aa.Id  ;

Могу ли я как-нибудь ускорить это? Я должен добавить, что столбцы BCODE, X, Y могут иметь длину до 300 символов.

Вот результаты объяснения:

+----+-------------+-----------+------+---------------+-------------+---------+--------------+----------+-------------+
| id | select_type | table     | type | possible_keys | key         | key_len |  ref         | rows     | Extra       |
+----+-------------+-----------+------+---------------+-------------+---------+--------------+----------+-------------+
|  1 | SIMPLE      | a         | ALL  | BCODE         | NULL        | NULL    | NULL         | 10238784 | NULL        |
|  1 | SIMPLE      | table_B   | ref  | relateIndex   | relateIndex | 632     | test.a.BCODE |       15 | Using where |
+----+-------------+-----------+------+---------------+-------------+---------+------------+----------+-------------+
2 rows in set (0.00 sec)

person Aries On The Cusp    schedule 04.04.2015    source источник
comment
как выглядит план выполнения/объяснения? даже с индексами вы все еще обновляете сотни миллионов строк, поэтому доступ к памяти/процессору/диску будет фактором   -  person pala_    schedule 04.04.2015
comment
Имеют ли table_B.X и aa.BCODE один и тот же тип данных? Индексируется ли aa.BCODE?   -  person Abhik Chakraborty    schedule 04.04.2015
comment
Я добавил результаты объяснения. Обе таблицы имеют одинаковый тип данных для объединенных столбцов.   -  person Aries On The Cusp    schedule 04.04.2015
comment
также попробуйте включить профилирование, а затем профилировать этот запрос на обновление при его запуске (обратите внимание, что он должен выполняться в течение всего времени). если у вас есть свободное время, это покажет вам, как ваш запрос тратит свое время. dev.mysql.com/doc/refman/5.5/en/ показать-профиль.html   -  person pala_    schedule 04.04.2015
comment
Примерно сколько строк в каждой таблице? Приблизительно сколько строк в таблице B соответствуют каждому значению bcode в таблице A?   -  person Bohemian♦    schedule 04.04.2015
comment
table_B имеет 350205473 строки. Table_A имеет 10238784 строки. Каждая строка в table_B должна иметь соответствие в table_A   -  person Aries On The Cusp    schedule 04.04.2015


Ответы (2)


Создайте покрывающий индекс:

create index table_a_bcode_id on table_A(bcode, id);

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

Ваши запросы выглядят нормально, но попробуйте их объединить:

update Table_B
left join table_A a1 on a1.BCODE = table_B.X
left join table_A a2 on a2.BCODE = table_B.Y
set table_B.IDX = a1.Id
    table_B.IDY = a2.Id

Это позволяет избежать необходимости дважды обновлять строку.

person Bohemian♦    schedule 04.04.2015
comment
Первоначально у меня было обновление, объединенное в один оператор, но проблема заключалась в том, что если один из столбцов не совпал при объединении, то другой, даже если он соответствует, не будет записан в обновление. Я попробую индекс покрытия и дам вам знать - person Aries On The Cusp; 04.04.2015
comment
@aries решить проблему отсутствия соединения легко (см. редактирование), но скажите мне, если соединения нет, можно ли записать нуль в idX или idY? Если это так, текущий запрос будет работать. Если нет, дайте мне знать. - person Bohemian♦; 04.04.2015
comment
Потребовалось 5 часов, чтобы создать покрытый индекс и 3,5 часа, чтобы выполнить обновление левого соединения, но, по крайней мере, оно наконец было завершено. Спасибо Богемский, ты молодец! - person Aries On The Cusp; 08.04.2015

Из вывода EXPLAIN видно, что Table_A.BCODE не имеет индекса для BCODE. Если вы хотите выполнить JOIN, обе таблицы должны быть проиндексированы по полям JOIN, иначе неиндексированная таблица будет замедлять работу из-за сложности O (N) поиска.

Кроме того, вы упомянули, что оба столбца представляют собой строки длиной до 300 символов. Индексы на таких столбцах малоэффективны. Если бы вы могли найти способ хешировать значения в этих столбцах, а затем выполнять соединение по хешированным значениям, это могло бы ускорить процесс.

С другой стороны, с такими большими таблицами вы должны проверить, помещаются ли индексы в память. Если они этого не сделают, то MySQL начнет подкачивать ваш индекс на диск, что чрезвычайно замедлит работу.

Мы можем сделать оценку: 600 (длина ключа вашего индекса) x 300M (количество строк) = 200 ГБ... Так что вполне вероятно, что проблема именно в этом.

Возможный обходной путь: попробуйте разбить вашу таблицу_B (например, по PK), чтобы для каждой части индекс мог поместиться в память (это может означать 25 или более разделов, если ваш экземпляр MySQL может использовать до 8 ГБ ОЗУ).

person Ashalynd    schedule 04.04.2015
comment
Я добавил индекс в table_A после того, как опубликовал EXPLAIN, но прошло 5 часов после создания индекса, а обновление все еще выполняется. Так что, возможно, вы правы насчет того, что индексы не помещаются в памяти. Я посмотрю, как сделать разбиение. Благодарю вас ! - person Aries On The Cusp; 04.04.2015