Най-добрият първичен ключ за съхраняване на URL адреси

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

За да избегна използването на автоинкрементален идентификатор (който всъщност не е обвързан с данните), проектирах схемата с използването на SHA1 подпис на URL като първичен ключ.

Този подход е полезен по много начини: например не е необходимо да чета last_id от базата данни, за да мога да подготвя всички актуализации на таблицата, като изчислявам ключа и да направя истинската актуализация в една транзакция. Няма нарушение на ограниченията.

Както и да е, прочетох две книги, които ми казват, че греша. В "High performance MySQL" се казва, че произволният ключ не е добър за DB оптимизатора. Освен това във всяка книга на Джо Челко той казва, че първичният ключ трябва да бъде част от данните.

Въпросът е: естествените ключове за URL адреси са... самите URL адреси. Факт е, че ако за даден сайт той е кратък (www.something.com), няма наложено ограничение за am 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 като прости, бързи атомарни операции за запис.

Бих добавил, че използването на вградената функция MD5() на MySQL е чудесно за тази цел. Единственият му недостатък е, че специализиран нападател може да предизвика сблъсъци, което съм напълно сигурен, че не ви интересува. Използването на вградената функция прави, например, някои видове обединения много по-лесни. Може да бъде малко по-бавно предаването на пълен URL адрес през кабела („SELECT url FROM urls WHERE hash=MD5('verylongurl')“ вместо „WHERE hash='32charhexstring'“), но ще имате опцията да направиш това, ако искаш. Освен ако не можете да измислите конкретен сценарий, при който MD5() ще ви разочарова, можете да го използвате.

Трудният въпрос е дали и как ще трябва да търсите URL адреси по начини, различни от пълния им текст: например, ще искате ли да намерите всички URL адреси, започващи с "/foo" на който и да е хост "bar.com"? Докато „КАТО '%bar.com%/foo%'“ ще работи при тестване, ще се провали мизерно в мащаб. Ако вашите нужди включват такива неща, можете да измислите творчески начини за генериране на не-УНИКАЛНИ индекси, насочени към типа данни, от които се нуждаете... може би колона име на домейн, за начало. Почти сигурно ще трябва да попълните тези колони от вашето приложение (тригерите и съхранените процедури създават много повече проблеми, отколкото си заслужават тук, особено ако сте загрижени за производителността - не си правете труда).

Добрата новина е, че релационните бази данни са много гъвкави за такива неща. Винаги можете да добавяте нови колони и да ги попълвате по-късно. Бих предложил за начало: int unsigned auto_increment първичен ключ, уникален хеш char(32) и (ако приемем, че са достатъчни 64K знака) текстов 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 КАТО „whatever%“ за ефективно търсене.

Но ако имате много 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 има вграден начин за извършване на това с така наречения обърнат индекс.)

Ако бях на ваше място, щях да избягвам ключ за автоматично увеличаване, освен ако не трябва да се присъедините към повече от две таблици 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 И t1.charhash=t2.charhash) и в изключително редкия случай на ГОЛЯМ сблъсък, пълният хеш ще гарантира, че все още получавате правилния отговор. - person Jamie McCarthy; 17.09.2010

Зависи как използвате таблицата. Ако избирате предимно с WHERE url='<url>', тогава е добре да имате таблица с една колона. Ако можете да използвате идентификатор за автоматично увеличаване, за да идентифицирате URL на всички места в приложението си, тогава използвайте автоматичното увеличение

person Bozho    schedule 17.09.2010