Приложение B. Ошибки, коды ошибок и общие проблемы

Это приложение перечисляет типичные проблемы и ошибки, которые могут произойти и потенциальные решения, в дополнение к перечислению ошибок, которые могут появиться, когда Вы вызываете MySQL из любого языка. Первый раздел покрывает проблемы и решения. Подробная информация об ошибках обеспечена: один список включает сообщения об ошибках сервера. Другой список включает сообщения программы клиента.

B.1. Источники информации об ошибке

Есть несколько источников информации об ошибке в MySQL:

Описания ошибок сервера и клиента обеспечены позже в этом Приложении. Для информации об ошибках, связанных с InnoDB, см. раздел 16.20.4.

B.2. Типы значений ошибки

Когда ошибка происходит в MySQL, сервер возвращает два типа значений:

Строка сообщения, которая обеспечивает текстовое описание ошибки, также доступна.

Когда ошибка происходит, код ошибки MySQL, значение SQLSTATE и строка сообщения доступны через функции C API:

Для готовых запросов соответствующие функции ошибок mysql_stmt_errno(), mysql_stmt_sqlstate() и mysql_stmt_error() . Все функции ошибок описаны в разделе 25.8 .

Число ошибок, предупреждений и примечаний для предыдущего запроса может быть получено вызовом mysql_warning_count() . См. раздел 25.8.7.77.

Первые два символа значения SQLSTATE указывают на класс ошибки:

B.3. Коды ошибок сервера

У программ MySQL есть доступ к нескольким типам информации об ошибке, когда сервер возвращает ошибку. Например, клиент mysql выводит на экран ошибки, используя следующий формат:

shell> SELECT * FROM no_such_table;
ERROR 1146 (42S02): Table 'test.no_such_table' doesn't exist
Выведенное на экран сообщение содержит три типа информации:

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

Коды ошибки устойчивы во всех релизах GA данного ряда MySQL. Прежде, чем ряд достигает состояния GA, новые коды могут все еще разрабатываться и подвержены изменениям.

Информация об ошибке сервера прибывает из следующих исходных файлов. Для деталей о способе, которым определена информация об ошибке, см. MySQL Internals Manual.

Поскольку обновления бывают часто, возможно, что те файлы будут содержать дополнительную информацию об ошибках, не перечисленную здесь.

B.4. Коды ошибки и сообщения клиента

Информация об ошибке клиента прибывает из следующих исходных файлов:

Поскольку обновления бывают часто, возможно, что те файлы будут содержать дополнительную информацию об ошибках, не перечисленную здесь.

B.5. Проблемы и распространенные ошибки

Этот раздел перечисляет некоторые типичные проблемы и сообщения об ошибках, с которыми Вы можете столкнуться. Это описывает, как определить причины проблем и что сделать, чтобы решить их.

B.5.1. Как определить, что вызывает проблему

Когда Вы сталкиваетесь с проблемой, первая вещь, которую Вы должны сделать, состоит в том, чтобы узнать, какая программа или элемент оборудования вызывают ее:

Если после того, как Вы исследовали все другие возможности и пришли к заключению, что сервер или клиент MySQL вызывают проблему, пора создать отчет об ошибках для списка рассылки или команды поддержки. В отчете об ошибках, попытайтесь дать очень подробное описание того, как система ведет себя и что Вы думаете, происходит. Вы должны также заявить, почему Вы думаете, что именно MySQL вызывает проблему. Учтите все ситуации в этой главе. Опишите любые проблемы точно, как они появляются, когда Вы исследуете свою систему. Используйте копирование и вставку для любых выходных сигналов и сообщений об ошибках из программ и файлов системного журнала.

Попытайтесь описать подробно, какая программа не работает и все признаки, которые Вы видите. Мы получили в прошлом много отчетов об ошибках, которые заявляют только "ничего не работает". Это не предоставляет информации о том, что могло быть проблемой.

Если программа терпит неудачу, всегда полезно знать следующую информацию:

Посылая отчет об ошибках, Вы должны следовать схеме, описанной в разделе 1.7.

B.5.2. Распространенные ошибки при использовании программ MySQL

Этот раздел перечисляет некоторые ошибки, с которыми пользователи часто сталкиваются, выполняя программы MySQL. Хотя проблемы обнаруживаются, когда Вы пытаетесь выполнить программы клиента, решения многих из проблем вовлекают изменение конфигурации сервера MySQL.

B.5.2.1. Access denied

Ошибка Access denied может иметь много причин. Часто проблема связана с учетными записями MySQL, которые сервер разрешает программам клиента использовать, соединяясь. См. разделы 7.2 и 7.2.8.

B.5.2.2. Can't connect to [local] MySQL server

Клиент MySQL на Unix может соединиться с сервером mysqld двумя различными способами: используя файл сокета Unix, чтобы соединиться через файл в файловой системе (значение по умолчанию /tmp/mysql.sock), или по TCP/IP, который соединяется через номер порта. Соединение файла сокета Unix быстрее, чем TCP/IP, но может использоваться только, соединяясь с сервером на том же самом компьютере. Файл сокета Unix используется, если Вы не определяете имя хоста или если определяете специальное имя хоста localhost.

Если сервер MySQL работает на Windows, Вы можете соединиться по TCP/IP. Если сервер запущен с опцией --enable-named-pipe, Вы можете также соединиться по именованному каналу, если Вы выполняете клиента на том компьютере, на котором работает сервер. Название названного канала MySQL по умолчанию. Если Вы не задаете имя хоста, соединяясь с mysqld, клиент MySQL сначала пытается соединиться с названным каналом. Если это не работает, он соединяется с портом TCP/IP. Вы можете вызвать использование именованных каналов в Windows при использовании . как имени хоста.

Ошибка (2002) Can't connect to ... обычно сообщает, что нет никакого сервера MySQL, работающего в системе, или что Вы используете неправильное имя файла сокета Unix или номер порта TCP/IP, пытаясь соединиться с сервером. Вы должны также проверить, что порт TCP/IP, который Вы используете, не был заблокирован брандмауэром или службой блокирования порта.

Ошибка (2003) Can't connect to MySQL server on 'server' (10061) указывает, что сетевое соединение не работает. Вы должны проверить, что есть выполненяемый сервер MySQL, что у него есть включенные сетевые соединения, и что сетевой порт, который Вы определили, является тем, который настроен на сервере.

Начните с проверки того, есть ли процесс mysqld, работающий на Вашем хосте сервера. Используйте ps xa | grep mysqld в Unix или Task Manager в Windows. Если нет такого процесса, Вы должны запустить сервер. См. раздел 2.9.2.

Если процесс mysqld работает, Вы можете проверить это, пробуя следующие команды. Номер порта или имя файла сокета Unix могут отличаться в Вашей установке. host_ip представляет IP-адрес машины, где сервер работает.

shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h host_ip version
shell> mysqladmin --protocol=SOCKET --socket=/tmp/mysql.sock version
Отметьте использование обратных кавычек, а не кавычек с командой hostname: они заставляют вывод hostname (то есть, текущее имя хоста) быть замененным в команде mysqladmin. Если Вы не имеете команды hostname или работаете в Windows, Вы можете вручную ввести имя хоста своей машины (без обратных кавычек) после опции -h. Вы можете также попробовать -h 127.0.0.1, чтобы соединяться по TCP/IP с локальной машиной.

Удостоверьтесь, что сервер не был сконфигурирован так, чтобы игнорировать сетевые соединения или (если Вы пытаетесь соединиться удаленно), что он не был сконфигурирован, чтобы слушать только локально на его сетевых интерфейсах. Если сервер был запущен с опцией --skip-networking , он не будет принимать соединения TCP/IP вообще. Если сервер был запущен с опцией --bind-address=127.0.0.1, он обрабатывает соединения TCP/IP только локально на кольцевом интерфейсе и не будет принимать удаленные соединения.

Проверьте, что нет никакого брандмауэра, блокирующего доступ к MySQL. Ваш брандмауэр может быть сконфигурирован на основе выполняемого приложения или номера порта, используемого MySQL для коммуникации (3306 по умолчанию). Под Linux или Unix, проверьте свои настройки IPtables (или подобные), чтобы гарантировать, что порт не был заблокирован. Под Windows приложения, такие как ZoneAlarm или Брандмауэр Windows, возможно, должны быть сконфигурированы, чтобы не блокировать порт MySQL.

Вот некоторые причины ошибки Can't connect to local MySQL server :

Если Вы получаете сообщение об ошибке Can't connect to MySQL server on some_host, Вы можете попробовать следующие вещи, чтобы узнать, в чем проблема:

B.5.2.2.1. Соединение с сервером MySQL терпит неудачу в Windows

Когда Вы выполняете сервер MySQL на Windows со многими соединениями TCP/IP с ним, и Ваши клиенты получают ошибку Can't connect to MySQL server , причина может быть в том, что Windows не учитывает достаточно много короткоживущих портов для таких соединений.

TIME_WAIT должен сохранить соединение, принимающее пакеты даже после того, как соединение было закрыто. Это потому, что интернет-маршрутизация может заставить пакет следовать медленным маршрутом к своему месту назначения, и он может прибыть после того, как обе стороны согласились закрыть соединение. Если порт используется для нового соединения, тот пакет от старого соединения мог бы сломать протокол или поставить под угрозу данные оригинального соединения. Задержка TIME_WAIT предотвращает это, гарантируя, что порт не может быть снова использован, пока некоторое время не пройдет для тех отсроченных пакетов.

Безопасно уменьшить TIME_WAIT на LAN-соединениях, потому что есть немного шансов существования пакетов с очень длинными задержками, по сравнению с Интернет с его сравнительно большими расстояниями и временами ожидания.

Windows разрешает эфемерные (недолгие) порты TCP пользователю. После того, как любой порт закрыт, это останется в статусе TIME_WAIT 120 секунд. Порт не будет доступен снова, пока это время не истечет. Диапазон по умолчанию значений номеров портов зависит от версии Windows, с большим ограниченным количеством портов в более старых версиях:

С маленьким стеком доступных портов TCP (5000) и высоким числом портов TCP, открытых и закрытых за короткий период времени наряду со статусом TIME_WAIT у Вас есть хороший шанс для того, чтобы исчерпать порты. Есть два способа решить эту проблему:

Следующая процедура вовлекает изменение реестра Windows. Прежде, чем Вы измените реестр удостоверьтесь, что зарезервировали его и понимаете, как восстановить, если проблема происходит. Для информации о том, как сохранить, восстановить и отредактировать реестр, смотрите следующую статью в Microsoft Knowledge Base: http://support.microsoft.com/kb/256986/EN-US/.

  1. Запустите Registry Editor (Regedt32.exe).

  2. Определите местонахождение следующего ключа в реестре:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
    
  3. В меню Edit кликните Add Value, затем добавьте следующее значение:
    Value Name: MaxUserPort
    Data Type: REG_DWORD
    Value: 65534
    
    Это определяет число эфемерных портов, доступных любому пользователю. Допустимый диапазон: 5000-65534 (десятичное число). Значение по умолчанию: 0x1388 (5000, десятичное число).
  4. В меню Edit кликните Add Value, затем добавьте следующее значение:
    Value Name: TcpTimedWaitDelay
    Data Type: REG_DWORD
    Value: 30
    
    Это определяет число секунд, которые надо держать порт TCP в статусе TIME_WAIT перед закрытием. Допустимый диапазон между 30 и 300 (десятичные числа). Значение по умолчанию 0x78 (120 десятично).
  5. Закройте Registry Editor.
  6. Перезагрузите машину.

Отмена вышеупомянутого должна быть столь же проста, как удаление записей реестра, которые Вы создали.

B.5.2.3. Потерянное соединение с сервером MySQL

Есть три вероятных причины для этого сообщения об ошибке.

Обычно это указывает на сетевую проблему связи, и Вы должны проверить работу своей сети, если эта ошибка часто происходит. Если сообщение об ошибке включает during query, это, вероятно, имеет место.

Иногда during query происходит, когда миллионы строк посылают как часть одного или более запросов. Если Вы знаете, что это происходит, Вы должны попытаться увеличить net_read_timeout от значения по умолчанию в 30 секунд до 60 секунд или дольше, достаточного времени для передачи данных.

Также это может произойти, когда клиент делает попытку начального соединения с сервером. В этом случае, если Ваше значение connect_timeout установлено только в несколько секунд, Вы в состоянии решить проблему, увеличивая его до десяти секунд, возможно больше, если у Вас есть очень длинное расстояние или медленное соединение. Вы можете определить, в чем дело при использовании SHOW GLOBAL STATUS LIKE 'Aborted_connects'. Это значение увеличится для каждой начальной попытки соединения, которую прерывает сервер. Вы можете видеть reading authorization packet как часть сообщения об ошибке.

Если причина не одна из только что описанных, Вы можете испытывать проблему со значениями BLOB, которые больше чем max_allowed_packet , который может вызвать эту ошибку с некоторыми клиентами. Иногда Вы можете видеть ошибку ER_NET_PACKET_TOO_LARGE и это подтверждает, что Вы должны увеличить max_allowed_packet.

B.5.2.4. Проблемы с паролем в интерактивном режиме

Клиенты MySQL запрашивают пароль когда вызваны с опцией --password или -p, у которой нет никакого последующего значения пароля:

shell> mysql -u user_name -p
Enter password:
На некоторых системах Вы можете найти, что Ваш пароль работает, когда определен в файле опции или в командной строке, но не когда Вы вводите его в интерактивном режиме в ответ на запрос Enter password:. Это происходит, когда библиотека, предоставленная системой, чтобы считать пароли, ограничивает значения пароля небольшим количеством символов (как правило, восемь). Это проблема с системной библиотекой, не с MySQL. Чтобы обойти проблему, измените свой пароль MySQL на значение, которое является восемью или меньшим количеством символов или впишите Ваш пароль в файл опций.

B.5.2.5. Хост 'host_name' блокирован

Если следующая ошибка происходит, это означает, что mysqld получил много запросов соединения от данного хоста, которые были прерваны в середине:

Host 'host_name' is blocked because of many connection errors.
Unblock with 'mysqladmin flush-hosts'
Значение системной переменной max_connect_errors определяет, сколько последовательных прерванных запросов соединения разрешено. См. раздел 6.1.5. После max_connect_errors неудавшихся запросов без успешного соединения, mysqld предполагает, что что-то неправильно (например, что кто-то пытается вскрыть систему) и блокирует соединения с этого хоста до запроса FLUSH HOSTS или выполнения команды mysqladmin flush-hosts .

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

shell> mysqld_safe --max_connect_errors=10000 &
Значение может также быть установлено во времени выполнения:
mysql> SET GLOBAL max_connect_errors=10000;
Если Вы получаете сообщение об ошибке Host 'host_name ' is blocked для данного хоста, Вы должны сначала проверить, что нет ничего неправильного с соединениями TCP/IP от него. Если у Вас есть сетевые проблемы, не стоит увеличивать max_connect_errors .

B.5.2.6. Too many connections

Если Вы получаете ошибку Too many connections, когда Вы пытаетесь соединиться с mysqld , это означает, что все доступные соединения используются другими клиентами.

Числом разрешенных соединений управляет системная переменная max_connections. Значение по умолчанию 151, чтобы улучшить работу, когда MySQL используется с веб-сервером Apache. Ранее значение по умолчанию было 100. Если Вы должны поддержать больше соединений, Вы должны установить большее значение для этой переменной.

mysqld фактически разрешает max_connections+1 клиентских соединений. Дополнительное соединение сохранено для использования учетными записями, которые имеют привилегию SUPER. Предоставляя привилегию SUPER администраторам, а не нормальным пользователям (кто не должен нуждаться в этом), администратор может соединиться с сервером и использовать SHOW PROCESSLIST, чтобы диагностировать проблемы, даже если максимальное количество непривилегированных клиентов соединено. См. раздел 14.7.5.29.

Максимальное количество соединений зависит от качества библиотеки потоков на данной платформе, количества доступной RAM, сколько RAM используется для каждого соединения, рабочей нагрузки каждого соединения и желаемого времени отклика. Linux или Solaris должны быть в состоянии поддержать по крайней мере 500-1000 одновременных соединений обычно и целых 10000 соединений, если Вы имеете много гигабайтов RAM в наличии, а рабочая нагрузка каждого низка или некритично время отклика. Windows ограничена (открытые таблицы*2+открытые соединения) < 2048 из-за уровня совместимости Posix, используемого на этой платформе.

Увеличение open-files-limit может быть необходимым. Также см. раздел 2.5 для того, как поднять ограничение операционной системы на то, сколько дескрипторов может использоваться MySQL.

B.5.2.7. Out of memory

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

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory
Чтобы исправить проблему, сначала проверьте, правилен ли Ваш запрос. Действительно ли разумно, что это должно возвратить очень много строк? В противном случае исправьте запрос и попробуйте еще раз. Иначе, Вы можете вызвать mysql с опцией --quick. Это заставляет использовать функцию C API mysql_use_result(), чтобы получить набор результатов, которая меньше нагружает клиента (но больше сервер).

B.5.2.8. MySQL server has gone away

Этот раздел также покрывает связанную ошибку Lost connection to server during query.

