MySQL.RU .:. Одобрено лучшими российскими программистами

Справочное руководство по MySQL

1.9.5 Известные ошибки и недостатки проектирования в MySQL

1.9.5 Известные ошибки и недостатки проектирования в MySQL

Устранение следующих из выявленных проблем относится к числу первоочередных задач:

  • ANALYZE TABLE на таблицах BDB в некоторых случаях может сделать таблицу недоступной для использования, пока не произойдет перезапуск mysqld. При этом в файле ошибок MySQL можно будет увидеть ошибки, подобные следующим:
    001207 22:07:56 bdb: log_flush: LSN past current end-of-log
    
  • Не следует выполнять ALTER TABLE на таблицах BDB, на которых осуществляются многокомандные транзакции, пока все эти транзакции не завершатся (возможно, данные транзакции будут проигнорированы).
  • ANALYZE TABLE, OPTIMIZE TABLE и REPAIR TABLE могут вызвать проблемы на таблицах, для которых используется INSERT DELAYED.
  • Выполнение LOCK TABLE ... и FLUSH TABLES ... не гарантирует, что на данной таблице нет исполняемых в текущий момент незаконченных транзакций.
  • Открытие таблиц BDB происходит несколько медленно. Если база данных содержит много таблиц BDB, то потребуется значительное время для использования клиента mysql на этой базе данных, если не применять опцию -A или если использовать rehash. Это особенно заметно при наличии большого табличного кэша.

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

  • При использовании функции RPAD, или любой другой строковой функции, добавляющией пробелы в правую часть строки, в запросе, для которого MySQL будет создавать временные таблицы для его выполнения, все результирующие строки будут в результате обработаны RTRIM'ом (RTRIM'ed). Вот пример запроса: SELECT RPAD(t1.field1, 50, ' ') AS f2, RPAD(t2.field2, 50, ' ') AS f1 FROM table1 as t1 LEFT JOIN table2 AS t2 ON t1.record=t2.joinID ORDER BY t2.record; В результате невозможно получить пробелы в правой части результирующего столбца. Такое поведение присутствует во всех версиях MySQL. Причина заключается в том, что HEAP-таблицы, которые в первую очередь используются для временных таблиц, неспособны работать с VARCHAR-столбцами. Такое поведение будет исправлено в одной из версий 4.1.
  • При использовании SET CHARACTER SET нельзя использовать преобразованные символы в именах базы данных, таблицы и столбца.
  • Нельзя использовать _ или % с ESCAPE в LIKE ... ESCAPE.
  • Если в столбце DECIMAL число хранится в различных форматах (+01.00, 1.00, 01.00), то GROUP BY может рассматривать каждую величину как самостоятельную.
  • DELETE FROM merge_table при использовании без WHERE будет очищать только отображение для этой таблицы, а не удалять все данные в отображенных таблицах.
  • При использовании потоков MIT-pthreads нельзя расположить сервер в ином каталоге. Поскольку для решения данной проблемы требуются изменения для потоков MIT-pthreads, маловероятно, что мы ее устраним (see section 2.3.6 Замечания по потокам MIT-pthreads).
  • Не обеспечивается ``надежное'' применение величин BLOB в GROUP BY или ORDER BY или DISTINCT. В этих случаях при сравнении величин BLOB используются только первые max_sort_length байтов (по умолчанию 1024). Это можно изменить с помощью опции -O max_sort_length для mysqld. Обходной путь для большинства случаев заключается в использовании подстроки: SELECT DISTINCT LEFT(blob,2048) FROM tbl_name.
  • В сервере MySQL вычисления производятся в форматах типов BIGINT или DOUBLE (оба типа обычно имеют длину 64 бита). Это зависит от того, какую точность обеспечивает применяемая функция. Общее правило состоит в том, что битовые функции работают с точностью BIGINT, функции IF и ELT() - с точностью BIGINT или DOUBLE, а остальные - с точностью DOUBLE. Следует избегать применения беззнаковых величин двойной точности, если они могут превысить 63 бита (9223372036854775807), для каких-либо величин, кроме битовых полей! В версии сервера MySQL 4.0 реализована лучшая обработка BIGINT, чем в 3.23.
  • Во всех строковых столбцах, исключая BLOB и TEXT при извлечении данных автоматически удаляются все концевые пробелы. Для типов CHAR это хорошо и может рассматриваться как свойство, соответствующее ANSI SQL92. Ошибка заключается в том, что в сервере MySQL столбцы VARCHAR трактуются тем же самым образом.
  • В одной таблице может быть только до 255 столбцов типа ENUM и SET.
  • В MIN(), MAX() и других групповых функциях, MySQL сейчас сравнивает ENUM и SET-столбцы по их строковому значению, а не по относительной позиции строки в множестве.
  • При указании параметра safe_mysqld все сообщения из mysqld направляются в журнал данного потока mysqld. Одна из проблем заключается в том, что если вы исполняете mysqladmin refresh для того, чтобы закрыть и заново открыть журнал, то stdout и stderr будут все еще по-прежнему направлены в старый журнал. При активном использовании --log следует отредактировать safe_mysqld, чтобы записи велись в ``hostname`.err', а не в ``hostname`.log', с тем, чтобы вы могли очищать пространство, удаляя старые журналы и вызывая mysqladmin refresh.
  • При выполнении команды UPDATE столбцы обновляются слева направо. При ссылке на обновленный столбец вместо исходной величины будет получена обновленная величина. Например:
    mysql> UPDATE tbl_name SET KEY=KEY+1,KEY=KEY+1;
    
    Эта команда обновит KEY со значением 2 вместо значения 1.
  • В одном и том же запросе нельзя использовать временные таблицы более чем один раз. Например, следующая команда выполнена не будет:
    mysql> SELECT * FROM temporary_table, temporary_table AS t2;
    
  • RENAME не работает с временными таблицами или при использовании таблицы MERGE.
  • Оптимизатор может обрабатывать DISTINCT по-разному, в зависимости от того, используются или нет в объединении ``скрытые'' столбцы. В объединении скрытые столбцы считаются частью результата (даже если они не показываются), в то время как в обычных запросах скрытые столбцы не участвуют в сравнении DISTINCT. Возможно, в будущем мы изменим это правило таким образом, чтобы при выполнении DISTINCT скрытые столбцы никогда не сравнивались. Например:
    SELECT DISTINCT mp3id FROM band_downloads
           WHERE userid = 9 ORDER BY id DESC;
    
    и
    SELECT DISTINCT band_downloads.mp3id
           FROM band_downloads,band_mp3
           WHERE band_downloads.userid = 9
           AND band_mp3.id = band_downloads.mp3id
           ORDER BY band_downloads.id DESC;
    
    Во втором случае в версии сервера MySQL 3.23.x можно получить две идентичных строки в результирующем наборе данных (поскольку скрытый столбец id может варьироваться). Заметьте, что это случается только с запросами, где в результате отсутствуют столбцы ORDER BY, что не разрешается делать в ANSI SQL.
  • Поскольку сервер MySQL обеспечивает возможность работать с типами таблиц, которые не поддерживают транзакции и, следовательно, не допускают отката данных, то поведение сервера MySQL в некоторых аспектах отличается от других серверов SQL. Это делается, чтобы гарантировать, что сервер MySQL никогда не будет нуждаться в откате SQL-команд. Такое поведение временами может быть несколько неудобным, так как вследствие этого величины столбцов должны проверяться в приложении. Однако благодаря такому решению вы получаете действительно хорошее увеличение скорости, поскольку для сервера MySQL обеспечивается возможность производить определенные оптимизации, что в противном случае было бы очень трудно сделать. При попытке установить столбец в некорректную величину сервер MySQL вместо выполнения отката будет сохранять в данном столбце ``наиболее вероятную величину'':
    • При попытке сохранить в числовом столбце величину, выходящую за допустимые пределы, сервер MySQL вместо нее будет сохранять в этом столбце наименьшую или наибольшую допустимую величину.
    • При попытке сохранить в числовом столбце строку, которая начинается не с числа, сервер MySQL будет сохранять в нем 0.
    • При попытке сохранить NULL в числовом столбце, который не принимает значения величины NULL, сервер MySQL вместо NULL будет сохранять 0 или '' (пустая строка) (однако это поведение можно изменить с помощью опции компиляции -DDONT_USE_DEFAULT_FIELDS).
    • MySQL обеспечивает возможность сохранять некоторые ошибочные величины даты в столбцах DATE и DATETIME (такие как 2000-02-31 или 2000-02-00). Идея заключается в том, что задача проверки валидности даты не входит в круг обязанностей сервера баз данных. Если MySQL может сохранить и корректно воспроизвести какие-либо значение даты, пусть и неправильное - MySQL будет сохранять такое значение. Если дата полностью неправильна, сервер MySQL будет сохранять в этом столбце специальную величину даты 0000-00-00.
    • Если устанавливать столбец ENUM в неподдерживаемую величину, то он будет устанавливаться в значение ошибки empty string с числовым значением 0.
    • Если устанавливать столбец SET в неподдерживаемую величину, то эта величина будет игнорироваться.
  • При выполнении PROCEDURE на запросе, возвращающем пустой набор, в некоторых случаях PROCEDURE не будет преобразовывать столбцы.
  • При создании таблицы типа MERGE не происходит проверки, если лежащие в ее основе таблицы имеют совместимые типы.
  • Сервер MySQL пока еще не может обрабатывать величины NaN, -Inf и Inf с двойной точностью. Их использование вызовет проблемы при попытке экспорта или импорта данных. В качестве промежуточного решения мы должны изменить NaN на NULL (если возможно) и -Inf и Inf на минимальную или, соответственно, максимально возможную величину двойной точности.
  • LIMIT на отрицательных числах трактуются как большие положительные числа.
  • Если ALTER TABLE используется для того, чтобы сначала добавить индекс UNIQUE к таблице, которая входит в таблицу MERGE, а затем - чтобы добавить обычный индекс к таблице MERGE, то в случае, если существовал старый ключ, который не был уникальным в данной таблице, порядок ключей для таблиц будет различным. Это обусловлено тем, что ALTER TABLE помещает уникальные ключи перед обычными ключами, чтобы обеспечить возможность определять дублирующиеся ключи как можно раньше.

В более ранних версиях MySQL известны следующие ошибки:

  • Можно получить зависший поток при выполнении DROP TABLE на таблице, которая является одной из числа многих таблиц, заблокированных с помощью LOCK TABLES.
  • В следующем случае может произойти аварийное завершение процесса:
    • Обработчик задержанных вставок имеет незаконченные вставки в таблицу.
    • LOCK table с помощью WRITE.
    • FLUSH TABLES.
  • В версиях сервера MySQL до 3.23.2 команда UPDATE, которая обновляла ключ с помощью WHERE на тот же самый ключ, может оказаться неудачной, поскольку данный ключ использовался для поиска записей и одна и та же строка может быть найдена много раз:
    UPDATE tbl_name SET KEY=KEY+1 WHERE KEY > 100;
    
    Обходным решением является использование:
    mysql> UPDATE tbl_name SET KEY=KEY+1 WHERE KEY+0 > 100;
    
    Эта команда будет работать, поскольку сервер MySQL не будет использовать индекс на выражениях в утверждении WHERE.
  • До версии сервера MySQL 3.23 все числовые типы трактовались как поля с фиксированной точкой. Это означает, что необходимо было указывать, сколько десятичных знаков должно содержать поле с плавающей точкой. Все результаты возвращались с правильным количеством десятичных знаков.

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