Предел изменения для слишком большого размера строки Mysql
Как изменить предел
Размер строки слишком большой ( > 8126). Изменение некоторых столбцов в TEXT или BLOB или с помощью ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED
может помочь. В формате текущей строки префикс BLOB
из 768 байт сохраняется в строке.
Таблица:
id int(11) No
name text No
date date No
time time No
schedule int(11) No
category int(11) No
top_a varchar(255) No
top_b varchar(255) No
top_c varchar(255) No
top_d varchar(255) No
top_e varchar(255) No
top_f varchar(255) No
top_g varchar(255) No
top_h varchar(255) No
top_i varchar(255) No
top_j varchar(255) No
top_title_a varchar(255) No
top_title_b varchar(255) No
top_title_c varchar(255) No
top_title_d varchar(255) No
top_title_e varchar(255) No
top_title_f varchar(255) No
top_title_g varchar(255) No
top_title_h varchar(255) No
top_title_i varchar(255) No
top_title_j varchar(255) No
top_desc_a text No
top_desc_b text No
top_desc_c text No
top_desc_d text No
top_desc_e text No
top_desc_f text No
top_desc_g text No
top_desc_h text No
top_desc_i text No
top_desc_j text No
status int(11) No
admin_id int(11) No
Ответы
Ответ 1
Вопрос был задан и на сервере.
Возможно, вы захотите взглянуть на эту статью, которая многое объясняет о размерах строк MySQL. Важно отметить, что даже если вы используете поля TEXT или BLOB, размер вашей строки все равно может превышать 8 КБ (предел для InnoDB), поскольку он хранит первые 768 байт для каждого встроенного поля на странице.
Самый простой способ исправить это - использовать формат файла Barracuda с InnoDB. Это в основном полностью избавляет от проблемы, сохраняя только 20-байтовый указатель на текстовые данные вместо того, чтобы сохранять первые 768 байт.
Метод, который работал для OP там был:
-
Добавьте следующее в файл my.cnf
разделе [mysqld]
.
innodb_file_per_table=1
innodb_file_format = Barracuda
-
ALTER
таблицы использовать ROW_FORMAT=COMPRESSED
.
ALTER TABLE nombre_tabla
ENGINE=InnoDB
ROW_FORMAT=COMPRESSED
KEY_BLOCK_SIZE=8;
Существует вероятность того, что вышеуказанное все еще не решит ваши проблемы. Это известная (и проверенная) ошибка в механизме InnoDB, и на данный момент временное исправление - откат к механизму MyISAM в качестве временного хранилища. Итак, в вашем файле my.cnf
:
internal_tmp_disk_storage_engine=MyISAM
Ответ 2
Недавно я столкнулся с этой проблемой и решил ее по-другому. Если вы используете MySQL версии 5.6.20, в системе существует известная ошибка. См. Документы MySQL
Важно Из-за ошибки # 69477, журнал повторных записей для больших, сохраненных во внешнем блоке полей BLOB может переписать наиболее последний контрольно-пропускной пункт. Чтобы устранить эту ошибку, патч, введенный в MySQL 5.6.20, ограничивает размер повтора log BLOB записывает 10% от размера файла журнала повтора. В результате этого предела innodb_log_file_size должно быть установлено в значение, превышающее в 10 раз наибольший размер данных BLOB, найденный в строках вашего таблицы плюс длина других полей переменной длины (поля VARCHAR, VARBINARY и TEXT).
В моей ситуации оскорбительная таблица blob составляла около 16 МБ. Таким образом, способ, которым я решил это, заключался в добавлении строки в my.cnf, которая обеспечила бы, что у меня было как минимум 10x это количество, а затем несколько:
innodb_log_file_size = 256M
Ответ 3
Если вы можете переключить ДВИГАТЕЛЬ и использовать MyISAM вместо InnoDB, это должно помочь:
ENGINE=MyISAM
В MyISAM есть два оговорки (возможно, больше):
- Вы не можете использовать транзакции.
- Вы не можете использовать ограничения внешнего ключа.
Ответ 4
Установите следующее в файле my.cnf и перезапустите сервер MySQL.
innodb_strict_mode = 0
Ответ 5
Я хотел бы поделиться удивительным ответом, это может быть полезно. Кредиты Билл Карвин см. Здесь https://dba.stackexchange.com/questions/6598/innodb-create-table-error-row-size-too-large
Они варьируются в зависимости от формата файла InnoDB. В настоящее время существует 2 формата, называемые Antelope и Barracuda.
Центральный файл табличного пространства (ibdata1) всегда находится в формате Antelope. Если вы используете файл за таблицей, вы можете сделать отдельные файлы использующими формат Barracuda, установив innodb_file_format = Barracuda в my.cnf.
Основные пункты:
-
Одна страница 16KB данных InnoDB должна содержать не менее двух строк данных. Плюс каждая страница имеет заголовок и нижний колонтитул, содержащий контрольные суммы страниц и порядковый номер журнала и т.д. Это то, где вы получаете свой лимит чуть меньше 8 КБ на строку.
-
На этой первичной странице данных хранятся фиксированные типы данных типа INTEGER, DATE, FLOAT, CHAR и рассчитываются в соответствии с лимитом размера строки.
-
Типы данных с переменным размером, такие как VARCHAR, TEXT, BLOB, хранятся на страницах переполнения, поэтому они не учитывают полностью ограничение по размеру строки. В Antelope до 768 байт таких столбцов хранятся на первичной странице данных в дополнение к хранению на странице переполнения. Barracuda поддерживает формат динамической строки, поэтому он может хранить только 20-байтовый указатель на первичной странице данных.
-
Типы данных с переменным размером также имеют префикс с 1 или более байтами для кодирования длины. И формат строки InnoDB также имеет массив смещений полей. Таким образом, внутренняя структура более или менее документирована в их вики.
Barracuda также поддерживает ROW_FORMAT = COMPRESSED, чтобы получить дополнительную эффективность хранения для данных переполнения.
Мне также нужно прокомментировать, что я никогда не видел, чтобы хорошо спроектированная таблица превышала предел размера строки. Это сильный "запах кода", что вы нарушаете условие повторяющихся групп первой нормальной формы.
Ответ 6
Потратив часы, я нашел решение: просто запустите следующий SQL в вашем администраторе MySQL, чтобы преобразовать таблицу в MyISAM:
USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;
Ответ 7
Я столкнулся с этой проблемой, когда пытался восстановить резервную копию базы данных mysql с другого сервера. Для меня эта проблема была решена путем добавления определенных настроек в my.conf (как в приведенных выше вопросах) и дополнительного изменения файла резервной копии sql:
Шаг 1: добавьте или отредактируйте следующие строки в my.conf:
innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1
Шаг 2 добавьте ROW_FORMAT = DYNAMIC в оператор создания таблицы в файле резервной копии sql для таблицы, которая вызывает эту ошибку:
DROP TABLE IF EXISTS 'problematic_table';
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE 'problematic_table' (
'id' bigint(20) NOT NULL AUTO_INCREMENT,
...
PRIMARY KEY ('id')
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;
важное изменение, приведенное выше, - ROW_FORMAT = DYNAMIC; (это не было включено в файл резервной копии оригинального sql)
источник, который помог мне решить эту проблему: слишком большой размер MariaDB и InnoDB MySQL Row
Ответ 8
У меня была та же самая проблема, это решило это для меня:
ALTER TABLE 'my_table' ROW_FORMAT=DYNAMIC;
Из документации MYSQL:
Формат строки DYNAMIC поддерживает эффективность хранения всей строки в узле индекса, если он подходит (как это делают форматы COMPACT и REDUNDANT), но этот новый формат устраняет проблему заполнения узлов B-дерева большим количеством байтов данных длинные колонны. Формат DYNAMIC основан на идее, что если часть длинного значения данных хранится вне страницы, обычно наиболее эффективно хранить все значения вне страницы. В формате DYNAMIC более короткие столбцы, вероятно, останутся в узле B-дерева, минимизируя количество страниц переполнения, необходимых для любой данной строки.
Ответ 9
Другие ответы отвечают на заданный вопрос. Я остановлюсь на основной причине: плохой дизайн схемы.
Не массируйте массив по столбцам. Здесь у вас есть 3 * 10 столбцов, которые должны быть превращены в 10 строк из 3 столбцов в новой таблице (плюс id
и т.д.)
В таблице Main
будет только
id int(11) No
name text No
date date No
time time No
schedule int(11) No
category int(11) No
status int(11) No
admin_id int(11) No
Ваша дополнительная таблица (Top
) имела бы
id int(11) No -- for joining to Main
seq TINYINT UNSIGNED -- containing 1..10
img varchar(255) No
title varchar(255) No
desc text No
PRIMARY KEY(id, seq) -- so you can easily find the 10 top_titles
В Top
для каждого id
будет 10 (или меньше?) строк.
Это устраняет вашу оригинальную проблему и очищает схему. (Это не "нормализация", как обсуждалось в некоторых комментариях.)
Не переключайтесь на MyISAM; он уходит.
Не беспокойтесь о ROW_FORMAT
.
Вам нужно будет изменить свой код, чтобы сделать JOIN
, и обрабатывать несколько строк вместо нескольких столбцов.
Ответ 10
Я также столкнулся с той же проблемой. Я решаю проблему, выполнив следующий sql:
ALTER ${table} ROW_FORMAT=COMPRESSED;
Но я думаю, что вы должны знать о Row Storage.
Существует два типа столбцов: столбца переменной длины (типа VARCHAR, VARBINARY, BLOB и TEXT) и столбца фиксированной длины. Они хранятся в разных типах страниц.
Столбцы переменной длины являются исключением из этого правила. Столбцы, такие как BLOB и VARCHAR, которые слишком длинны для размещения на странице B-дерева, хранятся на отдельно выделенных дисковых страницах, называемых страницами переполнения. Такие столбцы мы называем внестраничными. Значения этих столбцов хранятся в односвязных списках переполненных страниц, и каждый такой столбец имеет свой собственный список одной или нескольких страниц переполнения. В некоторых случаях все или префикс значения длинного столбца хранятся в B-дереве, чтобы избежать потери хранилища и устранения необходимости читать отдельную страницу.
и когда целью установки ROW_FORMAT является
Когда таблица создается с помощью ROW_FORMAT = DYNAMIC или ROW_FORMAT = COMPRESSED, InnoDB может хранить длинные значения столбцов переменной длины (для типов VARCHAR, VARBINARY и BLOB и TEXT) полностью вне страницы, а кластерная индексная запись, содержащая только 20-байтовый указатель на страницу переполнения.
Хотите узнать больше о ДИНАМИЧЕСКИЕ И СЖАТЫЕ ФОРМЫ Row
Ответ 11
Если это происходит в SELECT со многими столбцами, причиной может быть то, что mysql создает временную таблицу. Если эта таблица слишком велика для размещения в памяти, она будет использовать формат временной таблицы по умолчанию (InnoDB) для хранения на диске. В этом случае применяются ограничения размера InnoDB.
Затем у вас есть 4 варианта:
- измените ограничение размера строки innodb, как указано в другом посте, что требует повторной инициализации сервера.
- измените свой запрос, чтобы он включал меньше столбцов, или не создавайте временную таблицу (например, удаляя команды order by и limit).
- изменение max_heap_table_size на большое, чтобы результат помещался в памяти и не нуждался в записи на диск.
-
измените формат временной таблицы по умолчанию на MYISAM, это то, что я сделал. Изменение в my.cnf:
internal_tmp_disk_storage_engine=MYISAM
Перезапустите mysql, запрос работает.
Ответ 12
Вот простой совет для всех, кто интересуется:
После обновления с Debian 9 до Debian 10 с 10.3.17-MariaDB у меня возникли некоторые ошибки из баз данных Joomla:
[Предупреждение] InnoDB: Невозможно добавить поле field
в таблицу database
. table
, поскольку после добавления его размер строки составляет 8742, что превышает максимально допустимый размер (8126) для записи на листе индекса.
На всякий случай я поставил
innodb_default_row_format = DYNAMIC в /etc/mysql/mariadb.conf.d/50-server.cnf
(это все равно было по умолчанию)
Затем я использовал phpmyadmin для запуска "Оптимизировать таблицу" для всех таблиц в базе данных Joomla.
Я думаю, что восстановление таблицы, сделанное phpmyadmin в процессе, помогло.
Если у вас установлен phpmyadmin, достаточно сделать всего несколько кликов.
Ответ 13
Я использую MySQL 5.6 на AWS RDS. Я обновил следующее в группе параметров.
innodb_file_per_table=1
innodb_file_format = Barracuda
Мне пришлось перезагрузить экземпляр БД, чтобы изменения группы параметров вступили в силу.
Кроме того, ROW_FORMAT = COMPRESSED не поддерживается. Я использовал DYNAMIC, как показано ниже, и он работал нормально.
ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8