Jeg har beskæftiget mig indgående med dette, og min generelle filosofi er at bruge brugshyppighedsmetoden. Det er besværligt, men det giver dig mulighed for at køre nogle fantastiske analyser på dataene:
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;
Som en generel regel vil du have lignende stier på et enkelt domæne, men forskellige QueryStrings for hver sti.
Jeg har oprindeligt designet dette til at have alle dele indekseret i en enkelt tabel (protokol, domæne, sti, forespørgselsstreng), men jeg synes, at ovenstående er mindre pladskrævende og giver bedre mulighed for at få bedre data ud af det.
text
har tendens til at være langsom, så du kan ændre "Path" til en varchar efter nogen brug. De fleste servere dør efter ca. 1K for en URL, men jeg har set nogle store og ville fejle ved ikke at miste data.
Din hentningsforespørgsel er besværlig, men hvis du abstraherer den i din kode, er der ingen problemer:
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;
Gem et portnummer, hvis det ikke er standard (ikke-80 for http, ikke-443 for https), ellers gem det som NULL for at angive, at det ikke skal inkluderes. (Du kan tilføje logikken til MySQL, men det bliver meget grimmere.)
Jeg ville altid (eller aldrig) fjerne "/" fra stien såvel som "?" fra QueryString for pladsbesparelser. Kun tab ville være i stand til at skelne mellem
http://www.example.com/
http://www.example.com/?
Hvilket, hvis det er vigtigt, så ville jeg ændre dit greb for aldrig at fjerne det og bare inkludere det. Teknisk set
http://www.example.com
http://www.example.com/
Er de samme, så det er altid OK at fjerne sti-skråstregen.
Så for at parse:
http://www.example.com/my/path/to/my/file.php?id=412&crsource=google+adwords
Vi ville bruge noget som parse_url
i PHP for at producere:
array(
[scheme] => 'http',
[host] => 'www.example.com',
[path] => '/my/path/to/my/file.php',
[query] => 'id=412&crsource=google+adwords',
)
Du vil derefter kontrollere/indsætte (med passende låse, ikke vist):
SELECT D.ID FROM Domain D
WHERE
D.Protocol=0
AND D.Domain='www.example.com'
AND D.Port IS NULL
(hvis den ikke findes)
INSERT INTO Domain (
Protocol, Domain, Port
) VALUES (
0, 'www.example.com', NULL
);
Så har vi vores $DomainID
fremadrettet...
Indsæt derefter i DomainPath:
SELECT DP.ID FORM DomainPath DP WHERE
DP.Domain=$DomainID AND Path='/my/path/to/my/file.php';
(hvis det ikke findes, indsæt det på samme måde)
Så har vi vores $DomainPathID
fremadrettet...
SELECT U.ID FROM URL
WHERE
DomainPath=$DomainPathID
AND QueryString='id=412&crsource=google+adwords'
og indsæt om nødvendigt.
Lad mig nu bemærke vigtigt , at ovenstående ordning vil være langsom for højtydende websteder. Du bør ændre alt for at bruge en hash af en slags for at fremskynde SELECT
s. Kort sagt er teknikken sådan:
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'));
Jeg har bevidst fjernet det fra ovenstående for at holde det simpelt, men at sammenligne en TEXT med en anden TEXT for markeringer er langsom og går i stykker for virkelig lange forespørgselsstrenge. Brug heller ikke et indeks med fast længde, da det også går i stykker. For strenge med vilkårlig længde, hvor nøjagtigheden er vigtig, er en hash-fejlrate acceptabel.
Til sidst, hvis du kan, skal du udføre MD5-hash-klientsiden for at gemme at sende store klatter til serveren for at udføre MD5-handlingen. De fleste moderne sprog understøtter MD5 indbygget:
SELECT ID FROM Foo WHERE Hash=UNHEX('82fd4bcf8b686cffe81e937c43b5bfeb');
Men jeg afviger.