Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

cách tốt nhất để lưu trữ url trong mysql cho một ứng dụng chuyên sâu về đọc và ghi

Tôi đã giải quyết vấn đề này một cách rộng rãi, và triết lý chung của tôi là sử dụng phương pháp sử dụng tần suất. Nó cồng kềnh, nhưng nó cho phép bạn chạy một số phân tích tuyệt vời về dữ liệu:

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;

Theo nguyên tắc chung, bạn sẽ có các Đường dẫn tương tự trên một Tên miền, nhưng các Chuỗi truy vấn khác nhau cho mỗi đường dẫn.

Ban đầu, tôi thiết kế cái này để tất cả các phần được lập chỉ mục trong một bảng duy nhất (Giao thức, Tên miền, Đường dẫn, Chuỗi truy vấn) nhưng nghĩ rằng phần trên ít tốn dung lượng hơn và cho phép lấy dữ liệu tốt hơn.

text có xu hướng chậm, vì vậy bạn có thể thay đổi "Đường dẫn" thành một varchar sau một số lần sử dụng. Hầu hết các máy chủ chết sau khoảng 1K cho một URL, nhưng tôi đã thấy một số máy chủ lớn và sẽ gặp lỗi nếu không làm mất dữ liệu.

Truy vấn truy xuất của bạn rất phức tạp, nhưng nếu bạn tóm tắt nó trong mã của mình thì không có vấn đề gì:

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;

Lưu trữ số cổng nếu nó không chuẩn (không phải 80 cho http, không phải 443 cho https), nếu không hãy lưu trữ dưới dạng NULL để biểu thị rằng nó không nên được đưa vào. (Bạn có thể thêm logic vào MySQL nhưng nó trở nên xấu hơn nhiều.)

Tôi sẽ luôn (hoặc không bao giờ) loại bỏ "/" khỏi Đường dẫn cũng như "?" từ QueryString để tiết kiệm dung lượng. Chỉ có mất mát mới có thể phân biệt được đâu là

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

Mà, nếu quan trọng, thì tôi sẽ thay đổi hướng dẫn của bạn để không bao giờ tước nó và chỉ bao gồm nó. Về mặt kỹ thuật,

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

Giống nhau, vì vậy việc loại bỏ dấu gạch chéo trên Đường dẫn luôn luôn được chấp nhận.

Vì vậy, để phân tích cú pháp:

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

Chúng tôi sẽ sử dụng một cái gì đó như parse_url bằng PHP để sản xuất:

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

Sau đó, bạn sẽ kiểm tra / chèn (với ổ khóa thích hợp, không được hiển thị):

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

(nếu không tồn tại)

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

Sau đó, chúng tôi có $DomainID của chúng tôi tiếp tục ...

Sau đó, chèn vào DomainPath:

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

(nếu nó không tồn tại, hãy chèn nó tương tự)

Sau đó, chúng tôi có $DomainPathID của chúng tôi tiếp tục ...

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

và chèn nếu cần.

Bây giờ, hãy để tôi ghi chú quan trọng , rằng lược đồ trên sẽ chậm đối với các trang web hiệu suất cao. Bạn nên sửa đổi mọi thứ để sử dụng một số loại băm để tăng tốc SELECT S. Tóm lại, kỹ thuật này giống như:

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

Tôi đã cố tình loại bỏ nó khỏi những điều trên để giữ cho nó đơn giản, nhưng so sánh một TEXT với một TEXT khác cho các lựa chọn thì chậm và ngắt đối với các chuỗi truy vấn thực sự dài. Cũng đừng sử dụng chỉ mục có độ dài cố định vì điều đó cũng sẽ bị hỏng. Đối với các chuỗi có độ dài tùy ý mà độ chính xác quan trọng, tỷ lệ băm lỗi có thể chấp nhận được.

Cuối cùng, nếu bạn có thể, hãy thực hiện phía máy khách băm MD5 để lưu gửi các đốm màu lớn đến máy chủ để thực hiện thao tác MD5. Hầu hết các ngôn ngữ hiện đại đều hỗ trợ MD5 được tích hợp sẵn:

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

Nhưng tôi lạc đề.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Máy chủ 'xxx.xx.xxx.xxx' không được phép kết nối với máy chủ MySQL này

  2. trợ giúp với truy vấn qua bảng quan hệ

  3. Làm cách nào để lấy tên các cột cùng với tập kết quả trong php / mysql?

  4. Tại sao Eclipse đề xuất Đối tượng làm kiểu ánh xạ mặc định cho Văn bản kiểu dữ liệu?

  5. Không thể khôi phục bản sao lưu MYSQL vào Cơ sở dữ liệu mới