Zajmowałem się tym obszernie, a moją ogólną filozofią jest stosowanie metody częstotliwości użycia. Jest to kłopotliwe, ale umożliwia prowadzenie świetnych analiz danych:
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;
Z reguły będziesz mieć podobne ścieżki w jednej domenie, ale różne ciągi zapytań dla każdej ścieżki.
Pierwotnie zaprojektowałem to tak, aby wszystkie części były indeksowane w jednej tabeli (protokół, domena, ścieżka, ciąg zapytań), ale myślę, że powyższe zajmuje mniej miejsca i pozwala lepiej uzyskać z niego lepsze dane.
text
zwykle jest powolny, więc po pewnym czasie możesz zmienić „Ścieżkę” na varchar. Większość serwerów umiera po około 1K dla adresu URL, ale widziałem kilka dużych i popełniłem błąd, nie tracąc danych.
Twoje zapytanie pobierania jest kłopotliwe, ale jeśli wyabstrahujesz je w kodzie, nie ma problemu:
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;
Przechowuj numer portu, jeśli jest niestandardowy (inny niż 80 dla http, inny niż-443 dla https), w przeciwnym razie zachowaj go jako NULL, aby zasygnalizować, że nie powinien być uwzględniony. (Możesz dodać logikę do MySQL, ale robi się znacznie brzydsza.)
Zawsze (lub nigdy) usuwałbym „/” ze Ścieżki, a także „?” z QueryString dla oszczędności miejsca. Tylko strata byłaby w stanie odróżnić
http://www.example.com/
http://www.example.com/?
Co, jeśli jest to ważne, zmieniłbym twoją taktykę, aby nigdy tego nie rozbierać i po prostu to włączać. Technicznie,
http://www.example.com
http://www.example.com/
Są takie same, więc usunięcie ukośnika ścieżki jest zawsze w porządku.
Tak więc, aby przeanalizować:
http://www.example.com/my/path/to/my/file.php?id=412&crsource=google+adwords
Używalibyśmy czegoś takiego jak parse_url
w PHP do produkcji:
array(
[scheme] => 'http',
[host] => 'www.example.com',
[path] => '/my/path/to/my/file.php',
[query] => 'id=412&crsource=google+adwords',
)
Następnie należy sprawdzić/wstawić (z odpowiednimi blokadami, nie pokazano):
SELECT D.ID FROM Domain D
WHERE
D.Protocol=0
AND D.Domain='www.example.com'
AND D.Port IS NULL
(jeśli nie istnieje)
INSERT INTO Domain (
Protocol, Domain, Port
) VALUES (
0, 'www.example.com', NULL
);
Mamy wtedy nasz $DomainID
dalej...
Następnie wstaw do DomainPath:
SELECT DP.ID FORM DomainPath DP WHERE
DP.Domain=$DomainID AND Path='/my/path/to/my/file.php';
(jeśli nie istnieje, wstaw go podobnie)
Mamy wtedy nasz $DomainPathID
dalej...
SELECT U.ID FROM URL
WHERE
DomainPath=$DomainPathID
AND QueryString='id=412&crsource=google+adwords'
i wstaw w razie potrzeby.
Teraz zaznaczę ważne , że powyższy schemat będzie powolny w przypadku witryn o wysokiej wydajności. Powinieneś zmodyfikować wszystko, aby użyć jakiegoś skrótu, aby przyspieszyć SELECT
s. W skrócie, technika wygląda tak:
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'));
Celowo wyeliminowałem go z powyższego, aby zachować prostotę, ale porównywanie TEKSTU z innym TEKSTEM w przypadku selekcji jest powolne i przerywa się w przypadku naprawdę długich ciągów zapytań. Nie używaj też indeksu o stałej długości, ponieważ to również się zepsuje. W przypadku ciągów o dowolnej długości, w których liczy się dokładność, współczynnik niepowodzeń haszowania jest akceptowalny.
Na koniec, jeśli możesz, wykonaj po stronie klienta mieszania MD5, aby zapisać wysyłanie dużych obiektów blob do serwera w celu wykonania operacji MD5. Większość współczesnych języków obsługuje wbudowaną wersję MD5:
SELECT ID FROM Foo WHERE Hash=UNHEX('82fd4bcf8b686cffe81e937c43b5bfeb');
Ale mam dygresję.