sql >> Databáze >  >> RDS >> Mysql

nejlepší způsob, jak uložit adresu URL v mysql pro aplikace náročné na čtení a zápis

Obsáhle jsem se tím zabýval a mou obecnou filozofií je používat metodu frekvence použití. Je to těžkopádné, ale umožňuje vám provádět skvělé analýzy dat:

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;

Obecně platí, že budete mít podobné cesty na jedné doméně, ale různé QueryString pro každou cestu.

Původně jsem to navrhl tak, aby byly všechny části indexovány v jediné tabulce (protokol, doména, cesta, řetězec dotazu), ale myslím si, že výše uvedené je méně náročné na prostor a lépe z toho získávají lepší data.

text má tendenci být pomalý, takže po nějakém použití můžete změnit "Cesta" na varchar. Většina serverů umírá po přibližně 1 kB pro adresu URL, ale viděl jsem několik velkých a udělal bych chybu, pokud bych neztratil data.

Váš dotaz na vyhledávání je těžkopádný, ale pokud jej v kódu abstrahujete, žádný problém:

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;

Uložte číslo portu, pokud není standardní (jiné než 80 pro http, jiné než 443 pro https), jinak jej uložte jako NULL, což znamená, že by nemělo být zahrnuto. (Logiku můžete přidat do MySQL, ale bude mnohem ošklivější.)

Vždy (nebo nikdy) bych odstranil "/" z cesty stejně jako "?" z QueryString pro úsporu místa. Pouze ztráta by byla schopna rozlišit mezi

http://www.example.com/
http://www.example.com/?

Což, je-li to důležité, pak bych změnil váš připínáček tak, abyste ho nikdy nesvlékali a pouze zahrnuli. Technicky,

http://www.example.com 
http://www.example.com/

Jsou stejné, takže odstranění lomítka cesty je vždy v pořádku.

Takže k analýze:

http://www.example.com/my/path/to/my/file.php?id=412&crsource=google+adwords

Použili bychom něco jako parse_url v PHP vytvořit:

array(
    [scheme] => 'http',
    [host] => 'www.example.com',
    [path] => '/my/path/to/my/file.php',
    [query] => 'id=412&crsource=google+adwords',
)

Potom byste zaškrtli/vložili (s příslušnými zámky, které nejsou zobrazeny):

SELECT D.ID FROM Domain D 
WHERE 
    D.Protocol=0 
    AND D.Domain='www.example.com' 
    AND D.Port IS NULL

(pokud neexistuje)

INSERT INTO Domain ( 
    Protocol, Domain, Port 
) VALUES ( 
    0, 'www.example.com', NULL 
);

Pak máme naše $DomainID vpřed...

Poté vložte do DomainPath:

SELECT DP.ID FORM DomainPath DP WHERE 
DP.Domain=$DomainID AND Path='/my/path/to/my/file.php';

(pokud neexistuje, vložte jej podobně)

Pak máme naše $DomainPathID vpřed...

SELECT U.ID FROM URL 
WHERE 
    DomainPath=$DomainPathID 
    AND QueryString='id=412&crsource=google+adwords'

a v případě potřeby vložte.

Nyní mi dovolte upozornit důležitě , že výše uvedené schéma bude pro vysoce výkonné weby pomalé. Vše byste měli upravit tak, aby se používal nějaký hash pro urychlení SELECT s. Stručně řečeno, technika je taková:

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'));

Záměrně jsem to odstranil z výše uvedeného, ​​aby to bylo jednoduché, ale porovnávání TEXTu s jiným TEXTem pro výběry je pomalé a přerušuje se pro opravdu dlouhé řetězce dotazů. Nepoužívejte ani index s pevnou délkou, protože by se také zlomil. Pro řetězce libovolné délky, kde záleží na přesnosti, je míra selhání hash přijatelná.

Nakonec, pokud můžete, proveďte hash MD5 na straně klienta, abyste si ušetřili odesílání velkých objektů BLOB na server za účelem provedení operace MD5. Většina moderních jazyků podporuje vestavěný MD5:

SELECT ID FROM Foo WHERE Hash=UNHEX('82fd4bcf8b686cffe81e937c43b5bfeb');

Ale to jsem odbočil.



  1. Maximální (použitelný) počet řádků v tabulce Postgresql

  2. jak seskupovat a počítat pomocí MySQL

  3. Jak uložím řetězec delší než 4000 znaků v databázi Oracle pomocí Java/JDBC?

  4. MySQL se dusí kudrnatými (inteligentními) uvozovkami