SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 02.06.2018 10:28:39

immelnikoff
Участник
Зарегистрирован: 19.04.2018
Сообщений: 7

Вопрос по кодировкам: character_set_client и character_set_connection

Вопрос 1: Допустим, character_set_client = cp1251. Это означает, что сервер MySQL будет ожидать от клиента текст sql-запросов в кодировке cp1251?
Вопрос 2: Теперь пусть character_set_connection = utf8mb3 и пусть требуется в sql-запросе выполнить сравнение строки с полем type таблицы animals. При этом поле type таблицы animals имеет кодировку koi8r. Запрос, например, такой:
SELECT id FROM animals WHERE type = 'кошка'.
MySQL-сервер получает этот запрос в кодировке cp1251, затем переводит поле записи type из кодировки koi8r в кодировку utf8mb3 и строку 'кошка' из кодировки cp1251 в кодировку utf8mb3 и уже только после этого производит сравнение (согласно установленному collation)?

Неактивен

 

#2 04.06.2018 00:50:58

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6691

Re: Вопрос по кодировкам: character_set_client и character_set_connection

Первый вопрос — да.
Второй вопрос — иногда smile В случае, когда используется полный скан по таблице, сравнение идет в памяти (и тогда оно должно идти в character_set_connection). В случае, когда над type есть индекс, MySQL должен преобразовать текст в кодировку поля, чтобы можно было использовать индекс.

Подробное описание этих переменных есть в документации: https://dev.mysql.com/doc/refman/8.0/en … ction.html

Но мне кажется, что в 21 веке вредно делать кодировки отличные от utf8/utf8mb4 где-либо вообще.

Неактивен

 

#3 04.06.2018 13:48:18

immelnikoff
Участник
Зарегистрирован: 19.04.2018
Сообщений: 7

Re: Вопрос по кодировкам: character_set_client и character_set_connection

paulus написал:

Первый вопрос — да.
В случае, когда используется полный скан по таблице, сравнение идет в памяти (и тогда оно должно идти в character_set_connection). В случае, когда над type есть индекс, MySQL должен преобразовать текст в кодировку поля, чтобы можно было использовать индекс.

То есть, создание или удаление индекса для поля type может повлиять на результат запроса
SELECT id FROM animals WHERE type = 'кошка'; ? Ведь для кодировки поля и кодировки connection установлены разные collation.

paulus написал:

Но мне кажется, что в 21 веке вредно делать кодировки отличные от utf8/utf8mb4 где-либо вообще.

Дело в размере. Латинские буквы и цифры в utf8mb3/utf8mb4 весят по 1 байту, а русские – по 2 байта. В cp1251 все символы весят 1 байт. Получается, что в кодировке cp1251 нужно меньше памяти. Но дело не только в этом. Если в таблице есть поле типа CHAR, которое может содержать русские и английские буквы вперемешку, то, если кодировка поля cp1251, то размер поля для каждой записи имеет одинаковый размер в байтах, что скорей всего положительно сказывается на скорости SELECT. Если поле в кодировке utf8/utf8mb4, то размер поля будет "плавать". Ну и как бонус, для кодировки cp1251 меньше нагрузка на сеть.

Отредактированно immelnikoff (05.06.2018 12:18:09)

Неактивен

 

#4 04.06.2018 14:02:06

klow
Старожил
Зарегистрирован: 06.12.2014
Сообщений: 355

Re: Вопрос по кодировкам: character_set_client и character_set_connection

В 90-х, может быть это имело значение, но сегодня аргументация по поводу сети - не думаю, что имеет реальные основания. Настоятельно рекомендую послушаться совета paulus.

Неактивен

 

#5 04.06.2018 20:02:51

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6691

Re: Вопрос по кодировкам: character_set_client и character_set_connection

Я попробовал, MySQL оказался еще хитрее: для того, чтобы не свалиться с разным ответом, он игнорирует индекс в случае со смешанными кодировками (и приводит константные данные к кодировке столбца по умолчанию):

[surfer] root test > show create table a\G
*************************** 1. row ***************************
       Table: a
Create Table: CREATE TABLE `a` (
  `a` char(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=cp1251
1 row in set (0,00 sec)

[surfer] root test > select a, count(*) from a group by 1;
+------+----------+
| a    | count(*) |
+------+----------+
|      |    65536 |
| е    |        1 |
| ё    |        1 |
+------+----------+
3 rows in set (0,05 sec)

[surfer] root test > explain select * from a where a = 'е' collate utf8_general_ci;
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
|  1 | SIMPLE      | a     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 64244 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
1 row in set, 1 warning (0,00 sec)

[surfer] root test > select * from a where a = 'е' collate utf8_general_ci;
+------+
| a    |
+------+
| е    |
| ё    |
+------+
2 rows in set (0,02 sec)

[surfer] root test > alter table a add index(a);
Query OK, 0 rows affected (0,10 sec)
Records: 0  Duplicates: 0  Warnings: 0

[surfer] root test > explain select * from a where a = 'е' collate utf8_general_ci;
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows  | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+--------------------------+
|  1 | SIMPLE      | a     | NULL       | index | NULL          | a    | 2       | NULL | 64244 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+--------------------------+
1 row in set, 1 warning (0,00 sec)

[surfer] root test > select * from a where a = 'е' collate utf8_general_ci;
+------+
| a    |
+------+
| е    |
| ё    |
+------+
2 rows in set (0,02 sec)

[surfer] root test > explain select * from a where a = 'е';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | a     | NULL       | ref  | a             | a    | 2       | const |    1 |   100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0,00 sec)

[surfer] root test > select * from a where a = 'е';
+------+
| a    |
+------+
| е    |
+------+
1 row in set (0,00 sec)

[surfer] root test > select @@collation_connection;
+------------------------+
| @@collation_connection |
+------------------------+
| utf8_general_ci        |
+------------------------+
1 row in set (0,00 sec)
 

Неактивен

 

#6 05.06.2018 12:41:00

immelnikoff
Участник
Зарегистрирован: 19.04.2018
Сообщений: 7

Re: Вопрос по кодировкам: character_set_client и character_set_connection

paulus написал:

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

То есть, если
character_set_client = cp1251,
character_set_connection = utf8mb3,
а кодировка поля таблицы – koi8r,
то при запросе

SELECT id FROM animals WHERE type = 'кошка';
строка 'кошка' независимо от наличия индекса на поле будет переведена в кодировку поля и уже потом будет произведено сравнение? Другими словами, при сравнении константной строки с полем, константная строка всегда переводится в кодировку поля?
Тогда возникает вопрос для чего нужен character_set_connection? Только для случая, когда в запросе нужно сравнить две константные строки?

Неактивен

 

#7 05.06.2018 13:40:19

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6691

Re: Вопрос по кодировкам: character_set_client и character_set_connection

Вам нужно в какой-то кодировке хранить данные в памяти. Вот это она.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson