sql >> Database >  >> RDS >> Mysql

beste manier om url op te slaan in mysql voor een lees- en schrijfintensieve toepassing

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.



  1. PHP MySQL-triggers - Hoe variabelen doorgeven om te activeren?

  2. 1064, je hebt een fout in je SQL-syntaxis;... Python MySQL

  3. Automatische verwijdering van vastgelopen processen in MS SQL Server

  4. Hoe geef ik een []slice door aan een IN-voorwaarde in een voorbereide SQL-instructie met ook niet-IN-voorwaarden?