Mysql
 sql >> база данни >  >> RDS >> Mysql

най-добрият начин за съхраняване на url в mysql за приложение с интензивно четене и запис

Занимавал съм се подробно с това и моята обща философия е да използвам метода на честотата на употреба. Това е тромаво, но ви позволява да извършвате страхотни анализи на данните:

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;

Като общо правило ще имате подобни пътища в един домейн, но различни QueryStrings за всеки път.

Първоначално проектирах това, за да има всички части, индексирани в една таблица (протокол, домейн, път, низ на заявка), но смятам, че горното е по-малко пространство-интензивно и дава възможност за по-добро извличане на по-добри данни от него.

text има тенденция да е бавен, така че можете да промените "Path" на varchar след известно използване. Повечето сървъри умират след около 1K за 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');

Но се отклонявам.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL-Cluster не успява да се стартира

  2. FindByUUID() с помощта на JPA хранилището на Spring Data

  3. Стойността BIGINT UNSIGNED е извън обхвата

  4. Миграция на SQL Server 2008 R2 към MySQL

  5. Експортирайте база данни с MySQL Workbench с оператори INSERT