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 все числовые типы трактовались как поля с фиксированной точкой. Это означает, что необходимо было указывать, сколько десятичных знаков должно содержать поле с плавающей точкой. Все результаты возвращались с правильным количеством десятичных знаков.
В отношении ошибок, связанных со спецификой различных платформ, см. разделы о компилировании и переносе.