Trino: How to configure Presto searches to be case-insensitive?
Ты пишешь запрос в Trino к MySQL, где `name = 'Adam'` должен вернуть строку с `'adam'`. Но возвращается пустота. Или `LIKE '%a%'` ловит только строчную `a`, про
Ты пишешь запрос в Trino к MySQL, где name = 'Adam' должен вернуть строку с 'adam'. Но возвращается пустота. Или LIKE '%a%' ловит только строчную a, пропуская Alan. Знакомо?
Ты проверяешь — да, MySQL точно case-insensitive. Но Trino упорно сравнивает по-честному. В чём подвох?
Почему Trino не наследует нечувствительность к регистру
Trino — не прокси. Это распределённый SQL-движок. Он строит план запроса, и часто сам выполняет его части, а не просто пересылает сырой запрос в источник.
Соединитель (connector) читает метаданные из БД (названия таблиц, колонок, типы), но семантика операций — это уже зона ответственности Trino. Сравнение строк — одна из таких операций.
Если бы поведение зависело от каждой СУБД, то результаты одного запроса к разным источникам в федеративном запросе стали бы непредсказуемыми. Поэтому Trino по умолчанию следует стандарту SQL: сравнение строк — регистрозависимая операция.
Это касается и оператора =, и LIKE. Поэтому твой запрос where name = 'Adam' ищет точное совпадение, включая регистр.
Что делать? Явное приведение
Ответ — нормализация. Приводи сравниваемые значения к одному регистру явно, используя lower() или upper().
select * from table where lower(name) like '%a%';
Теперь 'a' в шаблоне и lower(name) оба в нижнем регистре. Запрос вернёт и adam, и Alan.
Для точного сравнения — тот же принцип:
select * from table where lower(name) = lower('Adam');
Теперь 'adam' и 'Adam' после lower() станут 'adam' и найдут друг друга.
А если не хочется оборачивать каждый столбец в lower()?
Придётся. Волшебной настройки в config.properties соединителя для глобального case-insensitive поиска нет. Можно было бы мечтать о параметре типа case-insensitive-name-matching=true, но его нет.
Можно создать view в MySQL, где заранее приведены все текстовые поля, и подключаться к нему. Или использовать вычисляемые колонки, если источник поддерживает. Но это костыли.
Правильный путь — признать, что Trino работает со своими строгими правилами, и явно указывать нужную логику в запросе. Это делает код переносимым и предсказуемым.
Итог
MySQL case-insensitive, а Trino — нет. Это не баг, а архитектурная особенность. Запрос планируется и частично выполняется в Trino, который следует стандарту SQL.
Решение всегда одно: lower(column) = lower(value). Пиши так сразу, и не будет сюрпризов. И да, это немного раздражает, но зато точно.