sql >> Database teknologi >  >> RDS >> Mysql

bedste måde at gemme url i mysql til en læse- og skriveintensiv applikation

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.



  1. Hvad er databasebrugerrettigheder?

  2. PHP - Gør min forespørgsels arrays nøgle til ID

  3. indsæt poster i flere tabeller i php

  4. Adminer – Et avanceret webbaseret databaseadministrationsværktøj til Linux