Наиболее распространенная причина ошибки MySQL server has gone away состоит в том, что сервер закрыл соединение по тайм-ауту. В этом случае Вы обычно получаете один из следующих кодов ошибки.

Код ошибкиОписание
CR_SERVER_GONE_ERROR Клиент не мог послать запрос на сервер.
CR_SERVER_LOST Клиент не получал ошибку при обращении к серверу, но не получил полный ответ (или любой ответ).

По умолчанию, сервер закрывает соединение после восьми часов, если ничто не произошло. Вы можете изменить ограничение по времени, устанавливая переменную wait_timeout , когда Вы запускаете mysqld . См. раздел 6.1.5.

Если у Вас есть скрипт, Вы только должны запустить запрос снова для клиента, чтобы сделать автоматическое пересоединение. Это предполагает, что у Вас есть автоматическое пересоединение во включенном режиме на клиенте (что является значением по умолчанию для mysql.

Некоторые другие общие причины MySQL server has gone away:

Вы можете проверить, упал ли сервер MySQL и перезапустить его, выполняя mysqladmin version и исследуя продолжительность работы сервера. Если бы соединение клиента было сломано, потому что mysqld перезапускался, то Вы должны сконцентрироваться на обнаружении причины катастрофического отказа.

Вы можете получить больше информации о потерянных соединениях, запуская mysqld с системной переменной log_error_verbosity равной 3. Это регистрирует некоторые из сообщений разъединения в файл hostname.err. См. раздел 6.4.2.

Если Вы хотите создать отчет об ошибке относительно этой проблемы, убедитесь, что Вы включаете следующую информацию:

См. также разделы B.5.2.10 и 1.7.

B.5.2.9. Packet Too Large

Коммуникационный пакет единственный запрос SQL, посланный серверу MySQL, единственная строка, которую посылают клиенту, или событие двоичного журнала, посланное с основного сервера репликации ведомому устройству.

Самым большим пакетом, который может быть передан к или из MySQL 8.0 серверов или клиент, является 1GB.

Когда клиент MySQL или сервер mysqld получают пакет, больше чем max_allowed_packet байт, это порождает ошибку ER_NET_PACKET_TOO_LARGE и завершает соединение. С некоторыми клиентами Вы можете также получить ошибку Lost connection to MySQL server during query, если коммуникационный пакет является слишком большим.

У клиента и сервера есть их собственные переменные max_allowed_packet так что, если Вы хотите обработать большие пакеты, Вы должны увеличить эту переменную в клиенте и в сервере.

Если Вы используете клиента mysql, значение по умолчанию max_allowed_packet равно 16 MB. Чтобы установить большее значение, запустите mysql так:

shell> mysql --max_allowed_packet=32M
Это устанавливает пакетный размер в 32 МБ.

Значение по умолчанию серверной копии max_allowed_packet равно 4 MB. Вы можете увеличить это, если сервер должен обработать большие запросы (например, если Вы работаете с большими столбцами BLOB). Например, чтобы установить переменную в 16 МБ, запустите сервер так:

shell> mysqld --max_allowed_packet=16M
Вы можете также использовать файл опции, чтобы установить max_allowed_packet . Например, чтобы установить размер для сервера в 16 МБ, добавьте следующие строки в файле опций:
[mysqld]
max_allowed_packet=16M
Безопасно увеличить значение этой переменной, потому что дополнительная память выделена только при необходимости. Например, mysqld выделяет больше памяти только, когда Вы запускаете длинный запрос или когда mysqld должен возвратить большую строку результата. Маленькое значение по умолчанию переменной предосторожность, чтобы поймать неправильные пакеты между клиентом и сервером, а также гарантировать, что Вы не исчерпываете память при использовании больших пакетов случайно.

Вы можете также получить странные проблемы с большими пакетами, если Вы используете большие значения BLOB, но не предоставили mysqld доступ к достаточной памяти, чтобы обработать запрос. Если Вы подозреваете, что дело обстоит именно так, попытайтесь добавить ulimit -d 256000 в начале скрипта mysqld_safe и перезапустите mysqld .

B.5.2.10. Коммуникационные ошибки и прерванные соединения

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

Если Вы запускаете сервер с системной переменной log_error_verbosity равной 3, Вы могли бы найти подобные этому сообщения в Вашем журнале ошибок:

[Note] Aborted connection 854 to db: 'employees' user: 'josh'
Если клиент неспособен даже соединиться, сервер постепенно увеличивает значение Aborted_connects . Неудачные попытки соединения могут произойти по следующим причинам:

Если эти проблемы происходят, это может указывать, что кто-то пытается ворваться в Ваш сервер! Если общий журнал запроса включен, сообщения для этих типов проблем зарегистрированы в нем.

Если клиент успешно соединяется, но позже разъединяется ненадлежащим образом, сервер постепенно увеличивает Aborted_clients и пишет в журнал ошибок сообщение Aborted connection. Причина может быть следующей:

Другие причины проблем с прерванными соединениями или клиентами:

См. также раздел B.5.2.8.

B.5.2.11. The table is full

Если происходит ошибка table-full, может случиться так, что диск полон или что таблица достигла своего максимального размера. Эффективный максимальный табличный размер для баз данных MySQL обычно определяется ограничениями операционной системы на размеры файла, а не внутренними пределами MySQL. См. раздел C.10.3.

B.5.2.12. Can't create/write to file

Если Вы получаете ошибку следующего типа для некоторых запросов, это означает, что MySQL не может создать временный файл для набора результатов во временном каталоге:

Can't create/write to file '\\sqla3fe_0.ism'.
Предыдущая ошибка типичное сообщение для Windows, сообщение в Unix подобно.

Можно запустить mysqld с опцией --tmpdir или добавить опцию к секции [mysqld] Вашего файла опции. Например, чтобы определить каталог C:\temp, используйте эти строки:

[mysqld]
tmpdir=C:/temp
Каталог C:\temp должен существовать и иметь достаточное пространство для сервера MySQL. См. раздел 5.2.6.

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

Проверьте также код ошибки, который Вы получаете с perror. Одна из причина, по которой сервер не может записать таблицу, состоит в том, что файловая система полна:

shell> perror 28
OS error code28: No space left on device
Если Вы получаете ошибку следующего типа во время запуска, она указывает, что файловая система или каталог, используемый для того, чтобы сохранить файлы с данными, являются защищенными от записи. При условии, что ошибка при записи к испытательному файлу, ошибка не серьезна и может быть безопасно проигнорирована.
Can't create test file /usr/local/mysql/data/master.lower-test

B.5.2.13. Commands out of sync

Если Вы получаете ошибку Commands out of sync; you can't run this command now в Вашем коде клиента Вы вызываете функции клиента в неправильном порядке.

Это может произойти, например, если Вы используете mysql_use_result() и пробуете выполнить новый запрос прежде, чем Вы вызвали mysql_free_result(). Это может также произойти, если Вы пытаетесь выполнить два запроса, которые возвращают данные без запроса mysql_use_result() или mysql_store_result() между ними.

B.5.2.14. Игнорирование пользователя

Если Вы получаете следующую ошибку, это означает, что, когда mysqld был запущен или когда он перезагружал таблицы привилегий, нашел учетную запись в таблице user, у которой был неверный пароль.

Found wrong password for user 'some_user'@'some_host'; ignoring user

В результате учетная запись просто проигнорирована системой. Чтобы решить эту проблему, назначьте новый, допустимый, пароль на учетную запись.

B.5.2.15. Table 'tbl_name' doesn't exist

Если Вы получаете любую из следующих ошибок, это обычно означает, что никакой таблицы не существует в базе данных по умолчанию:

Table 'tbl_name' doesn't exist
Can't find file: 'tbl_name' (errno: 2)
В некоторых случаях может случиться так, что таблица действительно существует, но Вы обращаетесь к ней неправильно:

Вы можете проверить, какие таблицы находятся в базе данных по умолчанию через SHOW TABLES. См. раздел 14.7.5.

B.5.2.16. Can't initialize character set

Вы могли бы видеть такую ошибку, если у Вас есть проблемы с набором символов:

MySQL Connection Failed: Can't initialize character set charset_name
У этой ошибки может быть любая из следующих причин:

B.5.2.17. File Not Found и подобные ошибки

Если Вы получили ERROR 'file_name' not found (errno: 23), Can't open file: file_name (errno: 24) или любую другую ошибку с errno 23 или errno 24 от MySQL, это означает, что Вы не выделили достаточно дескрипторов файла для сервера MySQL. Вы можете использовать perror, чтобы получить описание того, что означает код ошибки:

shell> perror 23
OS error code23:File table overflow
shell> perror 24
OS error code24:Too many open files
shell> perror 11
OS error code11:Resource temporarily unavailable
Проблема здесь состоит в том, что mysqld пытается сохранить открытым слишком много файлов одновременно. Вы можете или сказать mysqld не открывать очень много файлов сразу или увеличить число дескрипторов файла, доступных mysqld .

Чтобы сказать mysqld сохранять открытыми меньше файлов за один раз, Вы можете сделать табличный кэш меньше, уменьшая значение системной переменной table_open_cache (значение по умолчанию 64). Это, возможно, не полностью предотвращает исчерпание дескрипторов файла, потому что при некоторых обстоятельствах сервер может попытаться расширить размер кэша временно, как описано в разделе 9.4.3.1. Сокращение значения max_connections также сокращает количество открытых файлов (значение по умолчанию 100).

Чтобы изменить число дескрипторов файла, доступных mysqld, Вы можете использовать опцию --open-files-limit в mysqld_safe или установить системную переменную open_files_limit . См. раздел 6.1.5. Самый легкий способ установить эти значения состоит в том, чтобы добавить опцию к Вашему файлу опций. См. раздел 5.2.6. Если у Вас есть старая версия mysqld, которая не поддерживает установку предела открытых файлов, Вы можете отредактировать скрипт mysqld_safe . Есть в нем закомментированная строка ulimit -n 256 . Вы можете удалить символ #, чтобы раскомментировать эту строку, и изменить число 256, чтобы определить количество дескрипторов файла, которые будут доступны для mysqld.

--open-files-limit и ulimit могут увеличить число дескрипторов файла, но только до предела, наложенного операционной системой. Есть также жесткий предел, который может быть переопределен, только если Вы запускаете mysqld_safe или mysqld как root (только помните, что Вы также должны запустить сервер с опцией --user в этом случае так, чтобы он не продолжил работать как root после того, как стартует). Если Вы должны увеличить предел дескрипторов операционной системы на число описателей файла, доступных каждому процессу, консультируйтесь с документацией для своей системы.

Если Вы выполняете оболочку tcsh, ulimit не работает! tcsh также сообщает неправильные значения, когда Вы просите текущие пределы. В этом случае Вы должны запустить mysqld_safe , используя sh.

B.5.2.18. Проблемы табличного повреждения

Если Вы запустили mysqld с --myisam-recover-options, MySQL автоматически проверяет и пытается восстановить таблицы MyISAM, если они отмечены как 'не закрыта должным образом' или 'отказ'. Если это происходит, MySQL пишет запись в файл hostname.err: 'Warning: Checking table ...' , которая сопровождается Warning: Repairing table, если таблица должна быть восстановлена. Если Вы получаете много этих ошибок, без mysqld упавшего неожиданно как раз перед этим, то что-то тут не так и должно быть исследовано далее.

Когда сервер обнаруживает табличное повреждение MyISAM, он пишет дополнительную информацию в журнал ошибок, такую как имя и номер строки исходного файла и список потоков, получающих доступ к таблице. Пример: Got an error from thread_id=1, mi_dynrec.c:368. Это полезная информация для включения в отчеты об ошибках.

См. также разделы 6.1.4 и 26.5.1.7.

B.5.3. Проблемы администрирования

B.5.3.1. Проблемы с правами доступа

Если у Вас есть проблемы с правами доступа, переменная окружения UMASK или UMASK_DIR может быть установлена неправильно, когда mysqld стартует. Например, MySQL мог бы выдать следующее сообщение об ошибке, когда Вы составляете таблицу:

ERROR: Can't find file: 'path/with/file_name' (Errcode: 13)
Значения по умолчанию UMASK и UMASK_DIR 0640 и 0750, соответственно. MySQL предполагает, что значение для UMASK или UMASK_DIR восьмеричное, если начинается с 0. Например, установка UMASK=0600 эквивалентна UMASK=384 поскольку восьмеричное 0600 это десятичное 384.

Чтобы изменить значение по умолчанию UMASK, запустите mysqld_safe :

shell> UMASK=384# = 600 in octal
shell> export UMASK
shell> mysqld_safe &

По умолчанию, MySQL создает каталоги базы данных со значением разрешения на доступ 0750. Чтобы изменить это поведение, установите переменную UMASK_DIR. Если Вы устанавливаете это значение, новые каталоги создаются с объединенным значением UMASK и UMASK_DIR. Например, чтобы дать группе доступ ко всем новым каталогам, запустите mysqld_safe так:

shell> UMASK_DIR=504# = 770 in octal
shell> export UMASK_DIR
shell> mysqld_safe &

B.5.3.2. Как сбросить пароль root

Если Вы никогда не назначали root-пароль для MySQL, сервер не требует пароля вообще для того, чтобы соединиться как root. Однако, это небезопасно. Для инструкций по назначению пароля, см. раздел 2.9.4.

Если Вы знаете root-пароль и хотите изменить его, см. разделы 14.7.1.1 и 14.7.1.11.

Если Вы назначали root-пароль ранее, но забыли его, Вы можете назначить новый пароль. Следующие разделы обеспечивают инструкции для Windows и Unix-подобных систем.

B.5.3.2.1. Сброс Root-пароля: Windows

В Windows используйте следующую процедуру, чтобы сбросить пароль для пользователя MySQL 'root'@'localhost'.

  1. Войдите в систему как Администратор.

  2. Остановите сервер MySQL, если он работает. Для сервера, который работает как служба Windows, перейдите к Services manager: из меню Start выберите Control Panel, Administrative Tools и Services. Найдите службу MySQL в списке и остановите.

    Если Ваш сервер не работает как служба, Вы, возможно, должны использовать Диспетчер задач, чтобы вынудить его остановиться.

  3. Создайте текстовый файл, содержащий оператор присваивания пароля на одной строке. Укажите пароль, который Вы хотите использовать.
    ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
    
  4. Сохраните файл. Этот пример предполагает, что Вы называете файл C:\mysql-init.txt.
  5. Откройте консоль, чтобы добраться до командной строки.
  6. Запустите сервер MySQL со специальной опцией --init-file (обратите внимание, что наклонная черта влево в значении опции удвоена):
    C:\> cd "C:\Program Files\MySQL\MySQL Server 8.0\bin"
    C:\> mysqld --init-file=C:\\mysql-init.txt
    
    Если Вы устанавливали MySQL в другое место, скорректируйте команду cd.

    Сервер выполняет содержание файла, названного в опции the --init-file при запуске, изменяя пароль учетной записи 'root'@'localhost'.

    Чтобы вывести ответ сервер в консоль, а не в файл системного журнала, добавьте опцию --console к команде mysqld .

    Если Вы устанавливали MySQL, используя мастер установки MySQL, Вы, возможно, должны определить опцию --defaults-file. Например:

    C:\> mysqld
     --defaults-file="C:\\ProgramData\\MySQL\\MySQL Server 8.0\\my.ini"
     --init-file=C:\\mysql-init.txt
    
    Соответствующяя установка --defaults-file установка может быть найдена, используя Services Manager: из меню Start выберите Control Panel , Administrative Tools, Services. Найдите службу MySQL в списке, щелкните правой кнопкой мыши по строке и выберите Properties. Поле Path to executable содержит установку --defaults-file.
  7. После того, как сервер запустился успешно, удалите C:\mysql-init.txt.

Вы должны теперь быть в состоянии соединиться с сервером MySQL как root с новым паролем. Запустите сервер как обычно. Если Вы выполняете сервер как службу, запустите его из окна Windows Services.

B.5.3.2.2. Сброс Root-пароля в Unix

В Unix используйте следующую процедуру, чтобы сбросить пароль для пользователя MySQL 'root'@'localhost'.

Инструкции предполагают, что Вы запустите сервер MySQL с учетной записи Unix, которую Вы обычно используете для того, чтобы выполнить его. Например, если Вы выполняете сервер, используя учетку mysql, Вы должны войти в систему как mysql перед использованием инструкций. Альтернативно, Вы можете войти в систему как root, но в этом случае Вы должны запустить mysqld с опцией --user=mysql. Если Вы запускаете сервер как root без использования --user=mysql, сервер может создать принадлежащие root файлы в каталоге данных, такие как файлы системного журнала, и они могут вызвать связанные с доступом проблемы для будущих запусков сервера. Если это произойдет, то Вы будете должны исправить права доступа вручную.

  1. Войдите в систему как пользователь Unix, от имени которого сервер MySQL выполняется (например, mysql).

  2. Остановите сервер MySQL, если он работает. Определите местонахождение файла .pid, который содержит идентификатор процесса сервера. Точное местоположение и название этого файла зависят от Вашего дистрибутива, имени хоста, и конфигурации. Общие местоположения /var/lib/mysql/, /var/run/mysqld/ и /usr/local/mysql/data/. Вообще, у имени файла есть расширение .pid и начинается имя с mysqld или с имени хоста Вашей системы.

    Остановите сервер MySQL, посылая нормальный kill (не kill -9) процессу mysqld. Используйте фактический путь к .pid в следующей команде:

    shell> kill `cat /mysql-data-directory/host_name.pid`
    
    Используйте обратные кавычки с командой cat. Они вызывают вывод cat в команду kill.
  3. Создайте текстовый файл, содержащий оператор присваивания пароля на одной строке. Примерно так:
    ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
    
  4. Сохраните файл. Этот пример предполагает, что Вы называете файл /home/me/mysql-init. Файл содержит пароль, так что не сохраняйте его там, где он может быть считан другими пользователями. Если Вы не зарегистрированы как mysql (пользователь выполнения сервера), удостоверьтесь, что у файла есть права доступа для пользователя mysql на чтение.
  5. Запустите сервер MySQL со специальной опцией --init-file:
    shell> mysqld_safe --init-file=/home/me/mysql-init &
    
    Сервер выполняет содержание файла, названного в опции the --init-file при запуске, изменяя пароль для 'root'@'localhost'.
  6. После того, как сервер запустился успешно, удалите /home/me/mysql-init.

B.5.3.2.3. Сброс Root-пароля: общие инструкции

Предыдущие разделы обеспечивают инструкции определенно для Windows и Unix-систем. Альтернативно, на любой платформе, Вы можете сбросить пароль, используя mysql (но этот подход менее безопасен):

  1. Остановите сервер MySQL в случае необходимости, затем перезапустите его с опцией --skip-grant-tables. Это позволяет любому соединиться без пароля и со всеми привилегиями, и отключает команды управления учетными записями, такие как ALTER USER и SET PASSWORD. Поскольку это небезопасно, стоит использовать --skip-grant-tables в соединении с --skip-networking дабы воспрепятствовать тому, чтобы удаленные клиенты соединились.

  2. Соединитесь с сервером MySQL, используя клиент mysql, никакой пароль не нужен, потому что сервер был запущен с опцией --skip-grant-tables:
    shell> mysql
    
  3. В клиенте mysql скажите серверу перезагрузтть таблицы привилегий так, чтобы запросы управления учетными записями работали:
    mysql> FLUSH PRIVILEGES;
    
    Теперь смените пароль учетной записи 'root'@'localhost'. Замените его паролем, который Вы хотите использовать.
    mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
    

Теперь остановите сервер и запустите его нормально (без опций --skip-grant-tables и --skip-networking ).

B.5.3.3. Что делать, если MySQL падает

Каждая версия MySQL проверена на многих платформах прежде, чем она будет выпущена. Это не означает, что нет никаких ошибок в MySQL, но если есть ошибки, их должно быть очень мало.

Сначала Вы должны попытаться узнать, является ли проблема падений mysqld проблемой на сервере или на клиенте. Вы можете проверить, сколько времени Ваш сервер mysqld работал, выполняя запрос mysqladmin version. Если mysqld перезапустился, Вы можете найти причину в журнале ошибок сервера. См. раздел 6.4.2.

На некоторых системах Вы можете найти в журнале ошибок след стека при падении mysqld , который Вы можете обработать программой resolve_stack_dump . См. раздел 26.5. Отметьте, что значения переменных, написанные в журнале ошибок, возможно, не всегда на 100% правильны.

Много катастрофических отказов сервера вызваны поврежденными файлами с данными или индексными файлами. MySQL обновляет файлы на диске с помощью системного вызова write() после каждого запроса SQL и перед отчетом клиенту о результате. Это не так, если Вы работаете с опцией --delay-key-write, тогда записаны файлы с данными, но не индексные файлы. Это означает, что содержание файла с данными безопасно, даже если mysqld упадет, потому что операционная система гарантирует, что данные будут записаны на диск. Вы можете вынудить MySQL сбросить все на диск после каждого запроса SQL, запуская его с параметром --flush.

Предыдущие средства обеспечивают то, что обычно Вы не должны получить поврежденные таблицы, если одно из следующего не происходит:

Поскольку очень трудно знать, почему что-то отказывает, сначала попытайтесь проверить вещи, которые работают на катастрофический отказ для Вас. Попробуйте следующие вещи:

B.5.3.4. Как MySQL обрабатывает переполнение диска

Этот раздел описывает, как MySQL отвечает на ошибки переполнения диска (такие, как no space left on device) и ошибки исчерпания квоты (такие, как write failed или user block limit reached).

Этот раздел важен для записи в таблицы MyISAM. Это также применими к записи файлов двоичного журнала, за исключением того, что ссылки на строки и записи здесь означают события.

Когда происходит переполнение диска, MySQL делает следующее:

Чтобы облегчить проблему, предпримите следующие меры:

Исключения к предыдущему поведению: когда Вы используете REPAIR TABLE или OPTIMIZE TABLE или же когда индекс создается в пакете после LOAD DATA INFILE или после запроса ALTER TABLE. Все эти запросы могут создать большие временные файлы, которые вызывают большие проблемы для остальной части системы. Если диск становится полным, в то время как MySQL делает любую из этих операций, это удаляет большие временные файлы и отмечает таблицу как разрушенную. Исключение из этого: ALTER TABLE, старая таблица не меняется вообще.

B.5.3.5. Где MySQL хранит временные файлы

В Unix MySQL использует значение переменной окружения TMPDIR как путь к каталогу, в котором можно хранить временные файлы. Если TMPDIR не задана, MySQL использует системное значение по умолчанию, которое обычно является /tmp, /var/tmp или /usr/tmp.

В Windows MySQL проверяет в порядке значения переменные окружения TMPDIR, TEMP и TMP. Найдя первую, которая установлена, MySQL использует ее и не проверяет те, которые остаются. Если ни одна из TMPDIR, TEMP или TMP не установлены, MySQL использует системное значение по умолчанию Windows, которое обычно является C:\windows\temp\.

Если файловая система, содержащая Ваш временный каталог, является слишком маленькой, Вы можете использовать mysqld с опцией --tmpdir, чтобы определить каталог в файловой системе, где у Вас есть достаточно пространства. На ведомых устройствах репликации Вы можете использовать --slave-load-tmpdir, чтобы определить отдельный каталог для хранения временных файлов для обработки запросов LOAD DATA INFILE.

Опция --tmpdir может быть установлена в список из нескольких путей, которые используются круговым способом. Пути должны быть отделены символами двоеточия (:) в Unix и символом точки с запятой (;) в Windows.

Чтобы распределить нагрузку эффективно, эти пути должны быть расположены на различных физических дисках, а не на разных разделах того же самого диска.

Если сервер MySQL действует как ведомое устройство репликации, Вы должны убедиться, что установили --slave-load-tmpdir не на каталог, который находится в основанной на памяти файловой системе или каталог, который очищен, когда хост сервера перезапускается. Ведомое устройство нуждается в некоторых из своих временных файлов, чтобы пережить машинный перезапуск так, чтобы оно могло копировать временные таблицы или операции LOAD DATA INFILE. Если файлы в ведомом временном каталоге потеряны, когда сервер перезапускается, репликация терпит неудачу.

MySQL обеспечивает то, что временные файлы удалены, если mysqld прерван. На платформах, которые поддерживают это (такие, как Unix), это сделано, отвязывая файл после открытия. Недостаток в том, что имя не появляется в списках каталога, и Вы не видите большой временный файл, который заполняет файловую систему, в которой расположен временный каталог. В таких случаях lsof +L1 может быть полезным в идентификации больших файлов, связанных с mysqld.

Сортируя (ORDER BY или GROUP BY) MySQL обычно использует один или два временных файла. Максимальное требуемое дисковое пространство определено следующим выражением:

(длина того, что сортируется + sizeof(Размер указателя строки)) *
 число соответствующих строк * 2
Размер указателя строки обычно четыре байта, но может вырасти в будущем для действительно больших таблиц.

Для некоторых SELECT запросов MySQL также составляет временные таблицы SQL. Они не скрыты и имеют названия формы SQL_*.

В большинстве случаев ALTER TABLE создает временную копию оригинальной таблицы в том же самом каталоге, где оригинальная таблица.

Где InnoDB хранит временные файлы

Временные таблицы InnoDB сохранены во временном файле табличного пространства ibtmp1, который расположен в каталоге MySQL data (по умолчанию datadir). Опция innodb_temp_data_file_path может использоваться при запуске, чтобы определить иное имя файла и местоположение.

Если работа ALTER TABLE на таблице InnoDB использует метод ALGORITHM=COPY, InnoDB создает временную копию таблицы в том же самом каталоге, где оригинальная таблица. Временные табличные имена файла начинаются с префикса #sql- и появляется кратко только во время выполнения ALTER TABLE.

Если работа ALTER TABLE восстанавливает таблицц InnoDB, используя метод ALGORITHM=INPLACE (online DDL), InnoDB создает промежуточную копию таблицы в том же самом каталоге, где и оригинальная таблица. Промежуточные табличные имена файла начинаются с префикса #sql-ib.

ALTER TABLE, которые восстанавливают таблицы InnoDB, используя метод ALGORITHM=INPLACE (online DDL) также создают временные файлы сортировки во временном каталоге MySQL ($TMPDIR в Unix, %TEMP% в Windows, или каталоге, определенном опцией --tmpdir). Если временный каталог не является достаточно большим, чтобы содержать такие файлы, Вы, возможно, должны реконфигурировать tmpdir. Альтернативно, Вы можете определить отдельный временный каталог для InnoDB операций ALTER TABLE, используя опцию innodb_tmpdir. Эта опция была введена, чтобы помочь избежать временных переполнений каталога, которые могли произойти в результате больших временных файлов, создаваемых во время ALTER TABLE. innodb_tmpdir может быть сконфигурирована динамически, используя команды SET GLOBAL или SET SESSION.

Опция innodb_tmpdir неприменима к промежуточным табличным файлам, которые всегда создаются в том же самом каталоге, где оригинальная таблица.

В окружающей среде репликации стоит копировать только настройку innodb_tmpdir, если у всех серверов есть та же самая окружающая среда операционной системы. Иначе, мультиплицирование innodb_tmpdir может привести к отказу операций ALTER TABLE. Если операционные среды серверов отличаются, рекомендуется сконфигурировать innodb_tmpdir на каждом сервере индивидуально.

B.5.3.6. Как защитить или изменить файл сокета Unix MySQL

Местоположение по умолчанию для файла сокета Unix, который использует сервера для коммуникации с местными клиентами /tmp/mysql.sock. Для некоторых форматов дистрибутивов каталог может отличаться, например, /var/lib/mysql для RPM.

На некоторых версиях Unix любой может удалить файлы в каталоге /tmp или другом подобном каталоге, который используется для временных файлов. Если файл сокета расположен в таком каталоге в Вашей системе, это могло бы вызвать проблемы.

На большинстве версий Unix Вы можете защитить Ваш каталог /tmp так, чтобы файлы могли быть удалены только их владельцами или суперпользователем (root). Чтобы сделать это, установите бит sticky каталогу /tmp, войдя в систему как root и применив такую команду:

shell> chmod +t /tmp
Вы можете проверить установлен ли бит sticky, выполняя команду ls -ld /tmp. Если последний символ прав доступа t, значит бит установлен.

Другой подход должен изменить место, где сервер создает файл. Если Вы делаете это, Вы должны также позволить программам клиента узнать новое местоположение файла. Вы можете определить местоположение файла несколькими способами:

Вы можете проверить, работает ли новое местоположение, пытаясь соединиться с сервером этой командой:

shell> mysqladmin --socket=/path/to/socket version

B.5.3.7. Проблемы с зонами времени

Если у Вас есть проблема с SELECT NOW(), возвращающем значения в UTC, а не Вашем местном времени, Вы должны сказать серверу свою зону текущего времени. То же самое применяется, если UNIX_TIMESTAMP() возвращает неправильное значение. Это должно быть сделано для среды, в которой работает сервер, например, в mysqld_safe или mysql.server . См. раздел 5.9.

Вы можете установить часовой пояс для сервера с помощью опции --timezone= timezone_name при вызове mysqld_safe . Вы можете также установить это, устанавливая переменную окружения TZ прежде, чем Вы запустите mysqld.

Допустимые значения для --timezone или TZ зависят от ОС. Консультируйтесь со своей документацией на операционную систему, чтобы видеть, какие значения являются приемлемыми.

B.5.4. Связанные с запросом проблемы

B.5.4.1. Чувствительность к регистру в поиске строки

Для небинарных строк (CHAR, VARCHAR, TEXT) поиски строки используют сопоставление операндов сравнения. Для двоичных строк (BINARY, VARBINARY, BLOB) сравнения используют числовые значения байтов в операндах, это означает, что для буквенных символов сравнения будут чувствительными к регистру.

Сравнение между небинарной и двоичной строками обработано как сравнение двоичных строк.

Простые операции сравнения (>=, >, =, <, <=, сортировка и группировка) основаны на сортировочном значении каждого символа. Символы с тем же самым сортировочным значением обработаны как тот же самый символ. Например, если e и ц╘ имеют то же самое значение сортировки в данном сопоставлении, они сравниваются как равные.

Набор символов и сопоставление по умолчанию latin1 и latin1_swedish_ci, таким образом, небинарные строковые сравнения являются нечувствительными к регистру по умолчанию. Это означает что, если Вы ищете с col_name LIKE 'a%', Вы получаете все значения столбцов, которые начинаются с A или a . Чтобы сделать этот поиск чувствительным к регистру, удостоверьтесь, что у одного из операндов есть чувствительное к регистру или двоичное сопоставление. Например, если Вы сравниваете столбец и строку, которые оба имеют набор символов latin1, Вы можете использовать оператор COLLATE, чтобы заставить любой операнд иметь сопоставление latin1_general_cs или latin1_bin:

col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin
Если Вы хотите, чтобы столбец всегда был обработан чувствительным к регистру способом, объявите его чувствительным к регистру или двоичным. См. раздел 14.1.15.

Чтобы заставить чувствительное к регистру сравнение недвоичных строк быть нечувствительным к регистру, надо использовать COLLATE с именем сопоставления, нечувствительного к регистру. Строки в следующем примере обычно являются чувствительными к регистру, но COLLATE изменяет сравнение, чтобы быть нечувствительным к регистру:

mysql> SET @s1 = 'MySQL' COLLATE latin1_bin,
    -> @s2 = 'mysql' COLLATE latin1_bin;
mysql> SELECT @s1 = @s2;
+-----------+
| @s1 = @s2 |
+-----------+
| 0         |
+-----------+
mysql> SELECT @s1 COLLATE latin1_swedish_ci = @s2;
+-------------------------------------+
| @s1 COLLATE latin1_swedish_ci = @s2 |
+-------------------------------------+
| 1                                   |
+-------------------------------------+
Двоичная строка является чувствительной к регистру в сравнениях. Чтобы сравнить строку как нечувствительную к регистру, преобразуйте ее в небинарную строку и используйте COLLATE, чтобы указать нечувствительное к регистру сопоставление:
mysql> SET @s = BINARY 'MySQL';
mysql> SELECT @s = 'mysql';
+--------------+
| @s = 'mysql' |
+--------------+
| 0            |
+--------------+
mysql> SELECT CONVERT(@s USING latin1) COLLATE latin1_swedish_ci = 'mysql';
+--------------------------------------------------------------+
| CONVERT(@s USING latin1) COLLATE latin1_swedish_ci = 'mysql' |
+--------------------------------------------------------------+
| 1                                                            |
+--------------------------------------------------------------+
Чтобы определить, сравнится ли значение как недвоичная или двоичная строка, используйте функцию COLLATION() . Этот пример показывает, что VERSION() возвращает строку, у которой есть нечувствительное к регистру сопоставление, таким образом, сравнения являются нечувствительными к регистру:
mysql> SELECT COLLATION(VERSION());
+----------------------+
| COLLATION(VERSION()) |
+----------------------+
| utf8_general_ci|
+----------------------+
Для двоичных строк значение сопоставления binary, таким образом, сравнения будут чувствительными к регистру. Один контекст, в котором Вы будете видеть binary, это для сжатия и функций шифрования, которые возвращают двойные строки как правило:
mysql> SELECT COLLATION(ENCRYPT('x')), COLLATION(SHA1('x'));
+-------------------------+----------------------+
| COLLATION(ENCRYPT('x')) | COLLATION(SHA1('x')) |
+-------------------------+----------------------+
| binary                  | binary               |
+-------------------------+----------------------+
Чтобы проверить значение сортировки строки, можно применить функцию WEIGHT_STRING(). См. раздел 13.5.

B.5.4.2. Проблемы со столбцами DATE

Формат значений DATE 'YYYY-MM-DD'. Согласно стандарту SQL, не разрешен никакой другой формат. Вы должны использовать этот формат в выражениях UPDATE и предложениях WHERE оператора SELECT. Например:

SELECT * FROM t1 WHERE date >= '2003-05-05';
Как удобство, MySQL автоматически преобразовывает дату в число, если дата используется в числовом контексте и наоборот. MySQL также разрешает строковый формат при обновлении и в предложении WHERE, который сравнивает дату со столбцами DATE , DATETIME или TIMESTAMP. Этот формат означает, что любой символ пунктуации может использоваться в качестве разделителя между частями. Например, '2004-08-15' эквивалентно '2004#08#15'. MySQL может также преобразовать строку, не содержащую разделителей (например, '20040815'), если это имеет смысл как дата.

Когда Вы сравниваете DATE, TIME, DATETIME или TIMESTAMP с постоянной строкой с помощью операторов <, <=, =, >=, > или BETWEEN, MySQL обычно преобразовывает строку во внутреннее длинное целое для более быстрого сравнения. Однако, это преобразование подвергается следующим исключениям:

Для этих исключений сравнение сделано, преобразовывая объекты в строки и выполняя строковое сравнение.

Для безопасности предположите, что строки сравнены как строки и используют соответствующие строковые функции, если Вы хотите сравнить временное значение со строкой.

Специальная нулевая дата '0000-00-00' может быть сохранена и получена как '0000-00-00'. Когда дата '0000-00-00' используется через Connector/ODBC, она автоматически преобразована в NULL, потому что ODBC не может обработать такую дату.

Поскольку MySQL выполняет только описанные преобразования, следующие запросы работают (считается, что idate столбец типа DATE):

INSERT INTO t1 (idate) VALUES (19970505);
INSERT INTO t1 (idate) VALUES ('19970505');
INSERT INTO t1 (idate) VALUES ('97-05-05');
INSERT INTO t1 (idate) VALUES ('1997.05.05');
INSERT INTO t1 (idate) VALUES ('1997 05 05');
INSERT INTO t1 (idate) VALUES ('0000-00-00');

SELECT idate FROM t1 WHERE idate >= '1997-05-05';
SELECT idate FROM t1 WHERE idate >= 19970505;
SELECT MOD(idate,100) FROM t1 WHERE idate >= 19970505;
SELECT idate FROM t1 WHERE idate >= '19970505';
Однако, следующий запрос не работает:
SELECT idate FROM t1 WHERE STRCMP(idate,'20030505')=0;
STRCMP() строковая функция, таким образом, это преобразовывает idate в строку в формате 'YYYY-MM-DD' и выполняет строковое сравнение. Это не преобразовывает '20030505' в дату '2003-05-05' и выполняет сравнение даты.

Если Вы включаете режим SQL ALLOW_INVALID_DATES , MySQL разрешает Вам хранить даты, которые прошли только ограниченную проверку: MySQL требует только, чтобы день был в диапазоне от 1 до 31, и месяц находится в диапазоне от 1 до 12. Это делает MySQL очень удобным для Веб-приложений, где Вы получаете год, месяц и день в трех различных полях и хотите сохранить точно, что пользователь вставил (без проверки допустимости даты).

MySQL разрешает Вам хранить даты, где день или месяц и день ноль. Это удобно, если Вы хотите сохранить дату рождения в столбец DATE и знаете только часть даты. Чтобы отвергнуть нулевые части месяца или дня в датах, включите режим NO_ZERO_IN_DATE .

MySQL разрешает Вам хранить значение ноля ('0000-00-00'). Это в некоторых случаях более удобно, чем использование значений NULL. Если дата, которая будет сохранена в столбце DATE не может быть преобразована ни в какое разумное значение, MySQL запишет '0000-00-00'. Чтобы запретить '0000-00-00', включите режим NO_ZERO_DATE .

Сделать, чтобы MySQL проверил все даты и принял только легальные даты (если не переопределено IGNORE) можно, задав системной переменной sql_mode значение "NO_ZERO_IN_DATE,NO_ZERO_DATE".

B.5.4.3. Проблемы со значениями NULL

Понятие значения NULL общий источник беспорядка для новичков в SQL, которые часто думают, что NULL та же самая вещь, что и пустая строка ''. Дело обстоит не так. Например, следующие запросы абсолютно отличаются:

mysql> INSERT INTO my_table (phone) VALUES (NULL);
mysql> INSERT INTO my_table (phone) VALUES ('');
Оба запроса вставляют значение в столбец phone, но первый вставляет значение NULL, а второй пустую строку. Значение первого может быть расценено как "номер телефона неизвестен", а второго как "человек, как известно, не имеет никакого телефона, и таким образом никакого телефонного номера". Разница есть?

Для помощи с обработкой NULL Вы можете использовать операторы IS NULL и IS NOT NULL, а также функцию IFNULL().

В SQL значение NULL никогда не истина по сравнению с любым другим значением, даже с NULL. Выражение, которое содержит NULL всегда производит NULL, если иное не обозначено явно в документации для операторов и функций, вовлеченных в выражение. Все столбцы в следующем примере будут NULL:

mysql> SELECT NULL, 1+NULL, CONCAT('Invisible',NULL);
Чтобы искать значения столбцов, которые являются NULL, Вы не можете использовать тест expr = NULL. Следующее выражение не возвращает строк, потому что expr = NULL никогда не истина для любого выражения:
mysql> SELECT * FROM my_table WHERE phone = NULL;
Чтобы найти значения NULL, Вы должны использовать тест IS NULL. Следующие запросы показывают, как найти телефонный номер NULL и пустой номер телефона:
mysql> SELECT * FROM my_table WHERE phone IS NULL;
mysql> SELECT * FROM my_table WHERE phone = '';

Вы можете добавить индекс на столбце, который может иметь значения NULL, если Вы используете механизм хранения MyISAM, InnoDB или MEMORY. Иначе Вы должны объявить индексированный столбец NOT NULL и Вы не можете вставить в него NULL.

При чтении данных с помощью LOAD DATA INFILE пустые или недостающие столбцы обновлены с значением ''. Чтобы загрузить значение NULL в столбец, используйте в файле данных \N. Буквальное слово NULL также может использоваться при некоторых обстоятельствах. См. раздел 14.2.6.

Используя DISTINCT, GROUP BY или ORDER BY, все значения NULL расценены как равные.

Используя ORDER BY, значения NULL представлены сначала, или последними, если Вы определяете DESC.

Агрегатные функции (COUNT() , MIN() и SUM()) значения NULL игнорируют. Исключение: COUNT(*), которая считает строки, а не отдельные значения столбцов. Например, следующий запрос производит два результата. Первым является количество строк в таблице, вторым является количество значений не-NULL в столбце age:

mysql> SELECT COUNT(*), COUNT(age) FROM person;

Для некоторых типов данных, дескрипторов MySQL, значения NULL особенны. Если Вы вставляете NULL в столбец TIMESTAMP, реально вставятся текущие дата и время. Если Вы вставляете NULL в столбец целого числа или с плавающей запятой, который имеет атрибут AUTO_INCREMENT , следующее число в последовательности будет вставлено.

B.5.4.4. Проблемы с псевдонимами столбцов

Псевдоним может использоваться в запросе, чтобы дать столбцу другое имя. Вы можете использовать псевдоним в GROUP BY, ORDER BY или HAVING, чтобы обратиться к столбцу:

SELECT SQRT(a*b) AS root FROM tbl_name
       GROUP BY root HAVING root > 0;
SELECT id, COUNT(*) AS cnt FROM tbl_name
       GROUP BY id HAVING cnt > 0;
SELECT id AS 'Customer identity' FROM tbl_name;
Стандартный SQL отвергает ссылки на псевдонимы столбца в предложении WHERE. Это ограничение введено потому, что когда WHERE оценивается, значение столбца еще не могло быть определено. Например, следующий запрос незаконен:
SELECT id, COUNT(*) AS cnt FROM tbl_name
       WHERE cnt > 0 GROUP BY id;
Предложение WHERE определяет, какие строки должны быть включены в предложение GROUP BY, но это обращается к псевдониму значения столбца, которое неизвестно, пока строки не будут выбраны и сгруппированы с помощью GROUP BY.

В списке выбора запроса заключенный в кавычки псевдоним столбца может быть определен, используя идентификатор или строковые символы заключения в кавычки:

SELECT 1 AS `one`, 2 AS 'two';
В другом месте в запросе заключенные в кавычки ссылки на псевдоним должны использовать заключение в кавычки идентификатора, или ссылка будет обработана как буквальная строка. Например, этот запрос группирует значения в столбце id, на который ссылаются, псевдонимом `a`:
SELECT id AS 'a', COUNT(*) AS cnt FROM tbl_name
       GROUP BY `a`;
Но этот запрос группирует буквальной строкой 'a' и не будет работать как ожидалось:
SELECT id AS 'a', COUNT(*) AS cnt FROM tbl_name
       GROUP BY 'a';

B.5.4.5. Проблема с отменой для нетранзакционных таблиц

Если Вы получаете следующее сообщение, пытаясь выполнить ROLLBACK, это означает, что одна или больше таблиц, которые Вы использовали, не поддерживают транзакции:

Warning: Some non-transactional changed tables couldn't be rolled back
Эти таблицы не затронуты командой ROLLBACK .

Если Вы сознательно не смешивали транзакционные и нетранзакционные таблицы в пределах транзакции, наиболее вероятная причина для этого сообщения состоит в том, что таблица, которая, как Вы думали, была транзакционной, таковой на деле не оказалась. Это может произойти, если Вы пытаетесь составить таблицу, используя транзакционный механизм хранения, который не поддержан Вашим сервером mysqld (или это было отключено с опцией запуска). Если mysqld не поддерживает механизм хранения, он вместо этого составляет таблицу как MyISAM, которая является нетранзакционной.

Вы можете проверить механизм хранения таблицы при использовании любого из этих запросов:

SHOW TABLE STATUS LIKE 'tbl_name';
SHOW CREATE TABLE tbl_name;
См. разделы 14.7.5.36 и 14.7.5.10.

Чтобы проверить, какие механизмы хранения Ваш mysqld поддерживает, используйте этот запрос:

SHOW ENGINES;
См. раздел 14.7.5.16.

B.5.4.6. Удаление строк из связанных таблиц

Если полная длина запроса DELETE для related_table превышает 1MB (значение по умолчанию системной переменной max_allowed_packet), Вы должны разделить это на меньшие части и выполнить много запросов DELETE. Вы, вероятно, получаете самый быстрый DELETE определяя только от 100 до 1000 значений related_column в запросе, если related_column индексирован. Если related_column не индексирован, скорость независима от числа параметров в IN.

B.5.4.7. Решение проблем с несоответствием строк

Если у Вас есть сложный запрос, который использует много таблиц, но не возвращает строк, Вы должны использовать следующую процедуру, чтобы узнать, что не так:

  1. Проверьте запрос с EXPLAIN, чтобы выяснить, можете ли Вы найти что-то очевидно неправильное. См. раздел 14.8.2.

  2. Выберите только те столбцы, которые используются в предложении WHERE.
  3. Удалите по одной таблице за раз из запроса, пока он не возвратит некоторые строки. Если таблицы являются большими, хорошая идея использовать LIMIT 10 с этим запросом.
  4. Выполните SELECT для столбца, который должен был соответствовать строке таблицы, которая была последней удалена из запроса.
  5. Если Вы сравниваете столбцы FLOAT или DOUBLE с десятичными числами, Вы не можете использовать равенство (=). Эта проблема распространена в большинстве машинных языков, потому что не все значения с плавающей запятой могут быть сохранены точно. В некоторых случаях изменение FLOAT на DOUBLE поправит дело. См. раздел B.5.4.8.
  6. Если Вы все еще не можете выяснить что не так, попробуйте создать минимальный тест, который может быть выполнен с mysql test < query.sql, это показывает Ваши проблемы. Вы можете создать испытательный файл, выводя таблицы с mysqldump --quick db_name tbl_name_1 ... tbl_name_n > query.sql. Откройте файл в редакторе, удалите некоторые строки (если там более, чем необходимо, чтобы продемонстрировать проблему), и добавьте Ваш запрос SELECT в конце тестового файла.

    Проверьте, что испытательный файл демонстрирует проблему, выполняя эти команды:

    shell> mysqladmin create test2
    shell> mysql test2 < query.sql
    
    Присоедините испытательный файл к отчету об ошибках, который Вы можете зарегистрировать, используя инструкции в разделе 1.7.

B.5.4.8. Проблемы со значениями с плавающей запятой

Числа с плавающей запятой иногда вызывают беспорядок, потому что они приблизительны и не сохраненные как точные значения. Значение с плавающей запятой как записано в запросе SQL возможно, не то же самое значение, которое представлено внутренне. Попытки обработать значения с плавающей запятой как точные в сравнениях могут привести к проблемам. Они также подвергаются зависимостям от платформы. Типы данных FLOAT и DOUBLE подвергаются этим проблемам. Для столбцов DECIMAL MySQL выполняет операции с точностью 65 десятичных цифр, которые должны решить наиболее распространенные проблемы погрешности.

Следующее использование в качестве примера DOUBLE показывает, как вычисления, которые сделаны, используя операции с плавающей запятой, приводят к ошибке с плавающей запятой.

mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
    -> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
    -> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
    -> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
    -> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
    -> (6, 0.00, 0.00), (6, -51.40, 0.00);
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
    ->        FROM t1 GROUP BY i HAVING a <> b;
+--+------+------+
| i| a    | b    |
+--+------+------+
|1 | 21.4 | 21.4 |
|2 | 76.8 | 76.8 |
|3 |  7.4 |  7.4 |
|4 | 15.4 | 15.4 |
|5 |  7.2 |  7.2 |
|6 |-51.4 |    0 |
+--+------+------+
Результат правилен. Хотя первые пять записей, похоже, не должны удовлетворить сравнение (значения a и b не отличаются), они могут сделать это, потому что различие между числами обнаруживается после десятого знака или в зависимости от факторов, таких как архитектура системы, версия компилятора или уровень оптимизации. Например, различные центральные процессоры могут оценить числа с плавающей запятой по-другому.

Если столбцы d1 и d2 определены как DECIMAL вместо DOUBLE, результат запроса SELECT содержал бы только одну строку: последнюю из показанных выше.

Правильный способ сделать сравнение числа с плавающей запятой состоит в том, чтобы сначала выбрать приемлемую терпимость к различиям между числами и затем сделать сравнение со значением терпимости. Например, если мы соглашаемся, что числа с плавающей запятой должны быть расценены как равные, если они равны в пределах точности одной десятитысячной (0.0001), сравнение должно быть написано, чтобы найти различия большие, чем значение терпимости:

mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
    ->        GROUP BY i HAVING ABS(a - b) > 0.0001;
+--+-------+---+
| i|    a  | b |
+--+-------+---+
|6 | -51.4 | 0 |
+--+-------+---+
1 row in set (0.00 sec)
Наоборот, чтобы получить строки, где числа те же самые, тест должен найти различия в пределах значения терпимости:
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
    ->        GROUP BY i HAVING ABS(a - b) <= 0.0001;
+--+------+------+
| i| a    | b    |
+--+------+------+
|1 | 21.4 | 21.4 |
|2 | 76.8 | 76.8 |
|3 |  7.4 |  7.4 |
|4 | 15.4 | 15.4 |
|5 |  7.2 |  7.2 |
+--+------+------+
5 rows in set (0.03 sec)
Значения с плавающей запятой подвергаются зависимостям от среды выполнения или платформы. Предположите, что Вы выполняете следующие запросы:
CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));
INSERT INTO t1 VALUES('1e+52','-1e+52');
SELECT * FROM t1;
На некоторых платформах SELECT вернет inf и -inf. На других это возвращает 0 и -0.

