InnoDB、雜湊表、參考表和分片
我有一大串儲存在數據庫中的域和 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 快得多。這是可能的,因為您可以控制插入數據的方式和時間。