Лучший первичный ключ для хранения URL-адресов

какой первичный ключ лучше всего подходит для хранения адресов веб-сайтов и URL-адресов страниц?

Чтобы избежать использования автоинкрементного идентификатора (который на самом деле не привязан к данным), я разработал схему с использованием подписи SHA1 URL-адреса в качестве первичного ключа.

Этот подход полезен во многих отношениях: например, мне не нужно читать last_id из базы данных, поэтому я могу подготовить все обновления таблицы с вычислением ключа и выполнить настоящее обновление за одну транзакцию. Нет нарушения ограничений.

В любом случае я прочитал две книги, которые говорят мне, что я ошибаюсь. В «Высокопроизводительном MySQL» сказано, что случайный ключ не подходит для оптимизатора БД. Более того, в каждой книге Джо Селко говорится, что первичный ключ должен быть частью данных.

Возникает вопрос: естественные ключи для URL-адресов - это ... сами URL-адреса. Дело в том, что если для сайта он короткий (www.something.com), ограничений для URL-адреса нет (см. http://www.boutell.com/newfaq/misc/urllength.html).

Представьте, что мне нужно хранить (и работать) с несколькими миллионами из них.

Тогда какой ключ лучше? Автоинкрементные идентификаторы, URL-адреса, хеши URL-адресов?


person spider    schedule 17.09.2010    source источник
comment
Я думаю, это будет во многом зависеть от того, что еще вы делаете с этими URL-адресами, шаблонами доступа и т. Д. Использование SHA1 должно быть защищено от коллизий, где более короткая хеш-функция (например, CRC32), очевидно, неуместна, но коллизии могут все еще возможно, тебе просто не повезет.   -  person Damien_The_Unbeliever    schedule 17.09.2010


Ответы (3)


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

Что касается того, какие еще столбцы и индексы вам нужны, это, как всегда, зависит от того, как вы собираетесь их использовать.

Столбец, в котором хранится хэш каждого URL-адреса, является отличной идеей практически для любого приложения, использующего значительное количество URL-адресов. Это делает ВЫБОР URL-адреса по его полному тексту настолько быстрым, насколько это возможно. Второе преимущество заключается в том, что если вы сделаете этот столбец УНИКАЛЬНЫМ, вам не нужно беспокоиться о том, чтобы сделать столбец, в котором хранится фактический URL-адрес, уникальным, и вы можете использовать REPLACE INTO и INSERT IGNORE как простые и быстрые операции атомарной записи.

Я бы добавил, что для этой цели прекрасно подходит встроенная в MySQL функция MD5 (). Его единственный недостаток в том, что специализированный злоумышленник может вызвать коллизии, которые, я уверен, вам наплевать. Использование встроенной функции значительно упрощает, например, некоторые типы соединений. Передача полного URL-адреса по сети может быть немного медленнее («ВЫБРАТЬ URL-адрес ИЗ URL-адресов WHERE hash = MD5 ('verylongurl')» вместо «WHERE hash = '32charhexstring'»), но у вас будет возможность сделать это, если хочешь. Если вы не можете придумать конкретный сценарий, в котором MD5 () вас подведет, не стесняйтесь его использовать.

Трудный вопрос заключается в том, нужно ли и как вам искать URL-адреса способами, отличными от их полного текста: например, хотите ли вы найти все URL-адреса, начинающиеся с «/ foo», на любом хосте «bar.com»? Хотя «LIKE '% bar.com% / foo%'» будет работать при тестировании, он потерпит неудачу при масштабировании. Если ваши потребности включают такие вещи, вы можете придумать творческие способы создания индексов, отличных от UNIQUE, нацеленных на нужный вам тип данных ... может быть, столбец domain_name для начала. Вам почти наверняка придется заполнять эти столбцы из вашего приложения (триггеры и хранимые процедуры - намного больше проблем, чем они того стоят, особенно если вас беспокоит производительность - не беспокойтесь).

Хорошая новость в том, что реляционные базы данных очень гибки для такого рода вещей. Вы всегда можете добавить новые столбцы и заполнить их позже. Я бы посоветовал для начала: int unsigned auto_increment первичный ключ, уникальный хэш-символ (32) и (при условии, что символов 64К достаточно) текстовый URL.

person Jamie McCarthy    schedule 17.09.2010
comment
+1 - наличие более широких первичных ключей серьезно сказывается на производительности, что хорошо задокументировано командой SQL и по большей части игнорируется большинством разработчиков. - person TomTom; 17.09.2010
comment
Зачем хранить хеши в шестнадцатеричной форме, а не в десятичной? - person Gary Lindahl; 15.09.2011

Предположительно, вы говорите обо всем URL-адресе, а не только об имени хоста, включая параметры CGI и прочее.

SHA-1 хеширование URL-адресов делает все ключи длинными и делает решение проблем довольно непонятным. Один раз мне пришлось использовать индексы для хешей, чтобы скрыть некоторые конфиденциальные данные, сохранив при этом возможность соединения двух таблиц, и производительность была низкой.

Есть два возможных подхода. Один наивен и очевиден; он действительно будет хорошо работать в mySQL. У него есть такие преимущества, как простота и возможность использовать URL-адрес LIKE 'any%' для эффективного поиска.

Но если у вас много URL-адресов, сосредоточенных в нескольких доменах ... например ....

http://stackoverflow.com/questions/3735390/best-primary-key-for-storing-urls
http://stackoverflow.com/questions/3735391/how-to-add-a-c-compiler-flag-to-extconf-rb

и т. д. вы смотрите на индексы, которые различаются только последними символами. В этом случае вы можете рассмотреть возможность хранения и индексации URL-адресов с обратным порядком их символов. Это может привести к более эффективному доступу к индексу.

(В продукте Oracle Table Server есть встроенный способ сделать это с так называемым обратным индексом.)

На вашем месте я бы избегал ключа автоинкремента, если вам не нужно соединять более двух таблиц ON TABLE_A.URL = TABLE_B.URL или какое-либо другое условие соединения с таким видом измерения.

person O. Jones    schedule 17.09.2010
comment
Один из способов повысить производительность объединений по хешам - добавить второй индексированный столбец с более концентрированной версией хеш-данных. BIGINT с первыми 64 битами MD5 может быть проиндексирован более эффективно, чем CHAR (32). Столкновения будут в миллионы раз более частыми, то есть чрезвычайно редкими. Ваш WHERE может объединяться в обоих столбцах (WHERE t1.inthash = t2.inthash AND t1.charhash = t2.charhash), и в чрезвычайно редком случае столкновения BIGINT полный хеш гарантирует, что вы все равно получите правильный ответ. - person Jamie McCarthy; 17.09.2010

Зависит от того, как вы используете стол. Если вы в основном выбираете с помощью WHERE url='<url>', тогда нормально иметь таблицу с одним столбцом. Если вы можете использовать идентификатор автоинкремента для идентификации URL во всех местах вашего приложения, тогда используйте автоинкремент

person Bozho    schedule 17.09.2010