Оптимизация структуры таблиц MySQL и влияние размера строки

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

Он имеет ~ 13 000 000 строк и имеет размер 4,2 ГБ, из которых 1,2 ГБ — это данные.

Структура выглядит следующим образом:

CREATE TABLE IF NOT EXISTS `t1` (
  `id` int(10) unsigned NOT NULL,
  `int2` int(10) unsigned NOT NULL,
  `int3` int(10) unsigned NOT NULL,
  `int4` int(10) unsigned NOT NULL,
  `char1` varchar(255) NOT NULL,
  `int5` int(10) NOT NULL,
  `char2` varchar(1024) DEFAULT NULL,
  `char3` varchar(1024) NOT NULL,
  PRIMARY KEY (`id`,`int2`,`int3`,`int4`),
  KEY `key1` (`id`,`int2`,`char1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Обычными операциями в этой таблице являются вставка и выборка, строки никогда не обновляются и редко удаляются. int2 — номер текущей версии, что означает, что обычно выбираются только строки с самым высоким значением int2 для этого идентификатора.

Я думал о нескольких способах оптимизации этого, и мне было интересно, какой из них будет тем, который следует преследовать:

  1. char1 (который находится в индексе) на самом деле содержит только около 40 000 различных строк. Я мог бы переместить строки во вторую таблицу (idchar -> char), а затем просто сохранить идентификатор в моей основной таблице за счет дополнительного шага поиска идентификатора во время вставки и выбора.
  2. char2 и char3 часто пусты. Я мог бы переместить их в отдельную таблицу, а затем выполнить LEFT JOIN при выборе.
  3. Даже если char2 и char3 содержат данные, они обычно короче 1024 символов. Я мог бы, вероятно, сократить их до ~ 200.

Какой из них вы считаете наиболее перспективным? Действительно ли уменьшение размера строки (либо путем преобразования char1 в целое число, либо путем удаления/изменения размера столбцов) в таблицах MySQL InnoDB оказывает большое влияние на производительность?

Спасибо


person Nils    schedule 16.03.2014    source источник
comment
Рассматривали ли вы возможность разметить свою таблицу? Что касается медленного резервного копирования, рассматривали ли вы возможность использования двоичного журнала для инкрементного резервного копирования или использования подчиненного устройства репликации в качестве сервера резервного копирования (как описано в разделе Методы резервного копирования базы данных)?   -  person eggyal    schedule 16.03.2014
comment
Я не рассматривал разделение, нет. Как вы думаете, это поможет в моем случае? Читая страницу справки, я действительно не понимаю, какое практическое применение могло бы быть для моей проблемы.   -  person Nils    schedule 16.03.2014
comment
Это действительно зависит от того, с какими практическими проблемами вы сталкиваетесь. Вы упоминаете только медленные резервные копии: если у вас нет других проблем с производительностью, то я не думаю, что разбиение на разделы дает вам какие-либо преимущества.   -  person eggyal    schedule 16.03.2014


Ответы (2)


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

Точное влияние на производительность трудно сказать, не зная больше о вашей системе и нагрузке запросов.

Перемещение char3 и char4 в другую таблицу окажет минимальное влияние. Накладные расходы на ссылку на другую таблицу съели бы любой выигрыш в пространстве. Вы можете сэкономить пару байтов на запись, сохранив их как varchar(255), а не varchar(1024).

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

person Gordon Linoff    schedule 16.03.2014
comment
Я добавил примечание о распространенных запросах в свой первоначальный пост. Если я правильно понимаю ваш пост, это означает, что разделы могут быть полезны? - person Nils; 16.03.2014
comment
@Нильс. . . В этой ситуации разделы являются лучшим решением для ускорения резервного копирования (вы можете просто создавать резервные копии по одному разделу за раз). Вы все равно можете получить некоторый выигрыш в производительности, переместив char1 в другую таблицу. - person Gordon Linoff; 16.03.2014
comment
Хорошо, спасибо! Будет ли уже достаточно просто определить разделы, или мне также придется отказаться от обычного подхода к резервному копированию «mysqldump», чтобы воспользоваться ими? - person Nils; 16.03.2014
comment
@Нильс. . . Вам нужно будет изменить подход к резервному копированию, чтобы создать резервную копию только самого последнего раздела. - person Gordon Linoff; 17.03.2014

Есть несколько факторов, которые могут повлиять на производительность вашей БД. Разбиение на разделы, безусловно, лучший вариант, но не всегда можно сделать. Если вы ищете char1 перед вставкой, то разделение может быть проблемой, потому что вам нужно искать ключ во всех частях. Вы должны проанализировать, как генерируются данные и, что наиболее важно, как вы делаете запросы для этой таблицы. Это ключ, поэтому вы должны публиковать свои запросы в этой таблице. В случае с char2 и char3 переход на другую таблицу не будет иметь никакого значения. Вы также должны упомянуть о физическом распределении ваших данных. Вы используете один файл данных? Находятся ли файлы данных на том же физическом диске, что и SO? Дайте больше деталей, чтобы мы могли оказать вам больше помощи.

person ericpap    schedule 16.03.2014