Mysql: создать индекс на 1,4 миллиарда записей

9

У меня есть таблица с 1,4 миллиарда записей. Структура таблицы следующая:

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

Требуется создать индекс по столбцу text.

Размер стола составляет около 34G.

Я попытался создать индекс с помощью следующего утверждения:

ALTER TABLE text_page ADD KEY ix_text (text)

После 10 часов ожидания я наконец отказался от этого подхода.

Есть ли реальное решение этой проблемы?

ОБНОВЛЕНИЕ : таблица вряд ли будет обновлена ​​или вставлена ​​или удалена. Причина, по которой создается индекс для столбца, textзаключается в том, что этот тип SQL-запроса будет часто выполняться:

SELECT page_id FROM text_page WHERE text = ?

ОБНОВЛЕНИЕ : я решил проблему разделением таблицы.

Стол разбит на 40 столбцов text. Затем создание индекса для таблицы занимает около 1 часа.

Кажется, что создание индекса MySQL становится очень медленным, когда размер таблицы становится очень большим. А разбиение сокращает таблицу на меньшие стволы.

SiLent SoNG
источник
1
Что не так с использованием нормального CREATE INDEXвыражения?
Я бы предположил, что этот вопрос может быть лучше для ServerFault - это скорее вопрос администратора БД, чем вопроса программирования.
оттуда
@Derk: нормальный подход CREATE INDEX слишком медленный. Я должен выполнить задачу в течение 1 дня.
1
Хм ... я не думаю, что вы можете обойти это. Построение индекса требует, чтобы СУБД сканировала все записи, собирала их «текстовые» поля и вставляла / изменяла соответствующие узлы / поддеревья дерева. И это занимает много времени для 34G ...
chiccodoro
Сколько памяти у вашего сервера БД? Вы настроили MySQL, чтобы использовать всю эту память, или это ограничивает себя?

Ответы:

4

Может быть, ваша система просто не подходит для этой задачи? Я не использую MySQL (здесь SQL Server), но я знаю, как индексировать таблицу с 800 миллионами записей. В основном .... вам нужно подходящее оборудование для этого (как в: много быстрых дисков). Сейчас я использую почти дюжину Velociraptors, и производительность просто великолепна;)

Серверы SQL (не как MS SQL Server, а как серверы баз данных, использующие SQL) живут и умирают с доступом к диску, а обычные диски просто не справляются с задачей более крупных операций.

TomTom
источник
Я сомневаюсь, что создание индекса обычно очень быстро, если количество записей мало; скажем, миллионы. Но когда счет составляет миллиарды, создание индекса становится таким медленным. Похоже, время роста экспоненциально.
Не должно быть на самом деле. MySQL в целом имеет ограничения, но это не дерьмовая база данных, и это было бы ОЧЕНЬ плохо. Генерация индексов происходит медленнее, но по log (n), а не (n), так что это не должно быть НАСТОЛЬКО плохо.
TomTom
4

Возможно, вы захотите создать индекс по первым (например, 10) символам текстового поля.

Из документов:

Могут быть созданы индексы, которые используют только начальную часть значений столбца, используя синтаксис col_name (length) для указания длины префикса индекса:

CREATE INDEX ix_text ON text_page (text(10))

источник
4

Я решил проблему, разделив таблицу.

Стол разбит на 40 столбцов text. Затем создание индекса для таблицы занимает около 1 часа.

Кажется, что создание индекса MySQL становится очень медленным, когда размер таблицы становится очень большим. А разбиение сокращает таблицу на меньшие стволы.

SiLent SoNG
источник
То есть 40 х 1 час - это меньше 10 часов?
Symcbean
3

Установите sort_buffer_size на 4 ГБ (или столько, сколько вы можете в зависимости от того, сколько у вас памяти).

Прямо сейчас создание индекса выполняет сортировку, но, поскольку у вас есть sort_buffer_size 32 МБ, он в основном без необходимости перебивает жесткий диск.

tster
источник
Эти сообщения в значительной степени прямо не согласны с вами: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size и лучше ronaldbradford.com/blog/… Похоже, это не глобальная ценность, это за запрос, так что это 4 ГБ на запрос, который вы рекомендуете. Кроме того, когда он превышает 256 КБ, он записывается на диск, а не в оперативную память. Если вы держите его маленьким, требуется несколько проходов, но он избегает диска (он не меняет местами).
Ry4an Brase
3

Если вам не нужно делать запросы, такие как:

SELECT page_id FROM text_page WHERE text LIKE '?%';

Я бы предложил создать новый столбец хеша и индексировать таблицу по столбцу. Общий размер таблицы + индекс может быть намного меньше.

UPD : Кстати, 1,4 миллиарда целых чисел первичного ключа занимают около 6 ГБ, то есть средняя длина строки составляет менее 30 символов, то есть индексирование по префиксу может быть более предпочтительным.

Вы также должны взглянуть на механизм хранения MERGE .

newtover
источник
2

Один из способов сделать это - создать новую таблицу с установленным индексом и скопировать данные в новую таблицу.

Также убедитесь, что у вас достаточно временного пространства.

декомпилированные
источник
1
Я попробовал этот подход. Через 10 часов менее 1% данных были скопированы в новую таблицу.
1
Чувак ... это 1,4 миллиарда записей. Не миллион, МИЛЛИАРД. Это много. Это займет некоторое время независимо.
Если вы решите использовать этот метод, разбейте копию на более мелкие куски. Скажем, от 100 до 200 миллионов за каждую копию.
1
@ декомпилировать, разбивая его на более мелкие куски, ничего не будет делать (на самом деле, это может сделать его менее эффективным). @ Брайан, даже с 1,4 миллиардами записей это не должно занимать 1000 часов.
0

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

В интернете их много, одним из известных являются:

У нас те же проблемы с большими таблицами (более 500 миллионов записей), и изменения идут отлично. Он создает новую таблицу tmp, добавляет триггер к исходной таблице (для новых записей обновления / удаления / вставки) и в то же время копирует все записи в новую таблицу (с новой структурой)

Удачи!

Али Альваш
источник