Mysql
 sql >> Baza danych >  >> RDS >> Mysql

najlepszy sposób na przechowywanie adresu URL w mysql dla aplikacji intensywnie odczytujących i zapisujących

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ę.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Brak pobierania listy schematów ze źródła podczas migracji z MSSQL do MySQL przy użyciu Workbencha

  2. Relacje Laravel na stole z dwoma rodzajami flag

  3. Korzystanie z ról Nowość w MySQL 8

  4. Sprawdzone metody:śledzenie wyświetleń banerów

  5. Jak sprawdzić, czy tabela MySQL jest UTF-8 i ma storageEngine InnoDB?