MyRocks之bloom filter
title: MySQL · mysql · myrocks之Bloom filter
author: 張遠
Bloom filter 簡介
Bloom filter用於判斷一個元素是不是在一個集合裏,當一個元素被加入集合時,通過k個散列函數將這個元素映射成一個位數組中的k個點,把它們置為1。檢索時如果這些點有任何一個為0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。這就是布隆過濾器的基本思想。
優點:布隆過濾器存儲空間和插入/查詢時間都是常數O(k)。
缺點:有一定的誤算率,同時標準的Bloom Filter不支持刪除操作。
Bloom Filter通過極少的錯誤換取了存儲空間的極大節省。
設集合元素個數為n,數組大小為m, 散列函數個數為k
有一個規律是當 k=m/n*ln2 時,誤算率最低。參考Bloom_filter wiki
rocksdb與bloom filter
rocksdb中memtable和SST file都屬於集合類數據且不需要刪除數據,比較適合於Bloom filter.
rocksdb memtable和SST file都支持bloom filter, memtable 的bloom filter數組就存儲在內存中,而SST file的bloom filter持久化在bloom filter中.
- SST Bloom filter
SST Boomfilter 在Flush生成SST files時通過計算產生,分為兩個階段- 將prefix_extrator指定的key前綴加入到HASH表hash_entries_中
- 將hash_entries_所有映射到Bloom filter的數組中
SST Bloom filter相關參數有
filter_policy=bloomfilter:10:false;
whole_key_filtering=0
prefix_extractor=capped:24
partition_filters=false
其中prefix_extractor=capped:24, 表示最多取前綴24個字節,另外還有fixed:n方式表示隻取前綴n個字節,忽略小於n個字節的key. 具體可參考CappedPrefixTransform,FixedPrefixTransform
filter_policy=bloomfilter:10:false;其中bits_per_key_=10, bits_per_key_實際就是前麵公式k=m/n*ln2 中的m/n. 從而如下計算k即num_probes_的方式
void initialize() {
// We intentionally round down to reduce probing cost a little bit
num_probes_ = static_cast<size_t>(bits_per_key_ * 0.69); // 0.69 =~ ln(2)
if (num_probes_ < 1) num_probes_ = 1;
if (num_probes_ > 30) num_probes_ = 30;
}
use_block_based_builder_表示是使用block base filter還是full filter
partition_filters 表示時否使用partitioned filter,SST數據有序排列,按block_size進行分區後在生產filter,index_on_filter block存儲分區範圍. 開啟partition_filters 需配置index_type =kTwoLevelIndexSearch
filter 參數優先級如下 block base > partitioned > full. 比如說同時指定use_block_based_builder_=true和partition_filters=true實際使用的block based filter
whole_key_filtering,取值true, 表示增加全key的filter. 它和前綴filter並不衝突可以共存。
- memtable Bloom filter
memtable 在每次Add數據時都會更新Bloom filter. Bloom filter提供參數memtable_prefix_bloom_size_ratio,其值不超過0.25, Bloom filter數組大小為write_buffer_size* memtable_prefix_bloom_size_ratio. memtable Bloom filter 中的num_probes_取值硬編碼為6
另外參數cache_index_and_filter_blocks可以讓filter信息緩存在block cache中。
MyRocks和bloom filter
在myrocks中,Bloom filter是全局的,設置了Bloom filter後,所有表都有Bloom filter。Bloom filter和索引是綁定在一起的。也就是說,表在查詢過程中,如果可以用到某個索引,且設置了Bloom filter,那麼就有可能會用到索引的Bloom filter.
MyRocks可以使用Bloom filter的條件如下,詳見函數can_use_bloom_filter
- 必須是索引前綴或索引全列的等值查詢
- 等值前綴的長度應該符合prefix_extrator的約定
我們可以通過以下兩個status變量來觀察Bloom filter使用情況
rocksdb_bloom_filter_prefix_checked:是否使用了Bloom filter
rocksdb_bloom_filter_prefix_useful:使用Bloom filter判斷出不存在
rocksdb_bloom_filter_useful:BlockBasedTable::Get接口使用Bloom filter判斷出不存在
設置參數rocksdb_skip_bloom_filter_on_read可以讓查詢不使用Bloom filter。
示例
最後給個示例
參數設置如下,使用partitioned filter
rocksdb_default_cf_options=write_buffer_size=64k;block_based_table_factory={filter_policy=bloomfilter:10:false;whole_key_filtering=0;partition_filters=true;index_type=kTwoLevelIndexSearch};prefix_extractor=capped:24
SQL
CREATE TABLE t1 (id1 INT, id2 VARCHAR(100), id3 BIGINT, value INT, PRIMARY KEY (id1, id2, id3)) ENGINE=rocksdb collate latin1_bin;
let $i = 1;
while ($i <= 10000) {
let $insert = INSERT INTO t1 VALUES($i, $i, $i, $i);
inc $i;
eval $insert;
}
# case 1: 等值條件prefix長度 < 24, 用不Bbloom filter
select variable_value into @c from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_checked';
select variable_value into @u from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_useful';
select count(*) from t1 WHERE id1=100 and id2 ='10';
count(*)
0
select (variable_value-@c) > 0 from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_checked';
(variable_value-@c) > 0
0
select (variable_value-@u) > 0 from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_useful';
(variable_value-@u) > 0
0
# case 2: 符合使用Bbloom filter的條件,且成功判斷出不存在
select variable_value into @c from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_checked';
select variable_value into @u from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_useful';
select count(*) from t1 WHERE id1=100 and id2 ='00000000000000000000';
count(*)
0
select (variable_value-@c) > 0 from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_checked';
(variable_value-@c) > 0
1
select (variable_value-@u) > 0 from information_schema.global_status where variable_name='rocksdb_bloom_filter_prefix_useful';
(variable_value-@u) > 0
1
最後更新:2017-09-04 10:32:33