Значение предыдущих проблем: если Вы пытаетесь создать ведомое устройство репликации, выводя табличное содержание с mysqldump на ведущем устройстве и перезагружая файл дампа в ведомое устройство, таблицы, содержащие столбцы с плавающей запятой, могут отличаться между двумя хостами.

B.5.5. Проблемы с оптимизацией запросов

MySQL использует оптимизатор на основе издержек, чтобы определить лучший способ решить запрос. Во многих случаях, MySQL может вычислить самый лучший план запроса, но иногда MySQL не имеет достаточной информации о данных и должен сделать предположения о данных.

Для случаев, когда MySQL не делает "правильной" вещи, есть инструменты, которые могут помочь MySQL:

B.5.6. Проблемы определения таблиц

B.5.6.1. Проблемы с ALTER TABLE

Если Вы получаете дублирования ключа, используя ALTER TABLE, чтобы изменить набор символов или сопоставление символьного столбца, причина в том, что новое сопоставление столбца отображает два ключа на то же самое значение или таблица повреждена. В последнем случае Вы должны запустить REPAIR TABLE на таблице. REPAIR TABLE работает для таблиц MyISAM, ARCHIVE и CSV.

Если Вы используете ALTER TABLE на транзакционной таблице или если Вы используете Windows, ALTER TABLE разблокирует таблицу, если Вы сделали LOCK TABLE для нее. Это сделано потому что InnoDB и эти операционные системы не могут удалить таблицу, которая используется.

B.5.6.2. Проблемы с таблицами TEMPORARY

Следующий список указывает ограничения на использование таблиц TEMPORARY:

B.5.7. Известные проблемы в MySQL

Этот раздел перечисляет известные проблемы в недавних версиях MySQL.

Для информации о специфических вопросах платформы, см. разделы 2.1 и 26.5.

Следующие проблемы известны: