2012-01-02 2 views
9

У меня есть таблица с полем с использованием кодировки utf8 и сортировки utf8_unicode_ci:Чувствительный уникальность и поиск без учета регистра

CREATE TABLE dictionary (
    a varchar(128) NOT NULL 
) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

Сопоставление utf8_unicode_ci требуется для эффективного без учета регистра поиска с расширениями и перевязку. Для этого у меня есть индекс:

CREATE INDEX a_idx on dictionary(a); 

Проблема: Кроме того, я должен убедиться, что все сохраненные значения поля а являются уникальными, но в случае чувствительной способом. Пример Германии: «blühen» и «Blühen» должны храниться в таблице. Но добавление «Blühen» во второй раз не должно быть возможным.

Есть ли встроенные функции в MySQL, чтобы иметь оба?

К сожалению, не представляется возможным установить сопоставление индекса в MySQL 5.1.

Решения этой проблемы включают проверку уникальности перед вставкой или триггером. Оба они намного менее изящны, чем использование уникального индекса.

+0

К сожалению, MySQL не имеет таких функций, как индексы/материализованные представления или вычисляемые столбцы или индексы на основе функций, которые имеются в других СУБД. Мне было бы интересно посмотреть, как это делается, конечно ... – gbn

+0

Будет ли добавлен еще один столбец с учетом сортировки и неудобства для случая? –

+0

Я думаю, что эта тема - хорошая помощь. http://stackoverflow.com/questions/4945349/mysql-search-with-uft8-general-ci-is-case-sensitive-for-fulltext – MahanGM

ответ

4

Ну, есть 2 способа сделать это:

  1. с использованием _bin сверку
  2. изменить свой тип данных для VARBINARY

Случай 1: с помощью _bin сверку

Создать Ваша таблица выглядит следующим образом:

CREATE TABLE `dictionary` (
`a` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 
UNIQUE KEY `idx_un_a` (`a`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

Обратите внимание:

  1. тип данных столбца a
  2. УНИКАЛЬНО индекс на колонке a

Случай 2: с помощью VARBINARY dataype

Создать таблицу следующим образом:

CREATE TABLE `dictionary` (
`a` VARBINARY(128) NOT NULL, 
UNIQUE KEY `idx_uniq_a` (`a`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

Обратите внимание:

  1. новый тип данных VARBINARY
  2. УНИКАЛЬНО индекс на колонке a

Итак, как выше будет решать ваши цели. То есть, они оба позволят такие значения, как «abc», «abc», «ABC», «aBc» и т. Д., Но не позволяют повторять одно и то же значение, если это соответствует совпадению.

Обращаем ваше внимание, что предоставление сопоставления «_bin» отличается от использования двоичного типа данных.Поэтому, пожалуйста, не стесняйтесь обратиться к следующим ссылкам:

  1. The BINARY and VARBINARY datatypes
  2. The _bin and binary Collations

Я надеюсь, что выше помогает!

+0

Спасибо за ответ! Я не вижу, как с помощью этого решения будет эффективный (O (log (n)) и нечувствительный к регистру поиск. – user1091141

+0

@ user1091141, конечно, вы можете делать нечувствительные к регистру поиск, изменяя сортировку, например запрос типа слова SELECT * FROM WHERE a COLLATE utf8_general_ci = 'abc''. Извините, если мой ответ не был ясен, но я догадался, что вы можете понять это, вот ссылка - «http://dev.mysql.com/doc/refman/5.0 /en/case-sensitivity.html ". Относительно O (log (n)), извините, но моя математика не так сильна, но я не понимаю, почему поиск будет неэффективным. В качестве альтернативы вы можете сохранить 2' a 'column - один с общей сортировкой для запросов без учета регистра, а другой с _bin для чувствительных к регистру вставок – Abhay

+2

, если я укажу другое сопоставление в where-clause, чем то, что определено в определении таблицы, MySQL не будет использовать индекс, но делает полное сканирование таблицы. Полное сканирование таблицы может занять много времени для больших таблиц, поэтому они могут быть регарами как неэффективные. Выполнение 'EXPLAIN SELECT * FROM словаря WHERE COLLATE utf8_general_ci = 'abc'' показывает, что все строки в таблице прочитаны. Это, по крайней мере, для моей версии MySQL (5.0 и 5.1). Было бы неплохо, если бы все было иначе. – user1091141

1

Вы можете достичь этого, добавив добавочный столбец column_lower.

CREATE TABLE `dictionary` (
    `a` VARCHAR(128) NOT NULL, 
    `a_lower` VARCHAR(128) NOT NULL, 
    UNIQUE KEY `idx_un_a_lower` (`a_lower`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 

Вставка что выглядит следующим образом:

insert into dictionary set a = x, a_lower = lower(x); 

Выберите теперь могут быть чувствительны к регистру:

select * from dictionary where a_lower like lower('search_term%') 

Обратите внимание, что столбец, который имеет индекс на нем, может хранить не более 191 символов , MySQL может иметь индекс max 767 bytes, то есть 767/4 (unicode может занимать до 4 байтов, если вы используете сортировку utf8mb4) = 191,75 = 191 символ. Если вы используете настройку utf8, которая занимает максимум 3 байта на столбец с символом, можно сохранить максимум при 767/3 = 255 символов.

0
SELECT * FROM dictionary WHERE a COLLATE utf8_general_ci = 'abc' 

Попробуйте Это будет работать .. это сработало для меня.

Смежные вопросы