Сегодня обнаружил странную особенность работы IFNULL, когда параметры имеют одинаковую кодировку(charset) и разное сравнение(collation).
Итак проводим небольшой тест:
Посылаем запрос
А в ответ:
На первый взгляд всё логично — сравнение различается и возвращается ошибка, но если подумать, то оператор IFNULL вообще не должен обращать внимания на сравнение.
Начал обходить проблему, первое что пришло в голову
Запрос отработал без ошибок, но дольше по сравнению с простой выборкой одного поля на 5-10мс, что сопоставимо со временем работы самого запроса (~6-8мс, в моём случае это с десяток джоинов). Т.к. нагрузка на базу большая, а запрос основной, то решение меня не устроило.
Думаю дальше. «А что если попробовать обычный IF? Нет, очевидно же не сработает… А вдруг? Много времени не потеряю, лучше проверить»
Каково было моё удивление когда запрос сработал.
«Как это может быть. Я вероятно где-то ошибся… Перепроверим — действительно всё работает, но вероятно еще дольше.»
«Нет, время запроса изменилось на 1мс, это на уровне погрешности o_0»
Еще одна странная вещь
Посылаем запрос
«Сработало? 0_o Вот здесь я бы как раз и ожидал бы увидеть ошибку, но её нет!»
В мануале про такое поведение ничего не нашел. Что же это баг или фича?
P.S. Проверял на версиях 5.0 и 5.1.
Итак проводим небольшой тест:
CREATE TABLE `test` (
`name1` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL ,
`name2` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
)
ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
Посылаем запрос
SELECT IFNULL(name1, name2) FROM test;
А в ответ:
Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation 'ifnull'
На первый взгляд всё логично — сравнение различается и возвращается ошибка, но если подумать, то оператор IFNULL вообще не должен обращать внимания на сравнение.
Начал обходить проблему, первое что пришло в голову
SELECT IFNULL(name1 COLLATE utf8_general_ci, name2) FROM test;
Запрос отработал без ошибок, но дольше по сравнению с простой выборкой одного поля на 5-10мс, что сопоставимо со временем работы самого запроса (~6-8мс, в моём случае это с десяток джоинов). Т.к. нагрузка на базу большая, а запрос основной, то решение меня не устроило.
Думаю дальше. «А что если попробовать обычный IF? Нет, очевидно же не сработает… А вдруг? Много времени не потеряю, лучше проверить»
SELECT IF(name1 IS NOT NULL, name1, name2) FROM test;
Каково было моё удивление когда запрос сработал.
«Как это может быть. Я вероятно где-то ошибся… Перепроверим — действительно всё работает, но вероятно еще дольше.»
«Нет, время запроса изменилось на 1мс, это на уровне погрешности o_0»
Еще одна странная вещь
ALTER TABLE `test` MODIFY COLUMN `name2` varchar(10) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL AFTER `name1`;
Посылаем запрос
SELECT IFNULL(name1, name2) FROM test;
«Сработало? 0_o Вот здесь я бы как раз и ожидал бы увидеть ошибку, но её нет!»
В мануале про такое поведение ничего не нашел. Что же это баг или фича?
P.S. Проверял на версиях 5.0 и 5.1.