У меня есть приложение Rails с моделью (таблицей), которая имеет 150000 записей, с размером текстового поля от 50 до 8000 символов.
Мне нужно, чтобы текстовое поле было уникальным. Поскольку я не могу использовать уникальный индекс MySQL в текстовом поле, мое решение состоит в том, чтобы преобразовать текстовое поле в хэш (используя Digest :: SHA256.hexdigest) и сохранить этот хэш в поле varchar под названием body_hash. Затем добавьте уникальный индекс в это поле.
Вопросы:
Вы можете захотеть создать эту контрольную сумму/дайджест в самой БД. Это будет быстрее возвращать значения заполнения для существующих данных, а не обрабатывать Ruby.
Объединение MySQL CREATE_DIGEST
для заполнения столбца body_digest
:
CREATE_DIGEST('SHA512', 'The quick brown fox');
https://dev.mysql.com/doc/refman/8.0/en/enterprise-encryption-functions.html#function_create-digest
И BEFORE INSERT
/BEFORE UPDATE
триггер, чтобы установить это значение контрольной суммы:
https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
Стоит упомянуть там библиотеку Ruby для объявления триггеров базы данных на моделях ActiveRecord: https://github.com/jenseng/hair_trigger
Решение Rails - это крюк before_save
. Вы также можете сделать это с помощью триггера базы данных, но это намного более грязно и хрупко.
SHA256, вероятно, прекрасен здесь, как и SHA2. Вероятность столкновения должна быть исчезающе мала.
Использование хэша согласованной длины вместо текста для уникального индекса на самом деле отличная идея, потому что индексы MySQL становятся больше для более длинных строк. Короткая шестнадцатеричная строка намного легче обрабатывать движок индексирования и по-прежнему обеспечивает ограничение уникальности, которое вы хотите.
Уникальные ограничения MySQL фактически также обеспечивают механизм упорядочения, что источник боли здесь, но если вы не занимаетесь упорядочением хеш-решения, это отличная альтернатива.
before_save
хукаbefore_save
является то, что он не защищает от вставок / обновлений, сделанных непосредственно в БД