Получение повторяющихся ошибок ввода при преобразовании базы данных utf-8 в utf8mb4

Я пытаюсь преобразовать базу данных, чтобы использовать utf8mb4 вместо utf8. Все идет хорошо, кроме одного стола:

CREATE TABLE `search_terms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`search_term` varchar(128) NOT NULL,
`time_added` timestamp NULL DEFAULT NULL,
`count` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `search_term` (`search_term`),
KEY `search_term_count` (`count`)
) ENGINE=InnoDB AUTO_INCREMENT=198981 DEFAULT CHARSET=utf8;

По сути, все, что он делает — это сохраняет запись каждый раз, когда кто-то что-то ищет в форме, чтобы мы могли отслеживать количество запросов, очень просто.

Там есть уникальный индекс search_term потому что мы хотим иметь только одну строку для каждого поискового запроса и вместо этого увеличивать значение счетчика.

Однако при конвертации в utf8mb4 я получаю повторяющиеся ошибки ввода. Вот команда, которую я выполняю:

ALTER TABLE `search_terms` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Глядя в базу данных, я вижу различные примеры, подобные этому:

fm2012

fm2012

fm2012

В его текущем наборе символов utf8 все они рассматриваются как уникальные и существуют в базе данных, при этом никогда не возникало проблем с уникальным индексом search_term,

Но при конвертации в utf8mb4 они теперь считаются равными и выдают ошибку из-за этого индекса.

Я могу понять, как объединить их достаточно легко, но я обеспокоен тем, что это может быть признаком более серьезной основной проблемы. Я не совсем уверен, как это произошло или каковы могут быть последствия, поэтому мои вопросы немного расплывчаты:

  1. Почему utf8mb4 относится к ним по-разному к utf8?
  2. Каковы возможные последствия?
  3. Могу ли я сделать преобразование, чтобы такие вещи, как «like», никогда не появлялись в моей базе данных, а у меня только «fm2012» (я также использую Laravel 5.1)

0

Решение

Ваша проблема заключается в изменении сортировки: вы используете general_ci и вы переходите к unicode_ci: general_ci довольно простое сопоставление, которое мало что знает о юникоде, но unicode_ci делает.

Первое «f» в строке примера — это «Латинская буква F полной ширины» (U + FF46), которая считается равной «Латинской букве F» (U + 0066) unicode_ci но не general_ci,

Обычно рекомендуется использовать unicode_ci именно из-за его Unicode-осведомленности, но вы могли бы преобразовать в utf8mb4_general_ci чтобы предотвратить эту проблему.

Чтобы предотвратить эту проблему в будущем, вы должны нормализовать Ваш вход перед сохранением в БД. Обычно вы бы использовали NFC, но ваш случай, кажется, требует NFKC. Это должно привести все «эквивалентные» строки к одной и той же форме.

1

Другие решения

Несмотря на то, что было сказано ранее, речь идет не о general_ci быть более упрощенным, чем unicode_ci, Да, это может быть правдой, но проблема в том, что вы должны поддерживать его в соответствии с вашим подтипом.

Например, моя база данных utf8_bin, Я не могу перейти в utf8mb4_unicode_ci ни к utf8mb4_general_ci, Эти команды будут выдавать ошибку при обнаружении дубликата ключа. Однако правильное сопоставление utf8mb4_bin завершается без проблем.

0

По вопросам рекламы [email protected]