Ik heb dit uitgebreid behandeld en mijn algemene filosofie is om de methode van gebruiksfrequentie te gebruiken. Het is omslachtig, maar je kunt er geweldige analyses mee uitvoeren op de gegevens:
CREATE TABLE URL (
ID integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
DomainPath integer unsigned NOT NULL,
QueryString text
) Engine=MyISAM;
CREATE TABLE DomainPath (
ID integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
Domain integer unsigned NOT NULL,
Path text,
UNIQUE (Domain,Path)
) Engine=MyISAM;
CREATE TABLE Domain (
ID integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
Protocol tinyint NOT NULL,
Domain varchar(64)
Port smallint NULL,
UNIQUE (Protocol,Domain,Port)
) Engine=MyISAM;
Als algemene regel heb je vergelijkbare paden op een enkel domein, maar verschillende QueryStrings voor elk pad.
Ik heb dit oorspronkelijk ontworpen om alle onderdelen in een enkele tabel te laten indexeren (Protocol, Domein, Pad, Query String), maar ik denk dat het bovenstaande minder ruimte-intensief is en beter geschikt is om er betere gegevens uit te halen.
text
heeft de neiging traag te zijn, dus je kunt "Pad" na enig gebruik veranderen in een varchar. De meeste servers sterven na ongeveer 1K voor een URL, maar ik heb een aantal grote gezien en zou de fout maken om geen gegevens te verliezen.
Uw ophaalverzoek is omslachtig, maar als u het abstraheert in uw code, geen probleem:
SELECT CONCAT(
IF(D.Protocol=0,'http://','https://'),
D.Domain,
IF(D.Port IS NULL,'',CONCAT(':',D.Port)),
'/', DP.Path,
IF(U.QueryString IS NULL,'',CONCAT('?',U.QueryString))
)
FROM URL U
INNER JOIN DomainPath DP ON U.DomainPath=DP.ID
INNER JOIN Domain D on DP.Domain=D.ID
WHERE U.ID=$DesiredID;
Sla een poortnummer op als het niet standaard is (niet-80 voor http, niet-443 voor https), sla het anders op als NULL om aan te geven dat het niet moet worden opgenomen. (Je kunt de logica toevoegen aan de MySQL, maar het wordt veel lelijker.)
Ik zou altijd (of nooit) de "/" van het pad verwijderen, evenals de "?" van de QueryString voor ruimtebesparing. Alleen verlies zou onderscheid kunnen maken tussen
http://www.example.com/
http://www.example.com/?
Wat, als het belangrijk is, ik je overstag zou veranderen om het nooit te strippen en het gewoon op te nemen. Technisch,
http://www.example.com
http://www.example.com/
Zijn hetzelfde, dus het verwijderen van de pad-slash is altijd OK.
Dus, om te ontleden:
http://www.example.com/my/path/to/my/file.php?id=412&crsource=google+adwords
We zouden zoiets gebruiken als parse_url
in PHP om te produceren:
array(
[scheme] => 'http',
[host] => 'www.example.com',
[path] => '/my/path/to/my/file.php',
[query] => 'id=412&crsource=google+adwords',
)
U zou dan controleren/invoegen (met de juiste sloten, niet getoond):
SELECT D.ID FROM Domain D
WHERE
D.Protocol=0
AND D.Domain='www.example.com'
AND D.Port IS NULL
(indien niet bestaat)
INSERT INTO Domain (
Protocol, Domain, Port
) VALUES (
0, 'www.example.com', NULL
);
We hebben dan onze $DomainID
vooruit gaan...
Voeg vervolgens in DomainPath in:
SELECT DP.ID FORM DomainPath DP WHERE
DP.Domain=$DomainID AND Path='/my/path/to/my/file.php';
(als het niet bestaat, voeg het dan op dezelfde manier in)
We hebben dan onze $DomainPathID
vooruit gaan...
SELECT U.ID FROM URL
WHERE
DomainPath=$DomainPathID
AND QueryString='id=412&crsource=google+adwords'
en indien nodig invoegen.
Laat me nu belangrijk opmerken , dat het bovenstaande schema traag zal zijn voor sites met hoge prestaties. Je moet alles aanpassen om een soort hash te gebruiken om SELECT
te versnellen s. Kortom, de techniek is als volgt:
CREATE TABLE Foo (
ID integer unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT,
Hash varbinary(16) NOT NULL,
Content text
) Type=MyISAM;
SELECT ID FROM Foo WHERE Hash=UNHEX(MD5('id=412&crsource=google+adwords'));
Ik heb het met opzet uit het bovenstaande verwijderd om het simpel te houden, maar het vergelijken van een TEKST met een andere TEKST voor selecties is traag en breekt voor echt lange queryreeksen. Gebruik ook geen index met een vaste lengte, want die zal ook breken. Voor strings van willekeurige lengte waarbij nauwkeurigheid belangrijk is, is een hash-foutpercentage acceptabel.
Ten slotte, als je kunt, doe dan de MD5-hash-clientzijde om te voorkomen dat je grote blobs naar de server stuurt om de MD5-bewerking uit te voeren. De meeste moderne talen ondersteunen ingebouwde MD5:
SELECT ID FROM Foo WHERE Hash=UNHEX('82fd4bcf8b686cffe81e937c43b5bfeb');
Maar ik dwaal af.