跳到主要内容Java 实现 B+ 树:节点分裂合并与范围查询优化 | 极客日志Javajava算法
Java 实现 B+ 树:节点分裂合并与范围查询优化
综述由AI生成B+ 树在 Java 中的实现,涵盖节点结构定义、叶子节点与内部节点的分裂及合并策略。重点阐述了范围查询的优化方案,包括叶子节点链表遍历、预取机制、并行查询以及缓存优化。此外,还讨论了批量插入优化、并发控制(读写锁)、数据库索引配置及性能测试方法,为构建高性能索引结构提供了实践参考。
追风少年3.5K 浏览 一、B+ 树核心数据结构
1. 节点结构定义
public abstract class BPlusTreeNode<K extends Comparable<K>, V> {
protected boolean isLeaf;
protected int degree;
protected List<K> keys;
protected BPlusTreeNode<K, V> parent;
public abstract int size();
public abstract boolean isFull();
public abstract boolean isUnderflow();
public abstract int getMinKeys();
}
public class InternalNode<K extends Comparable<K>, V> extends BPlusTreeNode<K, V> {
private List<BPlusTreeNode<K, V>> children;
{
.degree = degree;
.isLeaf = ;
.keys = <>(degree);
.children = <>(degree + );
.parent = ;
}
{
keys.size();
}
{
keys.size() >= degree - ;
}
{
keys.size() < Math.ceil(degree / ) - ;
}
{
() Math.ceil(degree / ) - ;
}
}
<K <K>, V> <K, V> {
List<V> values;
LeafNode<K, V> next;
LeafNode<K, V> prev;
{
.degree = degree;
.isLeaf = ;
.keys = <>(degree - );
.values = <>(degree - );
.next = ;
.prev = ;
}
{
keys.size();
}
{
keys.size() >= degree - ;
}
{
keys.size() < Math.ceil((degree - ) / );
}
{
() Math.ceil((degree - ) / );
}
{
;
keys.size() - ;
(left <= right) {
left + (right - left) / ;
keys.get(mid).compareTo(key);
(cmp == ) {
mid;
} (cmp < ) {
left = mid + ;
} {
right = mid - ;
}
}
-left - ;
}
}
public
InternalNode
(int degree)
this
this
false
this
new
ArrayList
this
new
ArrayList
1
this
null
@Override
public
int
size
()
return
@Override
public
boolean
isFull
()
return
1
@Override
public
boolean
isUnderflow
()
return
2.0
1
@Override
public
int
getMinKeys
()
return
int
2.0
1
public
class
LeafNode
extends
Comparable
extends
BPlusTreeNode
private
private
private
public
LeafNode
(int degree)
this
this
true
this
new
ArrayList
1
this
new
ArrayList
1
this
null
this
null
@Override
public
int
size
()
return
@Override
public
boolean
isFull
()
return
1
@Override
public
boolean
isUnderflow
()
return
1
2.0
@Override
public
int
getMinKeys
()
return
int
1
2.0
public
int
findKeyIndex
(K key)
int
left
=
0
int
right
=
1
while
int
mid
=
2
int
cmp
=
if
0
return
else
if
0
1
else
1
return
1
二、节点分裂策略
1. 叶子节点分裂
public class BPlusTree<K extends Comparable<K>, V> {
private BPlusTreeNode<K, V> root;
private int degree;
private LeafNode<K, V> head;
private void splitLeafNode(LeafNode<K, V> leafNode) {
LeafNode<K, V> newLeaf = new LeafNode<>(degree);
int splitIndex = leafNode.size() / 2;
for (int i = splitIndex; i < leafNode.size(); i++) {
newLeaf.keys.add(leafNode.keys.get(i));
newLeaf.values.add(leafNode.values.get(i));
}
for (int i = leafNode.size() - 1; i >= splitIndex; i--) {
leafNode.keys.remove(i);
leafNode.values.remove(i);
}
newLeaf.next = leafNode.next;
if (leafNode.next != null) {
leafNode.next.prev = newLeaf;
}
leafNode.next = newLeaf;
newLeaf.prev = leafNode;
K newKey = newLeaf.keys.get(0);
insertIntoParent(leafNode, newKey, newLeaf);
}
private void insertIntoParent(BPlusTreeNode<K, V> leftChild, K key, BPlusTreeNode<K, V> rightChild) {
if (leftChild.parent == null) {
createNewRoot(leftChild, key, rightChild);
return;
}
InternalNode<K, V> parent = (InternalNode<K, V>) leftChild.parent;
int insertIndex = findInsertIndex(parent.keys, key);
parent.keys.add(insertIndex, key);
parent.children.add(insertIndex + 1, rightChild);
rightChild.parent = parent;
if (parent.isFull()) {
splitInternalNode(parent);
}
}
private void createNewRoot(BPlusTreeNode<K, V> leftChild, K key, BPlusTreeNode<K, V> rightChild) {
InternalNode<K, V> newRoot = new InternalNode<>(degree);
newRoot.keys.add(key);
newRoot.children.add(leftChild);
newRoot.children.add(rightChild);
leftChild.parent = newRoot;
rightChild.parent = newRoot;
this.root = newRoot;
}
}
2. 内部节点分裂
public class BPlusTree<K extends Comparable<K>, V> {
private void splitInternalNode(InternalNode<K, V> node) {
InternalNode<K, V> newNode = new InternalNode<>(degree);
int splitIndex = node.size() / 2;
K promoteKey = node.keys.get(splitIndex);
for (int i = splitIndex + 1; i < node.size(); i++) {
newNode.keys.add(node.keys.get(i));
}
for (int i = splitIndex + 1; i < node.children.size(); i++) {
BPlusTreeNode<K, V> child = node.children.get(i);
newNode.children.add(child);
child.parent = newNode;
}
for (int i = node.size() - 1; i >= splitIndex; i--) {
node.keys.remove(i);
}
for (int i = node.children.size() - 1; i >= splitIndex + 1; i--) {
node.children.remove(i);
}
if (node.parent == null) {
createNewRoot(node, promoteKey, newNode);
} else {
InternalNode<K, V> parent = (InternalNode<K, V>) node.parent;
int insertIndex = findInsertIndex(parent.keys, promoteKey);
parent.keys.add(insertIndex, promoteKey);
parent.children.add(insertIndex + 1, newNode);
newNode.parent = parent;
if (parent.isFull()) {
splitInternalNode(parent);
}
}
}
private int findInsertIndex(List<K> keys, K key) {
int left = 0;
int right = keys.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
int cmp = keys.get(mid).compareTo(key);
if (cmp < 0) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
}
三、节点合并策略
1. 叶子节点合并
public class BPlusTree<K extends Comparable<K>, V> {
private void mergeLeafNodes(LeafNode<K, V> node) {
if (node.prev != null && node.prev.parent == node.parent) {
LeafNode<K, V> leftSibling = node.prev;
if (leftSibling.size() > leftSibling.getMinKeys()) {
borrowFromLeftSibling(node, leftSibling);
return;
}
}
if (node.next != null && node.next.parent == node.parent) {
LeafNode<K, V> rightSibling = node.next;
if (rightSibling.size() > rightSibling.getMinKeys()) {
borrowFromRightSibling(node, rightSibling);
return;
}
}
if (node.prev != null && node.prev.parent == node.parent) {
mergeWithLeftSibling(node);
} else if (node.next != null && node.next.parent == node.parent) {
mergeWithRightSibling(node);
}
}
private void borrowFromLeftSibling(LeafNode<K, V> node, LeafNode<K, V> leftSibling) {
int lastIndex = leftSibling.size() - 1;
K borrowedKey = leftSibling.keys.get(lastIndex);
V borrowedValue = leftSibling.values.get(lastIndex);
leftSibling.keys.remove(lastIndex);
leftSibling.values.remove(lastIndex);
node.keys.add(0, borrowedKey);
node.values.add(0, borrowedValue);
updateParentSeparator(node, borrowedKey);
}
private void borrowFromRightSibling(LeafNode<K, V> node, LeafNode<K, V> rightSibling) {
K borrowedKey = rightSibling.keys.get(0);
V borrowedValue = rightSibling.values.get(0);
rightSibling.keys.remove(0);
rightSibling.values.remove(0);
node.keys.add(borrowedKey);
node.values.add(borrowedValue);
updateParentSeparator(rightSibling, rightSibling.keys.get(0));
}
private void mergeWithLeftSibling(LeafNode<K, V> node) {
LeafNode<K, V> leftSibling = node.prev;
for (int i = 0; i < node.size(); i++) {
leftSibling.keys.add(node.keys.get(i));
leftSibling.values.add(node.values.get(i));
}
leftSibling.next = node.next;
if (node.next != null) {
node.next.prev = leftSibling;
}
InternalNode<K, V> parent = (InternalNode<K, V>) node.parent;
int indexInParent = findChildIndex(parent, node);
parent.keys.remove(indexInParent - 1);
parent.children.remove(indexInParent);
if (parent.isUnderflow()) {
if (parent == root && parent.size() == 0) {
root = leftSibling;
leftSibling.parent = null;
} else {
mergeInternalNodes(parent);
}
}
}
}
2. 内部节点合并
public class BPlusTree<K extends Comparable<K>, V> {
private void mergeInternalNodes(InternalNode<K, V> node) {
InternalNode<K, V> parent = (InternalNode<K, V>) node.parent;
int nodeIndex = findChildIndex(parent, node);
if (nodeIndex > 0) {
InternalNode<K, V> leftSibling = (InternalNode<K, V>) parent.children.get(nodeIndex - 1);
if (leftSibling.size() > leftSibling.getMinKeys()) {
borrowFromLeftInternalSibling(node, leftSibling, parent, nodeIndex);
return;
}
}
if (nodeIndex < parent.children.size() - 1) {
InternalNode<K, V> rightSibling = (InternalNode<K, V>) parent.children.get(nodeIndex + 1);
if (rightSibling.size() > rightSibling.getMinKeys()) {
borrowFromRightInternalSibling(node, rightSibling, parent, nodeIndex);
return;
}
}
if (nodeIndex > 0) {
mergeWithLeftInternalSibling(node, parent, nodeIndex);
} else {
mergeWithRightInternalSibling(node, parent, nodeIndex);
}
}
private void borrowFromLeftInternalSibling(InternalNode<K, V> node, InternalNode<K, V> leftSibling, InternalNode<K, V> parent, int nodeIndex) {
K parentKey = parent.keys.get(nodeIndex - 1);
BPlusTreeNode<K, V> borrowedChild = leftSibling.children.remove(leftSibling.children.size() - 1);
K borrowedKey = leftSibling.keys.remove(leftSibling.keys.size() - 1);
node.keys.add(0, parentKey);
node.children.add(0, borrowedChild);
borrowedChild.parent = node;
parent.keys.set(nodeIndex - 1, borrowedKey);
}
private void mergeWithLeftInternalSibling(InternalNode<K, V> node, InternalNode<K, V> parent, int nodeIndex) {
InternalNode<K, V> leftSibling = (InternalNode<K, V>) parent.children.get(nodeIndex - 1);
K parentKey = parent.keys.get(nodeIndex - 1);
leftSibling.keys.add(parentKey);
for (K key : node.keys) {
leftSibling.keys.add(key);
}
for (BPlusTreeNode<K, V> child : node.children) {
leftSibling.children.add(child);
child.parent = leftSibling;
}
parent.keys.remove(nodeIndex - 1);
parent.children.remove(nodeIndex);
if (parent.isUnderflow()) {
if (parent == root && parent.size() == 0) {
root = leftSibling;
leftSibling.parent = null;
} else {
mergeInternalNodes(parent);
}
}
}
}
四、范围查询优化
1. 叶子节点链表遍历
public class BPlusTree<K extends Comparable<K>, V> {
public List<V> rangeQuery(K startKey, K endKey) {
List<V> results = new ArrayList<>();
LeafNode<K, V> startNode = findLeafNode(startKey);
if (startNode == null) {
return results;
}
int startIndex = startNode.findKeyIndex(startKey);
if (startIndex < 0) {
startIndex = -startIndex - 1;
}
LeafNode<K, V> currentNode = startNode;
int currentIndex = startIndex;
while (currentNode != null) {
while (currentIndex < currentNode.size()) {
K currentKey = currentNode.keys.get(currentIndex);
if (currentKey.compareTo(endKey) > 0) {
return results;
}
results.add(currentNode.values.get(currentIndex));
currentIndex++;
}
currentNode = currentNode.next;
currentIndex = 0;
}
return results;
}
public List<V> rangeQueryWithPrefetch(K startKey, K endKey, int batchSize) {
List<V> results = new ArrayList<>();
LeafNode<K, V> currentNode = findLeafNode(startKey);
int currentIndex = 0;
List<LeafNode<K, V>> prefetchedNodes = prefetchNodes(currentNode, batchSize);
while (!prefetchedNodes.isEmpty()) {
for (LeafNode<K, V> node : prefetchedNodes) {
int start = binarySearchInNode(node, startKey);
int end = binarySearchInNode(node, endKey);
if (start < 0) start = -start - 1;
if (end < 0) end = -end - 2;
for (int i = start; i <= end && i < node.size(); i++) {
results.add(node.values.get(i));
}
if (end < node.size() - 1 && node.keys.get(end + 1).compareTo(endKey) > 0) {
return results;
}
}
currentNode = prefetchedNodes.get(prefetchedNodes.size() - 1).next;
prefetchedNodes = prefetchNodes(currentNode, batchSize);
}
return results;
}
private List<LeafNode<K, V>> prefetchNodes(LeafNode<K, V> startNode, int count) {
List<LeafNode<K, V>> nodes = new ArrayList<>();
LeafNode<K, V> current = startNode;
for (int i = 0; i < count && current != null; i++) {
nodes.add(current);
current = current.next;
}
return nodes;
}
}
2. 并行范围查询
public class ParallelBPlusTree<K extends Comparable<K>, V> extends BPlusTree<K, V> {
private ExecutorService executor;
public List<V> parallelRangeQuery(K startKey, K endKey, int numThreads) {
long estimatedSize = estimateRangeSize(startKey, endKey);
if (estimatedSize < 1000) {
return super.rangeQuery(startKey, endKey);
}
List<RangeTask> tasks = splitRange(startKey, endKey, numThreads);
List<Future<List<V>>> futures = new ArrayList<>();
for (RangeTask task : tasks) {
futures.add(executor.submit(() -> executeRangeQuery(task.startKey, task.endKey)));
}
List<V> results = new ArrayList<>();
for (Future<List<V>> future : futures) {
try {
results.addAll(future.get());
} catch (Exception e) {
}
}
return results;
}
private List<RangeTask> splitRange(K startKey, K endKey, int numSplits) {
List<RangeTask> tasks = new ArrayList<>();
List<LeafNode<K, V>> leafNodes = getLeafNodesInRange(startKey, endKey);
int nodesPerTask = Math.max(1, leafNodes.size() / numSplits);
for (int i = 0; i < leafNodes.size(); i += nodesPerTask) {
int endIndex = Math.min(i + nodesPerTask, leafNodes.size());
List<LeafNode<K, V>> taskNodes = leafNodes.subList(i, endIndex);
K taskStartKey = taskNodes.get(0).keys.get(0);
K taskEndKey = taskNodes.get(taskNodes.size() - 1)
.keys.get(taskNodes.get(taskNodes.size() - 1).size() - 1);
tasks.add(new RangeTask(taskStartKey, taskEndKey, taskNodes));
}
return tasks;
}
private static class RangeTask {
K startKey;
K endKey;
List<LeafNode<K, V>> nodes;
RangeTask(K startKey, K endKey, List<LeafNode<K, V>> nodes) {
this.startKey = startKey;
this.endKey = endKey;
this.nodes = nodes;
}
}
}
3. 缓存优化策略
public class CachedBPlusTree<K extends Comparable<K>, V> extends BPlusTree<K, V> {
private LinkedHashMap<K, CacheEntry> cache;
private final int cacheSize;
public CachedBPlusTree(int degree, int cacheSize) {
super(degree);
this.cacheSize = cacheSize;
this.cache = new LinkedHashMap<K, CacheEntry>(cacheSize, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, CacheEntry> eldest) {
return size() > cacheSize;
}
};
}
@Override
public V get(K key) {
CacheEntry entry = cache.get(key);
if (entry != null) {
return entry.value;
}
V value = super.get(key);
if (value != null) {
cache.put(key, new CacheEntry(value, System.currentTimeMillis()));
}
return value;
}
@Override
public List<V> rangeQuery(K startKey, K endKey) {
List<V> results = new ArrayList<>();
preloadCache(startKey, endKey);
LeafNode<K, V> currentNode = findLeafNode(startKey);
while (currentNode != null) {
for (int i = 0; i < currentNode.size(); i++) {
K currentKey = currentNode.keys.get(i);
if (currentKey.compareTo(endKey) > 0) {
return results;
}
CacheEntry cached = cache.get(currentKey);
if (cached != null) {
results.add(cached.value);
} else {
V value = currentNode.values.get(i);
results.add(value);
cache.put(currentKey, new CacheEntry(value, System.currentTimeMillis()));
}
}
currentNode = currentNode.next;
}
return results;
}
private void preloadCache(K startKey, K endKey) {
List<K> sampleKeys = sampleKeysInRange(startKey, endKey, 100);
for (K key : sampleKeys) {
V value = super.get(key);
if (value != null) {
cache.put(key, new CacheEntry(value, System.currentTimeMillis()));
}
}
}
private static class CacheEntry {
V value;
long timestamp;
CacheEntry(V value, long timestamp) {
this.value = value;
this.timestamp = timestamp;
}
}
}
五、性能优化策略
1. 批量插入优化
public class OptimizedBPlusTree<K extends Comparable<K>, V> extends BPlusTree<K, V> {
public void bulkInsert(List<Pair<K, V>> data) {
if (data.isEmpty()) return;
data.sort(Comparator.comparing(Pair::getKey));
List<LeafNode<K, V>> leafNodes = buildLeafNodesInBatch(data);
buildIndexInBatch(leafNodes);
updateRootFromLeaves(leafNodes);
}
private List<LeafNode<K, V>> buildLeafNodesInBatch(List<Pair<K, V>> data) {
List<LeafNode<K, V>> leafNodes = new ArrayList<>();
LeafNode<K, V> currentLeaf = new LeafNode<>(degree);
for (Pair<K, V> entry : data) {
currentLeaf.keys.add(entry.getKey());
currentLeaf.values.add(entry.getValue());
if (currentLeaf.isFull()) {
leafNodes.add(currentLeaf);
currentLeaf = new LeafNode<>(degree);
}
}
if (!currentLeaf.keys.isEmpty()) {
leafNodes.add(currentLeaf);
}
for (int i = 0; i < leafNodes.size() - 1; i++) {
leafNodes.get(i).next = leafNodes.get(i + 1);
leafNodes.get(i + 1).prev = leafNodes.get(i);
}
return leafNodes;
}
private void buildIndexInBatch(List<LeafNode<K, V>> leafNodes) {
List<InternalNode<K, V>> currentLevel = new ArrayList<>();
for (int i = 0; i < leafNodes.size(); i += degree) {
InternalNode<K, V> parent = new InternalNode<>(degree);
int end = Math.min(i + degree, leafNodes.size());
for (int j = i; j < end; j++) {
LeafNode<K, V> leaf = leafNodes.get(j);
parent.children.add(leaf);
leaf.parent = parent;
if (j > i) {
parent.keys.add(leaf.keys.get(0));
}
}
currentLevel.add(parent);
}
while (currentLevel.size() > 1) {
currentLevel = buildNextLevel(currentLevel);
}
if (!currentLevel.isEmpty()) {
root = currentLevel.get(0);
}
}
}
2. 并发控制
public class ConcurrentBPlusTree<K extends Comparable<K>, V> extends BPlusTree<K, V> {
private final ReadWriteLock globalLock = new ReentrantReadWriteLock();
private final Map<BPlusTreeNode<K, V>, ReadWriteLock> nodeLocks = new ConcurrentHashMap<>();
@Override
public void insert(K key, V value) {
globalLock.readLock().lock();
try {
LeafNode<K, V> leaf = findLeafNode(key);
lockNode(leaf, false);
if (!leaf.isFull()) {
insertIntoLeaf(leaf, key, value);
unlockNode(leaf);
return;
}
lockNode(leaf.parent, false);
splitAndInsert(leaf, key, value);
unlockNode(leaf.parent);
unlockNode(leaf);
} finally {
globalLock.readLock().unlock();
}
}
public List<V> optimisticRangeQuery(K startKey, K endKey) {
List<V> results = new ArrayList<>();
int retries = 3;
while (retries-- > 0) {
try {
long startVersion = getTreeVersion();
results = doRangeQuery(startKey, endKey);
long endVersion = getTreeVersion();
if (startVersion == endVersion) {
return results;
}
results.clear();
} catch (ConcurrentModificationException e) {
}
}
return pessimisticRangeQuery(startKey, endKey);
}
private void lockNode(BPlusTreeNode<K, V> node, boolean readOnly) {
ReadWriteLock lock = nodeLocks.computeIfAbsent(node, n -> new ReentrantReadWriteLock());
if (readOnly) {
lock.readLock().lock();
} else {
lock.writeLock().lock();
}
}
private void unlockNode(BPlusTreeNode<K, V> node) {
ReadWriteLock lock = nodeLocks.get(node);
if (lock != null) {
if (lock.writeLock().isHeldByCurrentThread()) {
lock.writeLock().unlock();
} else {
lock.readLock().unlock();
}
}
}
}
六、应用场景与配置建议
1. 数据库索引配置
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
created_at TIMESTAMP,
INDEX idx_name (name),
INDEX idx_email (email)
) ENGINE=InnoDB
ROW_FORMAT=DYNAMIC
KEY_BLOCK_SIZE=16
innodb_page_size=16K
innodb_buffer_pool_size=1G
innodb_purge_threads=4
2. 文件系统实现
public class BPlusTreeFileSystem {
private BPlusTree<String, FileMetadata> index;
private BlockManager blockManager;
public List<FileMetadata> listFiles(String prefix) {
return index.rangeQuery(prefix, prefix + Character.MAX_VALUE);
}
public PageResult<FileMetadata> listFilesPaged(
String prefix, int page, int pageSize) {
LeafNode<String, FileMetadata> startNode = index.findLeafNode(prefix);
Cursor cursor = new Cursor(startNode, prefix);
List<FileMetadata> pageData = new ArrayList<>();
for (int i = 0; i < pageSize && cursor.hasNext(); i++) {
pageData.add(cursor.next());
}
String nextStartKey = cursor.hasNext() ? cursor.peek().getKey() : null;
return new PageResult<>(pageData, page, pageSize, nextStartKey);
}
}
3. 性能测试与监控
public class BPlusTreeBenchmark {
public void benchmark() {
int[] degrees = {16, 32, 64, 128};
int[] dataSizes = {1000, 10000, 100000, 1000000};
for (int degree : degrees) {
for (int size : dataSizes) {
testInsertPerformance(degree, size);
testQueryPerformance(degree, size);
testRangeQueryPerformance(degree, size);
testSplitMergeOverhead(degree, size);
}
}
}
private void testRangeQueryPerformance(int degree, int size) {
BPlusTree<Integer, String> tree = new BPlusTree<>(degree);
for (int i = 0; i < size; i++) {
tree.insert(i, "value" + i);
}
int[] rangeSizes = {10, 100, 1000, 10000};
for (int rangeSize : rangeSizes) {
long startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) {
int start = i % (size - rangeSize);
int end = start + rangeSize;
tree.rangeQuery(start, end);
}
long duration = System.nanoTime() - startTime;
System.out.printf("Degree=%d, Size=%d, Range=%d: %.2f ops/ms\n", degree, size, rangeSize, 1000.0 / (duration / 1_000_000.0));
}
}
}
七、总结
B+ 树的核心优势:
- 分裂合并策略:
- 分裂:当节点满时,将其分成两个节点并提升中间 key
- 合并:当节点元素过少时,与兄弟节点合并或借用元素
- 保证树的高度平衡和空间利用率
- 范围查询优化:
- 叶子节点链表支持顺序遍历
- 缓存和预取减少磁盘 IO
- 并行查询充分利用多核 CPU
- 游标支持分页查询
- 性能优化技术:
- 批量操作减少树的重组
- 细粒度并发控制
- 缓存热点数据
- 自适应分裂阈值
实际应用建议:
- 选择合适的度(degree):
- 内存数据库:较小的度(16-64)
- 磁盘数据库:较大的度(64-256),匹配页大小
- SSD:中等度(32-128)
- 监控与调优:
- 监控树的高度和节点填充率
- 定期重组优化空间利用率
- 根据负载模式调整缓存策略
- 现代改进:
- 考虑 B* 树(减少分裂频率)
- 支持 SSD 的 B+ 树变种
- 结合 LSM 树处理写入密集型负载
B+ 树作为经典的数据结构,通过精心设计的分裂合并策略和范围查询优化,在数据库索引和文件系统中仍然发挥着重要作用。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online