Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

cara terbaik untuk menyimpan url di mysql untuk aplikasi intensif baca&tulis

Saya telah membahas ini secara ekstensif, dan filosofi umum saya adalah menggunakan metode frekuensi penggunaan. Ini rumit, tetapi memungkinkan Anda menjalankan beberapa analitik hebat pada data:

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;

Sebagai aturan umum, Anda akan memiliki Jalur yang serupa pada satu Domain, tetapi QueryStrings yang berbeda untuk setiap jalur.

Awalnya saya merancang ini agar semua bagian diindeks dalam satu tabel (Protokol, Domain, Jalur, String Kueri) tetapi menurut saya hal di atas kurang memakan ruang dan lebih baik untuk mendapatkan data yang lebih baik darinya.

text cenderung lambat, sehingga Anda dapat mengubah "Jalur" menjadi varchar setelah digunakan. Sebagian besar server mati setelah sekitar 1K untuk sebuah URL, tetapi saya telah melihat beberapa yang besar dan akan berbuat salah di sisi tidak kehilangan data.

Permintaan pengambilan Anda rumit, tetapi jika Anda mengabstraksikannya dalam kode Anda, tidak ada masalah:

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;

Simpan nomor port jika tidak standar (non-80 untuk http, non-443 untuk https), jika tidak, simpan sebagai NULL untuk menandakan itu tidak boleh disertakan. (Anda dapat menambahkan logika ke MySQL tetapi menjadi jauh lebih buruk.)

Saya akan selalu (atau tidak pernah) menghapus "/" dari Path serta "?" dari QueryString untuk menghemat ruang. Hanya kehilangan yang bisa membedakan antara

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

Yang, jika penting, maka saya akan mengubah taktik Anda untuk tidak pernah menghapusnya dan hanya memasukkannya. Secara teknis,

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

Sama, jadi menghapus garis miring Path tidak masalah.

Jadi, untuk menguraikan:

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

Kami akan menggunakan sesuatu seperti parse_url di PHP untuk menghasilkan:

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

Anda kemudian akan memeriksa/menyisipkan (dengan kunci yang sesuai, tidak ditampilkan):

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

(jika tidak ada)

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

Kami kemudian memiliki $DomainID maju...

Kemudian masukkan ke DomainPath:

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

(jika tidak ada, masukkan dengan cara yang sama)

Kami kemudian memiliki $DomainPathID maju...

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

dan masukkan jika perlu.

Sekarang, izinkan saya mencatat penting , bahwa skema di atas akan lambat untuk situs berkinerja tinggi. Anda harus memodifikasi semuanya untuk menggunakan semacam hash untuk mempercepat SELECT s. Singkatnya, tekniknya seperti:

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

Saya sengaja menghilangkannya dari atas untuk membuatnya tetap sederhana, tetapi membandingkan TEXT dengan TEXT lain untuk pemilihan lambat, dan istirahat untuk string kueri yang sangat panjang. Jangan gunakan indeks dengan panjang tetap karena itu juga akan rusak. Untuk string panjang sewenang-wenang di mana akurasi penting, tingkat kegagalan hash dapat diterima.

Terakhir, jika Anda bisa, lakukan sisi klien hash MD5 untuk menghemat pengiriman gumpalan besar ke server untuk melakukan operasi MD5. Sebagian besar bahasa modern mendukung built-in MD5:

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

Tapi saya ngelantur.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara mengganti nama database MySQL

  2. Memperbarui skema tabel tanpa memengaruhi data di Laravel

  3. Apa kerugian menggunakan bidang berukuran teks panjang MySQL ketika setiap entri akan muat dalam bidang berukuran teks sedang?

  4. Kekurangan mengutip bilangan bulat dalam kueri Mysql?

  5. Masalah UTF-8 PHP/MySQL