Mysql

InnoDB、雜湊表、參考表和分片

  • July 17, 2013

我有一大串儲存在數據庫中的域和 URL,大約有 150M 域和 300M URL,我使用 InnoDB 以以下格式儲存每個域:

CREATE TABLE IF NOT EXISTS `domains_list` (
 `id` int(10) unsigned NOT NULL DEFAULT '0',
 `domain` varchar(350) DEFAULT NULL
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

這很好。新記錄的分配實際上是自動增量,因此沒有碎片,插入按升序排列。

然而,當新數據進入時(通常在 250K 和 2M 行之間),我使用兩個單獨的“雜湊”表來查看域或 URL 是否已經存在於數據庫中。嚴格來說,它不是一個“雜湊”表,只是我使用的一堆 MD5 來確保值是唯一的,並且表的附加好處是固定長度。該表也是分區的。

CREATE TABLE IF NOT EXISTS `domains_hashes` (
 `id` int(10) unsigned NOT NULL,
 `segment` tinyint(3) unsigned NOT NULL,
 `hash` binary(15) NOT NULL,
 PRIMARY KEY (`segment`,`hash`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (segment)
(PARTITION p0 VALUES LESS THAN (1) ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN (2) ENGINE = InnoDB,
...
PARTITION p254 VALUES LESS THAN (255) ENGINE = InnoDB,
PARTITION p255 VALUES LESS THAN (256) ENGINE = InnoDB) */;

segment基本上是散列的第一個字元,用於分區。剩下的 15 個字節進入hash.

為了查看數據庫中是否已經存在一堆域,這工作得相對較好,但是,由於插入的隨機性,表會變得碎片化。

雜湊表基本上只用於插入和快速查找數據庫中是否存在域。在插入期間,腳本從 0-255 遍歷並執行必要的檢查。

我的問題是,您知道更好的程序以更好地處理插入/選擇嗎?我相信當我開始使用這個數據庫時,我只是在 domain_list.domain 上有一個鍵,這很慢。

我發現重新組織分區時查找速度非常快,但是在多次批量插入之後,相同的查找速度會有所降低。伺服器有 32GB 的 RAM,我使用 16GB 作為緩衝池,而表本身佔用了 5.4GB 的磁碟空間。

想到了幾個想法:

雜湊表可以是記憶體表,一旦插入完成,您就可以將不存在的域複製到永久 domain_list 表中。將新數據保存在記憶體中還可能使雜湊表和 domain_list 表之間的域名比較變得更快。

另一種選擇是使用innodb_file_per_table選項並將數據庫(idb)文件保存在更快的磁碟上。

第三種選擇是將整個數據集載入到記憶體表中,然後使用ALTER TABLE table_name ENGINE=InnoDB. 這將比直接插入 InnoDB 快得多。這是可能的,因為您可以控制插入數據的方式和時間。

引用自:https://dba.stackexchange.com/questions/46490