Как стать автором
Обновить

MySQL и SQLite — регулярные выражения в предикате

Время на прочтение2 мин
Количество просмотров4.4K
Регулярные выражения могут оказать Вам неоценимую услугу при их разумном применении в SQL-запросах.
Они могут избавить Вас от необходимости перебирать в курсорных циклах, или (о ужас!) в циклах базового языка приложения солидные куски таблиц. Правда иногда услуга может оказаться «медвежьей».
Примеры и особености применения этой техники

Для примера — имеем безнес-логику приложения, в которой на первом этапе пользователь может создавать произвольную запись в базе, а на втором этапе — использовать данную произвольную запись в качестве внешнего ключа.
Задача вполне предсказуема — требуется соблюдать уникальность записи.
Могу предложить к рассмотрению вот такое решение (да, оно не универсально, потому что я дополняю произвольную запись пользователя, тем самым формально ее изменяя. С другой стороны, цитируя Кларксона: "-Да, я тиран! Хотите демократии — езжайте в Ирак!"):
DDL таблицы
CREATE TABLE `human_link` (
 `translit_link` varchar(255) NOT NULL DEFAULT 'main',
 `owner` int NOT NULL,
 PRIMARY KEY (`translit_link`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8


* This source code was highlighted with Source Code Highlighter.

Где обсуждаемая произвольная запись есть поле `translit_link`, которую для соблюдения уникальности мы дополняем цифрой (1) или, если цифра уже есть — увеличиваем цифру на +1.
Узнать, если ли подобная запись, можно запросом
SELECT `translit_link` FROM `foo`.`human_link`
WHERE `translit_link` REGEXP CONCAT('^',?,'[[:digit:]]*$') ORDER BY `translit_link` DESC LIMIT 1;


* This source code was highlighted with Source Code Highlighter.

Собственно, остается только разобраться, что к нам вернулось и сделать с возвратом то, что велит нам логика сохранения уникальности поля (более приближеный к жизни пример этой техники, с использованием perl и хранимой процедуры — в читайте моем блоге).
Но это все была только присказка.
Сказка вот в чем — EXPLAIN MySql про этот запрос скажет Using where; Using index, а вот при использовании SQLite из комлпекта DBD::SQLite —
REGEXP function
Note that regexp matching will not use SQLite indices, but will iterate over all rows, so it could be quite costly in terms of performance.

Кроме того и в MySQL не все так гладко — в книге «High performance MySQL: optimization, backups, replication, and load balancing» By Jeremy D. Zawodny, Derek J. Balling есть строка том, что выражение типа WHERE last_name RLIKE "(son|ith)$" будет нереально медленно по объяснимым причинам, а вот выражение типа WHERE rev_last_name RLIKE "^(thi|nos)" окажется медленне двух union по WHERE rev_last_name like «thi%» и «nos%», потому что что «MySQL оптимизатор никогда не пытается оптимизировать основаный на регулярном выражении запрос».
Из чего делаем вывод, что не все йогурты одинаково полезны.

PS. Буду весьма признателен за подсказку как обстоят дела в PostgreSQL, Oracle и в стане MS. :)
PPS. Я в курсе существования ON DUPLICATE KEY UPDATE — процедура ведет себя некорректно при использовании составного уникального индекса (multiple unique indexes). Т.е. ИМХО теоретически она вообще небезопасна для бизнес-логики, т.к. накладывает неявные ограничения на создаваемые индексы.
Теги:
Хабы:
+5
Комментарии9

Публикации

Изменить настройки темы

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн