Содержание
Duplicate entry '2147483647' for key 'PRIMARY'
Диагноз
Ну вот и напоролись на ограничение первичного ключа:
Это сообщение об ошибке из Битрикса в ответ на штатный механизм обновления данных в инфоблоках. Текст SQL ошибки:
MySQL Query Error: INSERT INTO b_iblock_element_prop_m45 (IBLOCK_ELEMENT_ID, IBLOCK_PROPERTY_ID, VALUE, VALUE_NUM, DESCRIPTION) SELECT 111871 ,P.ID ,'47585e53-0113-11e0-8255-003048d2334c' ,47584999999999 , '374' FROM b_iblock_property P WHERE ID=384</font>[Duplicate entry '2147483647' FOR KEY 'PRIMARY']
То же самое из админки при добавлении нового значения свойства:
Вот почему `ID` int(11) NOT NULL AUTO_INCREMENT
- зло. А тут еще поле объявлено как целое знаковое (считай, потеряли половину диапазона):
mysql> SHOW CREATE TABLE b_iblock_element_prop_m45\G *************************** 1. ROW *************************** TABLE: b_iblock_element_prop_m45 CREATE TABLE: CREATE TABLE `b_iblock_element_prop_m45` ( `ID` INT(11) NOT NULL AUTO_INCREMENT, `IBLOCK_ELEMENT_ID` INT(11) NOT NULL, `IBLOCK_PROPERTY_ID` INT(11) NOT NULL, `VALUE` text NOT NULL, `VALUE_ENUM` INT(11) DEFAULT NULL, `VALUE_NUM` DECIMAL(18,4) DEFAULT NULL, `DESCRIPTION` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`ID`), KEY `ix_iblock_elem_prop_m45_1` (`IBLOCK_ELEMENT_ID`,`IBLOCK_PROPERTY_ID`), KEY `ix_iblock_elem_prop_m45_2` (`IBLOCK_PROPERTY_ID`), KEY `ix_iblock_elem_prop_m45_3` (`VALUE_ENUM`,`IBLOCK_PROPERTY_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=2147483647 DEFAULT CHARSET=cp1251 1 ROW IN SET (0.00 sec)
Варианты решения
Решения два: сменить тип первичного ключа на беззнаковый UNSIGNED
(проблема откладывается на будущее), либо перенумеровать первичный ключ, так как число записей всего лишь 265422:
mysql> SELECT COUNT(*) FROM b_iblock_element_prop_m45; +----------+ | COUNT(*) | +----------+ | 265422 | +----------+
Смена типа первичного ключа на беззнаковый
Первый вариант сработал, ошибок не замечено:
ALTER TABLE `b_iblock_element_prop_m45` MODIFY `ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT;
Перенумерация первичного ключа с исправлением зависимостей
Хорошее решение. Хватит на 8 лет, затем - снова перенумерация. Но так как таблицы могут быть связаны, определим как это сделано.
Поиск зависимостей
Для начала я сделал построчный дамп всех таблиц в отдельные файлы, чтобы удобно было искать:
# PS. Необходимо определить параметры подключения через переменные for t in $(mysql -NBA -h $DB_host -u $DB_user -D $DB -e 'show tables') do echo "DUMPING TABLE: $t" mysqldump --default-character-set=utf8 --extended-insert=FALSE --complete-insert=TRUE -h $DB_host -u $DB_user $DB $t > $DIR/$t.sql done
Найдем первые и последние 10 ID
:
SELECT ID FROM b_iblock_element_prop_m45 ORDER BY ID ASC LIMIT 10; SELECT ID FROM b_iblock_element_prop_m45 ORDER BY ID DESC LIMIT 10;
Затем поищем в каких таблицах есть эти ID
:
grep -r 1837653803 grep -r 1837653812 # и так далее
Я понял, что связанных таблиц две: b_iblock_element_prop_m45
и b_iblock_element_prop_s45
- в ней ID
сохранен как serialized
:
{i:0;s:10:\"1837653803\";i:1;s:10:\"1837653804\";i:2;s:10:\"1837653805\";i:3;s:10:\"1837653806\"
То, что связка хранится как serialized
, усложняет задачу: нельзя обойтись только средствами SQL.
Размеры таблиц:
SELECT TABLE_NAME AS `Table`, round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB` FROM information_schema.TABLES WHERE TABLE_NAME IN ('b_iblock_element_prop_m45', 'b_iblock_element_prop_s45') AND table_schema = "my_cool_db"; +---------------------------+------------+ | TABLE | SIZE IN MB | +---------------------------+------------+ | b_iblock_element_prop_m45 | 37.09 | | b_iblock_element_prop_s45 | 19.55 | +---------------------------+------------+
Таблицы небольшие, поэтому сделаю скрипт, который сделает две временные таблицы, перенумерует ID «как надо», и заменит существующие данные.
Для обкатки на тестовом сайте делаем дамп, который будем поднимать в случае провала:
mysqldump my_cool_db b_iblock_element_prop_m45 b_iblock_element_prop_s45 > prop-45.sql;
Скрипт перенумерации ID
Найденные зависимости следует подставить в скрипт перенумерации ID.
Заняло 30 секунд на таблицах с количеством записей: 265422 (перенумерация, где вылез лимит) и 10987 (исправление ID).