Как хранить URL-адреса в MySQL

Мне нужно хранить потенциально 100 миллионов URL-адресов в базе данных. Каждый URL-адрес должен быть уникальным, поэтому я буду использовать ON DUPLICATE KEY UPDATE и подсчитать повторяющиеся URL-адреса.

Однако я не могу создать индекс в поле URL, так как мое поле varchar составляет 400 символов. MySQL жалуется и говорит; "# 1071 - Указанный ключ слишком длинный, максимальная длина ключа - 767 байт". (Varchar 400 займет 1200 байт)

Каков наилучший способ сделать это, если вам нужно обработать минимальные 500 000 URL-адресов в день на одном сервере?

Мы уже думаем, используя MongoDB для того же приложения, поэтому мы можем просто запросить MongoDB и найти дубликат URL-адреса и обновить строку. Тем не менее, я не сторонник решения этой проблемы с использованием MongoDB, и я хотел бы использовать только MySQL на этом этапе, поскольку я хотел бы быть как можно более легким в начале и быстрее завершить этот раздел проекта. (Мы еще не играли с MongoDB и не хотим тратить время на этом этапе)

Есть ли другая возможность сделать это, используя меньше ресурсов и времени. Я думал, чтобы получить хеш MD5 URL-адреса и сохранить его. И я могу сделать это поле УНИКАЛЬНЫМ. Я знаю, будет столкновение, но вполне нормально иметь 5-10-20 дубликатов в 100 миллионах URL-адресов, если это единственная проблема.

Есть ли у вас предложения? Я также не хочу тратить 10 секунд, чтобы вставить только один URL-адрес, так как он будет обрабатывать URL-адреса 500 тыс. В день.

Что бы вы предложили?

Изменить: согласно запросу это определение таблицы. (Я не использую MD5 на данный момент, это для тестирования)

mysql> DESC url;
+-------------+-----------------------+------+-----+-------------------+-----------------------------+
| Field       | Type                  | Null | Key | Default           | Extra                       |
+-------------+-----------------------+------+-----+-------------------+-----------------------------+
| url_id      | int(11) unsigned      | NO   | PRI | NULL              | auto_increment              |
| url_text    | varchar(400)          | NO   |     |                   |                             |
| md5         | varchar(32)           | NO   | UNI |                   |                             |
| insert_date | timestamp             | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| count       | mediumint(9) unsigned | NO   |     | 0                 |                             |
+-------------+-----------------------+------+-----+-------------------+-----------------------------+
5 rows in set (0.00 sec)

Ответ 1

В соответствии с спецификацией DNS максимальная длина имени домена:

Сам DNS помещает только одно ограничение на конкретные метки
которые могут использоваться для идентификации записей ресурсов. Это одно ограничение относится к длине ярлыка и имени. Длина любая одна метка ограничена от 1 до 63 октетов. Полный домен
имя ограничено 255 октетами (включая разделители).

255 * 3 = 765 < 767 (Только едва:-))

Однако обратите внимание, что каждый компонент может содержать только 63 символа.

Итак, я бы предложил нарезать url в биты компонента.

Использование http://foo.example.com/a/really/long/path?with=lots&of=query&parameters=that&goes=on&forever&and=ever

Возможно, это было бы адекватно:

  • флаг протокола [ "http" → 0] (сохранить "http" как 0, "https" как 1 и т.д.)
  • subdomain [ "foo" ] (255 - 63 = 192 символа: я мог бы вычесть еще 2, потому что min tld - 2 символа)
  • домен [ "example" ], (63 символа)
  • tld [ "com" ] (4 символа для обработки "info" tld)
  • path [ "a/really/long/path" ] (пока вы хотите - сохранить в отдельной таблице)
  • queryparameters [ "with = lots & of = query & parameters = that & go = on & forever & and = ever" ] (хранить в отдельной таблице ключей/значений)
  • номер порта/аутентификация, который редко используется, может быть в отдельной таблице с ключами, если это действительно необходимо.

Это дает вам приятные преимущества:

  • Индекс находится только на частях URL-адреса, которые вам нужно искать (меньший индекс!)
  • запросы могут быть ограничены различными частями URL (например, каждый URL-адрес в домене facebook).
  • любой URL-адрес, который слишком длинный, поддомен/домен является поддельным
  • легко отбрасывать параметры запроса.
  • легко сделать нечувствительное к регистру имя домена /tld поиск
  • отказаться от синтаксического сахара ( "://" после протокола "." между субдоменом/доменом, доменом /tld, "/" между tld и path, "?" перед запросом "&" "=" в запрос)
  • Избегает проблемы с большой разреженной таблицей. Большинство URL-адресов не будут иметь параметров запроса или длинных путей. Если эти поля находятся в отдельной таблице, ваша основная таблица не будет принимать размер. При выполнении запросов больше записей будет вписываться в память, что приведет к более быстрой работе с запросами.
  • (здесь больше преимуществ).

Ответ 2

Чтобы индексировать поле шириной до 767 символов, оно должно быть ascii или аналогичным, оно не может быть utf8, поскольку оно использует 3 байта на char, поэтому максимальный для индексированных полей utf-8 равен 255

Конечно, поле 767 ascii url, превзошло ваши первоначальные спецификации 400 символов. Конечно, некоторые URL-адреса превышают лимит 767. Возможно, вы можете хранить и индексировать первые 735 символов плюс хеш md5. Вы также можете иметь текстовое поле full_url для сохранения исходного значения.
Обратите внимание, что ascii charset достаточно хорош для URL-адресов

Ответ 3

Хорошо сформированный URL-адрес может содержать только символы в диапазоне ASCII - другие символы должны быть закодированы. Таким образом, предполагая, что URL-адреса, которые вы собираетесь хранить, хорошо сформированы (а если нет, вы можете исправить их до вставки их в базу данных), вы можете определить свой символ столбца url_text, установленный в ASCII (latin1 в MySQL). С ASCII один char представляет собой один байт, и вы сможете индексировать все 400 символов, как вы хотите.

Ответ 4

Вероятности ложного столкновения с MD5 (128 бит) могут быть сформулированы следующим образом:

"Если у вас есть 9 триллионов разных предметов, в 9 триллионах есть только один шанс, что два из них имеют тот же MD5".

Чтобы выразить это другим способом, он, скорее всего, попадет в метеор, выиграв мега-лотерею.

Ответ 5

Вы можете изменить url_text из VarChar (400) в текст, затем вы можете добавить полный текстовый индекс к нему, чтобы вы могли искать наличие URL-адреса перед его вставкой.