Производительность SQL при поиске длинных строк - PullRequest
4 голосов
/ 13 января 2012

Мне нужно хранить строки пользовательских агентов в базе данных для отслеживания и сравнения поведения клиентов и эффективности продаж между различными браузерами. Довольно простая строка пользовательского агента имеет длину около 100 символов. Было решено использовать varchar(1024) для хранения данных useragent в базе данных. (Я знаю, что это излишне, но это идея; предполагается, что в течение многих лет будут использоваться данные userragent, а некоторые устройства, панели инструментов и приложения уже будут выдавать 500 символов в длину.) Таблица, содержащая эти строки, будет нормализована (каждый отдельный пользователь Строка агента будет сохранена только один раз) и будет обрабатываться как кэш, поэтому нам не придется интерпретировать пользовательские агенты снова и снова.

Типичный вариант использования:

  • Пользователь заходит на наш сайт, определяется как новый резистор
  • Для этого пользователя создана новая информация о сеансе
  • Определите, нужно ли нам анализировать строку пользовательского агента или у нас есть действительный анализ для файла
  • Если он у нас есть, хорошо, если нет, проанализировать его (в настоящее время мы планируем вызвать сторонний API)
  • Сохранение соответствующей информации (имя браузера, версия, ОС и т. Д.) В объединенной таблице, привязав информацию о существующем сеансе пользователя и указав на запись в кэше

Примечание: У меня есть тенденция говорить «поиск» строки агента пользователя в базе данных, потому что это не простой поиск. Но чтобы было ясно, в запросах будут использоваться операторы '=', а не регулярные выражения или синтаксис LIKE%.

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

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

Хеширование до целочисленного значения обеспечит наилучшую производительность при риске более высоких коллизий. Я ожидаю увидеть максимум тысячи или десятки тысяч пользовательских агентов; даже 100 000 пользовательских агентов вполне могли бы вписаться в целое число размером 2 ^ 32 с очень небольшим количеством коллизий, которые могли бы быть расшифрованы веб-сервисом с минимальным влиянием на производительность. Даже если вы думаете, что целочисленный хэш не очень хорошая идея, использование дайджеста из 32 символов (например, SHA-1, MD5) должно быть намного быстрее для выбора, чем необработанная строка, верно?

Моя база данных - движок MySQL InnoDB. Сначала веб-код будет исходить из C #, а затем из php (после того, как мы объединяем хостинг и аутентификацию) (не то, чтобы веб-код имел большое значение).

Позвольте мне извиниться, если вы думаете, что это неубедительный вопрос о выборе алгоритма хэша. Я действительно надеюсь получить некоторую информацию от людей, которые делали что-то подобное раньше, и от процесса принятия решений Итак, вопрос:

  • Какой хеш вы бы использовали для этого приложения?
  • Вы бы вычислили хеш в коде или позволили бы его обработать БД?
  • Существует ли радикально иной подход для хранения / поиска длинных строк в базе данных?

Ответы [ 2 ]

2 голосов
/ 13 января 2012

Ваша идея хэширования длинных строк для создания токена, по которому можно искать в хранилище (кеше или базе данных), хороша.Я видел, что это было сделано для очень больших строк и в средах с большим объемом, и это прекрасно работает.

«Какой хэш вы бы использовали для этого приложения?»

  • Я неНе думаю, что алгоритм шифрования (хеширования) действительно имеет значение, поскольку вы не хешируете для шифрования данных, вы хэшируете для создания токена, который будет использоваться в качестве ключа для поиска более длинных значений.Таким образом, выбор алгоритма хеширования должен основываться на скорости.

"Вы бы вычислили хэш в коде или позволили бы его обработать БД?"

  • Если бы это былоВ моем проекте я выполняю хеширование на уровне приложения, а затем передаю его для поиска в хранилище (кэш, затем база данных).

"Существует ли радикально иной подход для хранения / поиска?длинные строки в базе данных? "

  • Как я уже упоминал, я думаю, что для вашей конкретной цели предложенное решение является хорошим.

Таблица рекомендаций (только для демонстрации):

user

  • id int (11) unsigned not null
  • name_first varchar (100) not null

user_agent_history

  • user_id int (11) без знака не нуль
  • agent_hash varchar (255) не нуль

agent

  • agent_hash varchar (255) не нулевой
  • browser varchar (100) не нулевой
  • agent текст не нулевой

Несколько заметок на ПКhema:

  • Из вашего OP звучит так, будто вам нужны отношения M: M между пользователем и агентом, поскольку пользователь может использовать Firefox с работы, но затем может переключитьсяна IE9 дома.Отсюда необходимость в сводной таблице.

  • Varchar (255), используемый для agent_hash, является предметом споров.MySQL предлагает использовать тип столбца varbinary для хранения хэшей, из которых существует несколько типов.

  • Я бы также предложил либо сделать agent_hash первичным ключом, либопо крайней мере, добавив к столбцу уникальное ограничение.

0 голосов
/ 13 января 2012

Ваша идея хэша - это звук.Я фактически использовал хеширование, чтобы ускорить поиск по миллионам записей.Хеш-индекс будет быстрее, так как каждая запись имеет одинаковый размер.md5, скорее всего, подойдет для вашего случая и даст вам самую короткую длину хеша.Если вас беспокоит коллизия хешей, вы можете добавить в него длину строки агента.

...