Это безумие, чтобы обойти проблемы чувствительности к регистру базы данных, сохраняя оригинальный строчный регистр И нижний регистр? - PullRequest
1 голос
/ 25 октября 2010

Я реализую базу данных, в которой несколько таблиц имеют строковые данные в качестве ключей-кандидатов (например, имя пользователя) и будут соответствующим образом проиндексированы.Для этих полей я хочу:

  1. Нечувствительность к регистру, когда кто-то запрашивает таблицу по этим ключам

  2. Первоначально записанный кейс как-то сохраняется, чтобыприложение может представить данные пользователю с использованием исходного регистра

Я также хочу, чтобы схема базы данных была настолько независимой от базы данных, насколько это возможно, поскольку код приложения является (или не должен быть) не подчинено конкретной СУБД.

Также стоит отметить, что подавляющее большинство запросов к базе данных будет выполняться кодом приложения, а не с помощью прямого доступа к таблице со стороны клиента.

При реализации этого я сталкиваюсь с множеством раздражающих проблем.Одна из них заключается в том, что не все СУБД реализуют COLLATE (в этом случае чувствительность к регистру настраивается на уровне схемы) одинаково.Другая проблема заключается в том, что параметры сортировки и чувствительности к регистру могут быть установлены на нескольких уровнях (сервер, база данных, таблица (?), Столбец), и я не могу гарантировать приложению, какие настройки он получит.Еще одна проблема заключается в том, что сам COLLATE может стать волосатым, потому что в нем есть намного больше, чем просто чувствительность к регистру (например, параметры Unicode).

Чтобы избежать всех этих головных болей, то, что я рассматриваюполностью уклоняется от проблемы, сохраняя два столбца для одного фрагмента данных.Один столбец с исходным регистром, другой - с нижнего регистра на прикладном уровне.

Например: два поля в таблице

user_name = "fredflintstone" (a unique index on this one)
orig_name = "FredFlintstone" (just data... no constraints)

Плюсы и минусы этого, как я вижуэто:

Плюсы:

  1. Нет двусмысленности - код приложения будет управлять преобразованиями кейсов, и мне никогда не нужно беспокоиться о сбоях модульных тестов«таинственно», когда изменяется базовая СУБД / настройки.

  2. Поиск в индексе будет чистым и никогда не будет замедлен функциями сортировки или вызовами LOWER () или чем-либо (при условии, что такие вещизамедление индекса, что кажется логичным)

Минусы:

  1. Для удвоения требуется дополнительное место для храненияdata

  2. Кажется немного грубоватым

Я знаю, что это будет работать, но в то же время пахнет неправильно.

Это безумие / бессмысленно делать это?Есть ли что-то, чего я не знаю, что делает проблему с чувствительностью к регистру менее сложной, чем мне кажется на данный момент?

Ответы [ 4 ]

2 голосов
/ 25 октября 2010

Поиск в индексе будет чистым и никогда не будет замедлен функциями сортировки или вызовами LOWER () или чем-то еще (при условии, что такие вещи замедляют индекс, что кажется логичным)

Нет, это не логично. Вы можете иметь индексы для константных функций.

create index users_name on users(name); -- index on name
create index users_name_lower on users(lower(name)); -- index on the function result

Ваша СУБД должна быть достаточно умна, чтобы знать, чтобы использовать users_name_lower, когда получает этот запрос:

select * from users where lower(name) = ?

Без users_name_lower, да, пришлось бы ходить по столу. С функциональным индексом это делает правильно.

2 голосов
/ 25 октября 2010

Конечно, такие решения всегда являются компромиссом, но я не думаю, что это обязательно «удвоенные данные». Строка в нижнем регистре может быть нетривиальной операцией, особенно если вы выходите за пределы ASCII, поэтому версия строки в нижнем регистре не просто «дублируется». Это несколько связано с исходной строкой, но не более того.

Если вы считаете это аналогом сохранения вычисленных результатов в БД, это становится более естественным.

Опция запроса на UPPER(UserName) является еще одним хорошим решением, которое позволяет избежать второго столбца. Однако для его использования вам нужна как минимум надежная функция UPPER (где, в частности, вы можете контролировать локаль, которую она использует для символов, не входящих в ASCII), и, вероятно, индексы на основе функций для достойной производительности.

1 голос
/ 25 октября 2010

Я часто видел, как данные дублировались таким образом из соображений производительности.Это позволяет вам сохранить оригинальный регистр (который вам, очевидно, понадобится, поскольку вы не всегда можете угадать, каким должен быть регистр, например, вы не можете быть уверены, что каждое имя начинается с заглавной буквы).Если база данных не поддерживает другие способы сделать это (функциональные индексы), то это практично, а не безумие.Вы можете поддерживать согласованность данных с помощью триггеров.

1 голос
/ 25 октября 2010

Предложите вашим поисковым запросам сделать что-то вроде этого:

  • SELECT * FROM Users WHERE LOWER(UserName) = LOWER('fredFlinstone')
  • явно включить подсказку COLLATION в запрос, когда чувствительность к регистру следует игнорировать / соблюдать

Я бы посчитал дублирование данных слишком чувствительным к регистру.

...