Индекс базы данных без учета регистра?

У меня есть запрос, в котором я ищу строку:

SELECT county FROM city WHERE UPPER(name) = 'SAN FRANCISCO';

Теперь это работает нормально, но плохо масштабируется, и мне нужно его оптимизировать. Я нашел вариант создания сгенерированное представление или что-то в этом роде, но я надеялся на более простое решение с использованием индекса.

Мы используем DB2, и я действительно хочу использовать выражение в индексе, но эта опция, по-видимому, доступна только в z/OS, однако мы используем Linux. Я все равно попробовал индекс выражения:

CREATE INDEX city_upper_name_idx
ON city UPPER(name) ALLOW REVERSE SCANS;

Но, конечно, давится ВЕРХНИМ (имя).

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

РЕДАКТИРОВАТЬ: я готов выслушать решения для других баз данных... это может быть перенесено на DB2...


person Mike Stone    schedule 15.08.2008    source источник


Ответы (6)


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

Затем вы можете сделать несколько предложений where :

hash = [compute hash key for 'SAN FRANCISCO']

SELECT county 
FROM city 
WHERE cityHash = hash 
  AND UPPER(name) = 'SAN FRANCISCO' ;

В качестве альтернативы просмотрите руководство по базе данных и просмотрите варианты создания индексов таблиц. Может быть что-то полезное.

person nsanders    schedule 15.08.2008

Короткий ответ, нет.

Длинный ответ: да, если вы работаете на мейнфрейме, но это не так, поэтому вам придется использовать другие хитрости.

DB2 (начиная с DB2/LUW v8) теперь создает столбцы, поэтому вы можете:

CREATE TABLE tbl (
    lname  VARCHAR(20),
    fname  VARCHAR(20),
    ulname VARCHAR(20) GENERATED ALWAYS AS UPPER(lname)
);

а затем создайте индекс для ulname. Я не уверен, что вы собираетесь получить это проще, чем это.

До этого вам приходилось использовать комбинацию триггеров вставки и обновления, чтобы обеспечить синхронизацию столбца ulname, и поддерживать это было кошмаром. Кроме того, теперь, когда эта функциональность является частью основной СУБД, она была оптимизирована (она намного быстрее, чем решение на основе триггеров) и не мешает реальным пользовательским триггерам, поэтому не нужно поддерживать дополнительные объекты БД.

См. здесь для деталей.

person paxdiablo    schedule 07.01.2009

Я не знаю, будет ли это работать в DB2, но я расскажу вам, как бы я сделал это в SQL Server. Я думаю, что MSSQL делает это по стандарту ANSI, хотя конкретные строки сопоставления могут отличаться. В любом случае, если вы можете сделать это, не уничтожая остальную часть вашего приложения, есть ли другие места, где столбец «имя» должен быть чувствительным к регистру? -- попробуйте сделать весь столбец нечувствительным к регистру, изменив параметры сортировки, а затем проиндексируйте столбец.

ALTER TABLE city ALTER COLUMN name nvarchar(200) 
    COLLATE SQL_Latin1_General_CP1_CI_AS

... где «nvarchar (200)» означает любой тип данных вашего текущего столбца. Часть «CI» строки сопоставления — это то, что помечает ее как нечувствительную к регистру в MSSQL.

Чтобы объяснить... насколько я понимаю, индекс будет хранить значения в порядке сортировки индексированного столбца. Если сделать сопоставление столбца нечувствительным к регистру, индекс будет хранить «Сан-Франциско», «САН-ФРАНЦИСКО» и «Сан-Франциско» вместе. Тогда вам нужно просто удалить "UPPER()" из вашего запроса, и DB2 должна знать, что она может использовать ваш индекс.

Опять же, это основано исключительно на том, что я знаю о SQL Server, плюс пару минут изучения спецификации SQL-92; это может работать или не работать для DB2.

person Kevin Crumley    schedule 19.08.2008

Oracle поддерживает индексы на основе функций. Их канонический пример:

 create index emp_upper_idx on emp(upper(ename));  
person Mark Harrison    schedule 16.08.2008
comment
К сожалению, в DB2/LUW этого пока нет, но, вероятно, он появится, поскольку он есть в DB2/z. - person paxdiablo; 07.01.2009

PostgreSQL также поддерживает индексацию результатов функции:

CREATE INDEX mytable_lower_col1_idx ON mytable (lower(col1));

Единственный другой вариант, который я могу придумать, - это немного денормализовать ваши данные, создав еще один столбец для хранения версии в верхнем регистре (обновляемой триггерами) и проиндексировав ее. Блех!

person Neall    schedule 16.08.2008
comment
Не нужны триггеры и тому подобное, DB2 поддерживает сгенерированные столбцы. - person paxdiablo; 07.01.2009

DB2 не сильна в отношении сортировки. И у него нет индексов на основе функций.

Предложение Ника Сандерса будет работать, если вы согласитесь с тем, что хеширование должно происходить в вашем приложении (поскольку, насколько мне известно, в DB2 нет функций SHA или MD5).

Однако на вашем месте я бы создал материализованное представление (MQT == Materialized Query Table, на языке db2), используя СОЗДАТЬ ТАБЛИЦУ КАК, добавив столбец с предварительно вычисленным вариантом верхнего регистра название. Примечание: Вы можете добавлять индексы к материализованным представлениям в DB2.

person Troels Arvin    schedule 03.09.2008
comment
Дешевле с точки зрения хранения и скорости просто добавить еще один сгенерированный столбец в существующую таблицу, чем иметь целую другую таблицу. И я оспариваю, что DB2 слаб с сопоставлением. И урод твоей сестры... пардон, увлёкся :-). - person paxdiablo; 07.01.2009