Производительность MySQL Insert снижается на большой таблице - PullRequest
15 голосов
/ 09 сентября 2010

Я работаю с огромной таблицей, в которой более 250 миллионов строк. Схема проста.

CREATE TABLE MyTable (
        id BIGINT PRIMARY KEY AUTO_INCREMENT,
        oid INT NOT NULL,
        long1 BIGINT NOT NULL,
        str1 VARCHAR(30) DEFAULT NULL,
        str2 VARCHAR(30) DEFAULT NULL,
        str2 VARCHAR(200) DEFAULT NULL,
        str4 VARCHAR(50) DEFAULT NULL,
        int1 INT(6) DEFAULT NULL,
        str5 VARCHAR(300) DEFAULT NULL,
        date1 DATE DEFAULT NULL,
        date2 DATE DEFAULT NULL,
        lastUpdated TIMESTAMP NOT NULL,
        hashcode INT NOT NULL,
        active TINYINT(1) DEFAULT 1,
        KEY oid(oid),
        KEY lastUpdated(lastUpdated),
        UNIQUE KEY (hashcode, active),
        KEY (active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 MAX_ROWS=1000000000;

Производительность вставки значительно упала. До 150 миллионов строк в таблице на вставку 10000 строк уходило 5-6 секунд. Сейчас оно выросло в 2-4 раза. Файл ibdata от Innodb вырос до 107 ГБ. Параметры конфигурации Innodb следующие.

innodb_buffer_pool_size = 36G # Machine has 48G memory
innodb_additional_mem_pool_size = 20M
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_file_size = 50M
innodb_log_buffer_size = 20M
innodb_log_files_in_group=2
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50
innodb_thread_concurrency = 8
innodb_flush_method = O_DIRECT
expire_logs_days = 4

Время ожидания ввода-вывода увеличилось, как видно из top. Я попытался изменить метод сброса на O_DSYNC, но это не помогло. Диск вырезан из аппаратной настройки RAID 10. В более ранней установке с одним диском IO не было проблемой.

Является ли опция разбиения таблицы только? Может ли помочь разбиение одного файла 100G на файлы меньшего размера? Есть ли переменные, которые нужно настроить для RAID?

Обновление : это тестовая система. У меня есть свобода вносить любые необходимые изменения.

Ответы [ 6 ]

15 голосов
/ 09 сентября 2010

Вы не сказали, была ли это тестовая система или производство; Я предполагаю, что это производство.

Вероятно, вы получили таблицу с размером, в котором ее индексы (или весь лот) больше не помещаются в памяти.

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

Разделение кажется наиболее очевидным решением, но разделение MySQL может не соответствовать вашему варианту использования.

Вам, безусловно, следует рассмотреть все возможные варианты - перенесите таблицу на тестовый сервер в своей лаборатории, чтобы увидеть, как он себя ведет.

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

Также рассмотрите плагин и сжатие innodb, это заставит ваш innodb_buffer_pool пойти дальше.

Вам действительно нужно проанализировать ваши сценарии использования, чтобы решить, действительно ли вам нужно хранить все эти данные, и является ли разделение разумным решением.

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

4 голосов
/ 24 сентября 2010

Исходя из моего опыта работы с Innodb, кажется, что для систем с интенсивной записью, похоже, достигнут предел, даже если у вас действительно оптимизированная дисковая подсистема.Я удивлен, что вам удалось получить его до 100 ГБ.

Это то, что щебетал недавно, и понял, что его нужно осколок - см. http://github.com/twitter/gizzard.

Все зависит от вашего использованияв некоторых случаях, но вы также можете перейти от mysql к cassandra, поскольку он действительно хорошо работает для приложений с интенсивной записью. (http://cassandra.apache.org)

1 голос
/ 25 ноября 2010

Вы не упомянули, на что похожа ваша рабочая нагрузка, но если не слишком много операций чтения или у вас достаточно основной памяти, другой вариант - использовать оптимизированный для записи бэкэнд для MySQL вместо innodb.По мере роста набора данных Tokutek заявляет о 18-кратном увеличении числа вставок и гораздо более плоской кривой производительности.

tokutek.com

http://tokutek.com/downloads/tokudb-performance-brief.pdf

1 голос
/ 24 сентября 2010

Как прокомментировал MarkR выше, производительность вставки ухудшается, когда индексы больше не могут помещаться в пул буферов. InnoDB имеет механизм случайного сокращения ввода-вывода (называемый буфером вставки), который предотвращает некоторые из этих проблем - но он не будет работать с вашим индексом UNIQUE. Индекс на (хэш-код, активный) должен проверяться при каждой вставке, чтобы убедиться, что дубликаты записей не вставлены. Если хеш-код не «следует» первичному ключу, эта проверка может быть случайным IO.

У вас есть возможность изменить схему?

Ваш лучший выбор:

(a) Сделайте хэш-код кем-то последовательным или сортируйте по хэш-коду перед массовой вставкой (это само по себе поможет, так как случайное чтение будет уменьшено).

(b) Сделать (хэш-код, активный) первичным ключом - и вставить данные в отсортированном порядке. Я предполагаю, что ваше приложение, вероятно, читает по хэш-коду - и поиск первичного ключа выполняется быстрее.

0 голосов
/ 24 октября 2013

Увеличение с innodb_log_file_size = 50M до innodb_log_file_size = 500M

И innodb_flush_log_at_trx_commit должно быть 0, если вы несете потерю данных в течение 1 секунды.

0 голосов
/ 25 ноября 2010

Я буду второй @ MarkR комментарии о сокращении индексов. Еще одна вещь, на которую вы должны обратить внимание, это увеличение вашего innodb_log_file_size. Это увеличивает время восстановления после сбоя, но должно помочь. Имейте в виду, что вам нужно удалить старые файлы перед перезагрузкой сервера.

Общие советы по настройке InnoDB: http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/

Вам также следует помнить о LOAD DATA INFILE для выполнения вставок. Это намного быстрее.

...