Я много занимался этим, и моя общая философия - использовать метод частоты использования. Это громоздко, но позволяет вам проводить отличную аналитику данных:
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;
Как правило, у вас будут одинаковые пути в одном домене, но разные строки запросов для каждого пути.
Первоначально я разработал это для того, чтобы все части были проиндексированы в одной таблице (Протокол, Домен, Путь, Строка запроса), но я считаю, что вышеупомянутое требует меньше места и позволяет лучше получать из него более качественные данные.
text
имеет тенденцию быть медленным, поэтому вы можете изменить «Путь» на varchar после некоторого использования. Большинство серверов умирают примерно за 1 КБ для URL, но я видел несколько крупных и ошибаюсь из-за того, что не теряю данные.
Ваш поисковый запрос громоздок, но если вы абстрагируете его в своем коде, нет проблем:
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;
Сохраните номер порта, если он нестандартный (не-80 для http, не-443 для https), в противном случае сохраните его как NULL, чтобы указать, что он не должен быть включен. (Вы можете добавить логику в MySQL, но она становится намного ужаснее.)
Я бы всегда (или никогда) убирал "/" с Пути, а также "?" из QueryString для экономии места. Только потеря могла бы отличить
http://www.example.com/
http://www.example.com/?
Что, если важно, то я бы изменил тэкс, чтобы он никогда не раздевался и просто включал его. Технически,
http://www.example.com
http://www.example.com/
То же самое, поэтому удаление косой черты в пути всегда в порядке.
Итак, для разбора:
http://www.example.com/my/path/to/my/file.php?id=412&crsource=google+adwords
Мы будем использовать что-то вроде parse_url
в PHP для получения:
array(
[scheme] => 'http',
[host] => 'www.example.com',
[path] => '/my/path/to/my/file.php',
[query] => 'id=412&crsource=google+adwords',
)
Затем вы должны проверить / вставить (с соответствующими блокировками, не показаны):
SELECT D.ID FROM Domain D
WHERE
D.Protocol=0
AND D.Domain='www.example.com'
AND D.Port IS NULL
(если не существует)
INSERT INTO Domain (
Protocol, Domain, Port
) VALUES (
0, 'www.example.com', NULL
);
Затем у нас есть $DomainID
, идущие вперед ...
Затем вставьте в DomainPath:
SELECT DP.ID FORM DomainPath DP WHERE
DP.Domain=$DomainID AND Path='/my/path/to/my/file.php';
(если он не существует, вставьте его аналогично)
Затем у нас есть $DomainPathID
, идущие вперед ...
SELECT U.ID FROM URL
WHERE
DomainPath=$DomainPathID
AND QueryString='id=412&crsource=google+adwords'
и вставьте, если необходимо.
Теперь позвольте мне отметить , что важно , что приведенная выше схема будет медленной для высокопроизводительных сайтов. Вы должны изменить все, чтобы использовать какой-то хеш, чтобы ускорить SELECT
с. Короче, техника такая:
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'));
Я намеренно исключил его из вышеперечисленного, чтобы упростить его, но сравнение ТЕКСТА с другим ТЕКСТОМ для выборок идет медленно и разрывается для действительно длинных строк запроса. Также не используйте индекс фиксированной длины, потому что он также сломается. Для строк произвольной длины, где важна точность, допустима частота сбоев хеша.
Наконец, если вы можете, сделайте MD5-хеш-клиентскую часть, чтобы сохранить отправку больших двоичных объектов на сервер для выполнения операции MD5. Большинство современных языков поддерживают встроенный MD5:
SELECT ID FROM Foo WHERE Hash=UNHEX('82fd4bcf8b686cffe81e937c43b5bfeb');
Но я отвлекся.