Sergey Danielyan
Корректная настройка MySQL для работы с UTF8
Сегодня речь пойдет о MySQL и о настройке UTF8 кодировки по-умолчанию. Тема заезжена, но как я убедился за прошедшую неделю, мало кто в состоянии нормально пояснить какие параметры и куда надо прописать для полноценной работы с UTF8 в MySQL. К сожалению, ситуация на тематических блогах оставляет желать лучшего. Основной тип ответа — приведение соедржимого конфигурационного файла с комментарием типа “попробуй, у меня это работает”.
Основная цель данного поста — выяснить, какие параметры и с какими значениями следует прописать в конфигурационный файл my.cnf (my.ini) для дальнейшей беспроблемной работы с Юникодом.
Рабочее окружение
UTF8 на данный момент у меня успешно работает в Мастер-Слейв конфигурации:
- MySQL версии 5.1.66
- Два сервера CentOS версии 6.3
- Репликация между серверами Master-Slave на базе SSL
Любой внешний клиент в состоянии корректно работать с UTF8 базой (проверено на EMS Manager for MySQL c Windows 8 x64).
Все опции и настройки я привожу для версии сервера 5.1.x, однако с минимальными (а то и вовсе без оных) изменениями все это будет работать и на версиях 5.5.x и 5.6.x.
Параметры кодировок MySQL
Довольно часто приходится видеть в ответах на вопросы о настройке UTF8 следующее:
Предполагается, что после вставки всего этого добра (тут кстати есть противоречащие друг другу опции) в конфигурационный файл my.cnf (my.ini) магический Юникод начнет работать.
Но давайте забудем о списке и попытаемся разбираться со всеми опциями сами и начнем с самого начала. То есть с документации. Потому как все это прекрасно описано в документации MySQL на официальном сайте. Я лишь постараюсь последовательно рассказать о параметрах сервера и прояснить неясные моменты.
Главный раздел по описанию кодировок (character sets) и их представлений (collations — используется например при сортировке) в контексте сервера, базы, таблиц — это секция 10.1.3. Specifying Character Sets and Collations.
Символьная кодировка может быть задана для:
- сервера,
- базы данных,
- таблицы и
- колонок в таблице.
Сделано это для гибкой настройки баз данных и доступа клиентов с разными кодировками. Однако, последнее не входит в область рассмотрения данного поста, поэтому будем рассматривать вариант с кодировкой UTF8 настроенной для всего по-умолчанию.
Все параметры могут быть переданы серверу тремя разными способами:
- через командную строку mysqld
- через конфигурационный файл my.cnf (my.ini)
- через опции компиляции.
Второй и третий варианты рассматриваться не будут. Тут уместно будет просто прочитать официальные доки — в каждом разделе приведены примеры конфигурации с использованием всех трех способов. Я же буду использовать первый вариант.
Кодировка (character set) и представление (collation) сервера
Кодировка (characher set) — набор используемых символов.
Представление (collation) — набор правил для сравнения символов в наборе.
Тут есть несколько фундаментальных вещей которые надо понимать.
Основные параметры используемые в контексте сервера — это character_set_server и collation_server . Оба параметра влияют на определение кодировки и отображения сервера MySQL.
Можно задать оба параметра либо только один из них. При этом важно знать как задача того или иного влияет на определение отсутствующего:
Не заданы — используются значения по умолчанию (дефолтные),
Заданы оба — используются указанные кодировка и ее представление,
Задана только кодировка — ее представление выставляется по умолчанию для данного типа кодировки. Что это значит? Для каждого типа кодировки есть ее дефолтное представление, например, дефолтная кодировка сервера — latin1 , а дефолтное отображение для нее — latin1_swedish_ci . Посмотреть соответствие кодировки и ее дефолтного представления можно используя команду:
SHOW COLLATION LIKE ‘your_character_set_name’;
Поле Default дает ответ о представлении выбранной кодировки.
В нашем случае, при настройке дефолтной кодировки в UTF8, параметры должны быть определены, так как могут быть использованы при определении кодировки или представления базы данных:
Наши команды:
my.cnf (my.ini)
[mysqld]
character-set-server = utf8
collation-server = utf8_unicode_ci
Дефолтное представление для utf8 — utf8_general_ci , так что если бы мы его использовали вместо utf8_unicode_ci , то параметр collation_server можно было бы вообще опустить.
Кодировка (character set) и представление (collation) базы данных
Тут есть два варианта определения кодировки и представления:
явно — при выполнении запроса на создание базы данных:
CREATE DATABASE db_name CHARACTER SET latin1 COLLATE latin1_swedish_ci;
неявно через переменные character_set_database и collation_database . Однако, эти переменные нельзя задать явно ни в командной строке ни в конфигурационном файле. Как они инициализируются — чуть ниже.
Вообще при работе с базой данных огромную роль помимо серверных настроек играют настройки клиент-серверного соединения (connection). На этом этапе вступают в игру следующие специфичные для соединения параметры:
- character_set_client — кодировка в которой посылается запрос от клиента
- character_set_connection — кодировка используемая для конвертации пришедшего запроса (statement’а)
- character_set_results — кодировку, в которую сервер должен перевести результат перед его отправкой клиенту
Есть еще представление кодировки соединения ( colation_connection ). Для чего нужен этот параметр думаю пояснять не надо.
Озадачиваться проблемой инициализации всех этих переменных не стоит (хотя в нашем случае присвоить им значения необходимо). Есть способ проще: существует два типа запросов (statements) которые задают настройки соединения клиента с сервером группой:
Запрос SET NAMES ‘charset_name’ [COLLATE ‘collation_name’]
Параметр определяет в какой кодировке теперь будут приходить сообщения для сервера от клиента. Прелесть в том, что запрос SET NAMES x эквивалентен следующей группе:
SET character_set_client = x;
SET character_set_results = x;
SET character_set_connection = x;
Для определении представления кодировки соединения ( colation_connection ) отличного от дефолтного, следует дополнить запрос:
SET NAMES x COLLATE y
А так как у нас utf8 и ее дефолтное представление utf8_general_ci , то нам нужно выпонить полный запрос:
SET NAMES utf8 COLLATE utf8_unicode_ci
Таким образом, используя только этот запрос, можно добиться корректной UTF8 инициализации соединения.
Однако, тут есть один нюанс:
SET NAMES x , как понятно из определения, определяет настройку клиента при коннекте к серверу. Но что делать, если клиент — сам mysql.exe и нам хочется установить collation_connection по-умолчанию, не выполняя каждый раз SET NAMES x при коннекте?
Для этих целей, существует еще один параметр — default_character_set . Он эквивалентен запросу SET NAMES utf8 . В случае его использования задать collation_connection отличный от дефолтного уже не получится, поэтому придется заюзать еще одну команду init_connect (так как напрямую collation_connection нельзя прописать в конфигурационном файле):
init_connect=‘SET collation_connection = utf8_unicode_ci’
Но и тут есть еще одно но: init_connect команда не выполняется для SUPER пользователей — пользователей, обладающих привилегией SUPER. root входит в этот перечень, поэтому при коннекте root’ом команду SET collation_connection = utf8_unicode_ci все же придется выполнить вручную.
Запрос SET CHARACTER SET charset_name
Запрос групповой и он также эквивалентен следующей группе:
SET character_set_client = x;
SET character_set_results = x;
SET collation_connection = @@collation_database;
Согласно документации, разница между двумя запросами в том, что параметры character_set_connection и collation_connection будут установлены на @@character_set_database и @@collation_database соответственно (выше я про них упоминал).
За более детальной информацией отсылаю по двум источникам — собственно к официальной документации и прекрасно оформленному ответу на stackoverflow.com. Для нашей задачи вполне хватает первого параметра вместе с дополнительной командой.
Подытожим: различные сценарии и что юзается на каждом из них — относительно к настройкам соединения:
- Если к базе коннектится mysql.exe клиент с пользователем с привилегией SUPER:
- срабатывает опция в конфигурационном файле default_character_set = utf8
- надо выполнить вручную команду init_connect=’SET collation_connection = utf8_unicode_ci’
- Если к базе коннектится mysql.exe клиент с пользователем без привилегии SUPER:
- срабатывает опция в конфигурационном файле default_character_set = utf8
- срабатывает команда в конфигурационном файле init_connect=’SET collation_connection = utf8_unicode_ci’
- Если к базе коннектится внешний клиент:
- надо выполнить вручную команду SET NAMES utf8 COLLATE utf8_unicode_ci
Наши команды:
my.cnf (my.ini)
[client]
default_character_set = utf8
[mysqld]
init_connect=‘SET collation_connection = utf8_unicode_ci’
Кодировка (character set) и представление (collation) таблиц
Тут все довольно просто. Задать кодировку и ее представление можно через команды:
CREATE TABLE t1 ( … )
CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Тут главное иметь в виду, что если эти настройки не заданы, то берутся настройки базы данных (см. пред. раздел). Нам эти настройки не интересны.
Кодировка (character set) и представление (collation) колонок в таблице
Тут по аналогии с пред. секцией. Если параметры кодировок не указаны, берутся те, что указывались для таблицы.
Прежде чем перейти к след. разделу, должен сказать, что все команды и запросы относятся к указанной версии MySQL и в случае возникновения каких-либо проблем советую обратиться к соответствующей версии документации.
skip-character-set-client-handshake
Помимо освещенных параметров, есть еще один довольно часто фигурирующий в разного рода источниках — skip-character-set-client-handshake. Установка этого параметра позволит проигнорировать информацию клиента о кодировке. Я данный параметр не использовал.
Верификация настроек
Итак, вот финальный snapshot наших изменений в файле my.cnf (my.ini):
[mysqld]
init_connect=‘SET collation_connection = utf8_unicode_ci’
character-set-server = utf8
collation-server = utf8_unicode_ci
[client]
default-character-set = utf8
После применения всех опций и рестарта сервера mysql для проверки настроек можно воспользоваться командами SHOW VARIABLES LIKE ‘char%’ и SHOW VARIABLES LIKE ‘collation%’ ;
Состояние среды до изменений:
Состояние среды после изменений (в случае, если вы приконнектились не SUPER пользователем):
Для примера, вот отличие при соединении через mysql.exe пользователем с и без привилегии SUPER:
с привилегией и выполненной вручную командой ‘SET collation_connection = utf8_unicode_ci’:
Поздравляю, теперь ваши база, таблицы и все в таблицах по-умолчанию в кодировке UTF8.
Использование кодировок в MySQL >= 4.1
Когда я только начал осваивать InnoDB и транзакции в MySQL (понадобилось обновить версию с 3.23 до 4.1) столкнулся с проблемой некорректного обмена данными между PHP и MySQL которая проявлялась в том, что сервер вместо символов кириллицы, в запросах генерируемых php-скриптом, вставлял в ячейки таблиц БД знаки вопроса. В процессе «выкуривания» документации, чтения форумов и изучения статей пришло понимание проблемы и нашелся способ ее решения.
Первопричиной проблемы оказалось то, что до версии 4.1 кодировку можно было задать только для всего сервера (определив значение параметра —default-charset ), а начиная с версии 4.1 разработчики добавили возможность определения кодировки на разных уровнях иерархии СУБД (для всего сервера, БД, таблиц, столбцов).
Немного терминологии
CHARACTER SET — это некий набор символов, называемых кодировкой. Разные CHARACTER SET включают в себя различные наборы символов. Различные CHARACTER SET могут включать примерно одинаковые наборы символов но в различном порядке (см. например koi8ru и cp1251). MySQL необходимо знать какой CHARACTER SET будет использован для данных в таблице, чтобы корректно проводтиь сортировку и индексацию данных.
COLLATION — способ, с помощью которого следует упорядочивать и сравнивать данные в БД.
Для одного и того же CHARACTER SET существует как правило несколько COLLATION. Например: cp1251_general_ci — сравнение не чувствительное к регистру, cp1251_bin — чувствительное к регистру.
Для того чтобы избежать проблем с кодировками нужно иметь представление о том, как для разных уровней иерархии СУБД их можно задать.
Способы задания кодировок
1) Для всего сервера при компиляции, определив параметры —with-charset и —with-collation :
Работа с клиентскими программами
Любой mysql-клиент при соединении с сервером может установить несколько переменных:
- character_set_client — указывает, в какой кодировке будут поступать данные от клиента;
- character_set_connection — указывает, в какую кодировку следует преобразовать данные полученые от клиента перед выполнением запроса;
- collation_connection — указывает, каким образом сравнивать между собой строки в запросах;
- character_set_results — указывает серверу не необходимость перекодировать результаты запроса в определенную кодировку перед выдачей их клиенту.
Для корректной работы клиента с сервером следует установть как минимум character_set_client, character_set_connection, character_set_results при помощи оператора SET:
Кодировка базы данных MySQL – выводим из запоя пьющие базы
От автора: вы зачем полное ведро баз на мусорку несете выбрасывать? Сервер китайский попался, и все строки иероглифами отображаются? Так кодировка базы данных MySQL не та, наверное. Кто ее закодирует, она же база? Понятно! Идите, гражданин дальше. Не обращаем на него внимания. Сегодня мы познакомимся с кодировками в MySQL.
Зачем кодировать БД?
Сразу хочу вас заверить, что у нас ни одной «пьющей» базы нет. Поэтому данная кодировка никак не связана с чрезмерным употреблением «горячительных» напитков. Наоборот, все БД кодируются для того, чтобы пользователи (то есть мы с вами) могли прочитать содержащуюся в них информацию. Понятно, что непонятно и без полулитра не разберешься? . Давайте обойдемся пока без этого крайнего средства. Сейчас все поясню!
Код MySQL, как и любая другая информация в вычислительной технике, задается с помощью сочетания единицы и нуля, которые образуют биты. Вспоминаете? Это ведь основы информатики, которые все мы проходили в школе.
В мире существует множество текстовых кодировок (сочетаний 0 и 1), но в современности все они более-менее стандартизированы. Хотя и сейчас можно наткнуться на «абракадабру», если неправильно задать кодировку.
Бесплатный курс по PHP программированию
Освойте курс и узнайте, как создать динамичный сайт на PHP и MySQL с полного нуля, используя модель MVC
В курсе 39 уроков | 15 часов видео | исходники для каждого урока
На данном этапе развития всемирной паутины самыми распространенными являются 3 типа кодировок:
Мы не будет сильно «зарываться» в теоретическом ворохе. Для получения более детальной информации перейдите по расположенным выше ссылкам на соответствующие публикации в Википедии.
Для нас самой главной кодировкой базы данных MySQL является UTF-8. Это значит, что в ней используется 8-битный Юникод для представления всех символов. Благодаря широкой поддержке данной кодировки в Сети и на прикладном уровне вы можете быть уверены, что записи в базе будут сохранены в читаемом виде (без «абракадабр»).
Где ее искать?
Немного пробежимся по интерфейсу phpMyAdmin. Зайдя на первую страницы программы, обратите внимание на раздел «Общие настройки».
Параметр «Сопоставление кодировки соединения с MySQL» устанавливает, с какой кодировкой должен сравниваться формат полученных данных при подключении к серверу СУБД. В этой программной оболочке кодировку можно задать вручную.
В «родных» утилитах СУБД (mysqladmin, mysqlimport и других) кодировка таблиц MySQL берется из настроек операционной системы ПК. В случае их отсутствия устанавливается значение, заданное по умолчанию. Чаще всего, это кодировка latin1.
При соединении с СУБД клиентская сторона с помощью значений нескольких системных переменных говорит MySQL, какую кодировку использовать при обработке и отображении данных из БД.
Системные переменные и их значения
Архитектура MySQL построена на основе «клиент-сервер». Системные переменные (точнее их значения) используются при установке соединения клиента и сервера для корректного отображения всех данных, их обработки и поддержания сетевого сеанса.
Для ознакомления с установленными значениями переменных системы СУБД в phpMyAdmin нужно в последнем пункте верхнего меню «Еще» выбрать «Переменные».
После этого вам станут доступны для просмотра и редактирования все системные переменные. Настоятельно рекомендую не менять установленных значений, если не знаете «что почем». На устранение причиненного вреда может уйти много времени. Также это чревато плохим настроением, преждевременной сединой и проявлением других симптомов профессиональных болезней сисадминов .
Также список всех переменных (в том числе и тех, которые нужны для настройки кодировка MySQL) можно получить с помощью команды show variables.
Вернемся к полученному списку переменных, и остановимся на тех, которые начинаются с charset. Краткое описание тех, которые могут пригодиться:
character_set_client – указана кодировка, в которой будут поступать данные с клиентской стороны.
character_set_connection – устанавливает кодировку соединения.
Бесплатный курс по PHP программированию
Освойте курс и узнайте, как создать динамичный сайт на PHP и MySQL с полного нуля, используя модель MVC
В курсе 39 уроков | 15 часов видео | исходники для каждого урока
character_set_database –набор символов, используемы в БД по умолчанию.
character_set_results – кодировка, в которой сервер отправит данные клиенту.
character_set_server –используемая по умолчанию на сервере.
Вот тут перед описанием следующей группы переменных, необходимых для того, как узнать кодировку базы MySQL, следует покопаться в теории.
Под кодировкой мы подразумеваем набор символов, применяемых для определенной структуры данных (базы, таблицы, поля). Но есть еще такое понятие как «представление» (collation), которая соответствует конкретному языку и используется при сравнении и упорядочивания записей.
Например, есть кодировка UTF-8. Существует огромное количество представлений в рамках одной кодировки. Нельзя сравнивать данные, «представленных» в разных наборах символов. Это можно осуществлять только в рамках одной кодировки. Последние 3 переменные как раз и показывают установленные представления.
Разрешенные сравнения для конкретной кодировки на текущем экземпляре сервера, можно узнать с помощью команды show collation. Например: