MySQL различные UTF – utf8_bin и utf8_general_ci
Чем же отличаются эти два collate для таблиц?
utf8_bin – использует сравнения по двоичным значениям каждого символа
utf8_general_ci – использует сравнения на основе языковых особенностей и игнорирует регистр символов.
Для наглядности приведем небольшой эксперимент.
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
first_name VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
last_name VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
) ENGINE = INNODB CHARACTER SET utf8;
INSERT INTO peoples (first_name, last_name) VALUES ('Петя', 'Иванов'), ('андрей', 'иванов'), ('Иван', 'Петров'), ('Андрей', 'Сидоров');
INSERT INTO peoples (first_name, last_name) VALUES ('Петр', 'Большой'), ('Пётр', 'Большои');
Получаем такую вот табличку:
+----+--------------+----------------+
| id | first_name | last_name |
+----+--------------+----------------+
| 1 | Петя | Иванов |
| 2 | андрей | иванов |
| 3 | Иван | Петров |
| 4 | Андрей | Сидоров |
| 5 | Петр | Большой |
| 6 | Пётр | Большои |
+----+--------------+----------------+
Из-за разности сопоставления символов получаются различия в сортировке, если делать её по полю с utf8_general_ci получаем следующее:
+----+--------------+----------------+
| id | first_name | last_name |
+----+--------------+----------------+
| 2 | андрей | иванов |
| 4 | Андрей | Сидоров |
| 3 | Иван | Петров |
| 5 | Петр | Большой |
| 6 | Пётр | Большои |
| 1 | Петя | Иванов |
+----+--------------+----------------+
И не совсем ожидаемым образом отрабатывает запрос с сортировкой по полю utf8_bin
+----+--------------+----------------+
| id | first_name | last_name |
+----+--------------+----------------+
| 6 | Пётр | Большои |
| 5 | Петр | Большой |
| 1 | Петя | Иванов |
| 3 | Иван | Петров |
| 4 | Андрей | Сидоров |
| 2 | андрей | иванов |
+----+--------------+----------------+
Помимо всего прочего в utf8_general_ci некоторые буквы считаются идентичными, например ё = е:
+----+------------+----------------+
| id | first_name | last_name |
+----+------------+----------------+
| 5 | Петр | Большой |
| 6 | Пётр | Большои |
+----+------------+----------------+
Отсюда же может появиться и проблема с уникальными ключами. В приведенной структуре уникальный ключ по полю first_name создать не получится, т. к. дублируются значения «Андрей» и «андрей», а так же не совсем ожидаемые «Пётр» и «Петр».
ERROR 1062 (23000): Duplicate entry 'Пётр' FOR KEY 3
Зато по полю last_name создастся без проблем, в нем все значения различающиеся:
Query OK, 6 rows affected (0.06 sec)
Records: 6 Duplicates: 0 Warnings: 0
С проблемой уникальности я столкнулся при переводе старой таблички с пользователями из cp1251_general_ci в utf8_general_ci – логины «Ёлка» и «елка» перестали быть уникальными. Можно было создать эталонное поле utf8_bin (используемое только при авторизации) со значением приведенным к скажем нижнему регистру.
Ну и мануал: Unicode Character Sets
Июль 11th, 2010 at 08:15
Спасибо. Все просто и понятно.