如何按照最左原则和B+树设计的联合索引

devtools/2024/10/25 14:19:49/

在数据库的联合索引中,最左原则(Leftmost Prefix Rule)指的是:当查询使用联合索引时,查询必须从索引的最左侧列开始才能有效利用索引。这是因为联合索引按列的顺序进行存储,如果跳过最左列,查询优化器将无法正确使用索引。

为了更好地解释这个概念,假设我们有一个包含三列 (A, B, C) 的联合索引 (A, B, C),联合索引的结构依赖于这些列的顺序。在查询时,必须首先使用 A 列,之后才能使用 BC 列。

下面是一个简单的 Java 代码实现,演示了如何通过最左原则来利用联合索引进行查询。

代码示例:联合索引最左原则的实现

import java.util.ArrayList;
import java.util.List;// 模拟数据库中的数据行
class TableRow {int colA;  // 第一列int colB;  // 第二列int colC;  // 第三列String data;public TableRow(int colA, int colB, int colC, String data) {this.colA = colA;this.colB = colB;this.colC = colC;this.data = data;}@Overridepublic String toString() {return "A: " + colA + ", B: " + colB + ", C: " + colC + ", Data: " + data;}
}// 模拟联合索引的 B+ 树节点
class BPlusTreeNode {boolean isLeaf;List<Integer> keysA;  // 第一列的索引(最左列)List<Integer> keysB;  // 第二列的索引List<Integer> keysC;  // 第三列的索引List<TableRow> rowData;public BPlusTreeNode(boolean isLeaf) {this.isLeaf = isLeaf;this.keysA = new ArrayList<>();this.keysB = new ArrayList<>();this.keysC = new ArrayList<>();this.rowData = new ArrayList<>();}// 插入到叶子节点中public void insert(int colA, int colB, int colC, TableRow row) {keysA.add(colA);keysB.add(colB);keysC.add(colC);rowData.add(row);}
}// 联合索引的 B+ 树
class BPlusTree {BPlusTreeNode root;public BPlusTree() {// 初始化一个空的 B+ 树根节点root = new BPlusTreeNode(true);}// 插入数据行到 B+ 树public void insert(int colA, int colB, int colC, TableRow row) {BPlusTreeNode leafNode = root;leafNode.insert(colA, colB, colC, row);}// 根据联合索引查找数据行,应用最左原则public List<TableRow> search(Integer colA, Integer colB, Integer colC) {List<TableRow> result = new ArrayList<>();BPlusTreeNode currentNode = root;// 应用最左原则,必须从 colA 开始for (int i = 0; i < currentNode.keysA.size(); i++) {boolean match = true;// 如果 colA 不为空,则要求匹配 A 列if (colA != null && !currentNode.keysA.get(i).equals(colA)) {match = false;}// 如果 colB 不为空且 colA 匹配,则要求匹配 B 列if (colB != null && match && !currentNode.keysB.get(i).equals(colB)) {match = false;}// 如果 colC 不为空且前两列匹配,则要求匹配 C 列if (colC != null && match && !currentNode.keysC.get(i).equals(colC)) {match = false;}// 如果匹配则将该数据行加入结果中if (match) {result.add(currentNode.rowData.get(i));}}return result;}
}// 模拟表类,创建数据行和联合索引
class Table {List<TableRow> rows;BPlusTree index;public Table() {this.rows = new ArrayList<>();this.index = new BPlusTree();}// 添加数据行并更新联合索引public void addRow(int colA, int colB, int colC, String data) {TableRow newRow = new TableRow(colA, colB, colC, data);rows.add(newRow);index.insert(colA, colB, colC, newRow);  // 插入到索引中}// 根据索引查找数据,必须遵循最左原则public List<TableRow> findByIndex(Integer colA, Integer colB, Integer colC) {return index.search(colA, colB, colC);}
}public class BPlusTreeExample {public static void main(String[] args) {// 创建表并插入数据Table myTable = new Table();myTable.addRow(1, 10, 100, "Row 1");myTable.addRow(2, 20, 200, "Row 2");myTable.addRow(1, 30, 300, "Row 3");myTable.addRow(2, 20, 400, "Row 4");// 根据联合索引查找数据System.out.println("Search (1, null, null):");List<TableRow> result1 = myTable.findByIndex(1, null, null);result1.forEach(System.out::println);System.out.println("\nSearch (2, 20, null):");List<TableRow> result2 = myTable.findByIndex(2, 20, null);result2.forEach(System.out::println);System.out.println("\nSearch (1, 30, 300):");List<TableRow> result3 = myTable.findByIndex(1, 30, 300);result3.forEach(System.out::println);System.out.println("\nSearch (null, 20, 200): (Should return nothing due to the left-most rule)");List<TableRow> result4 = myTable.findByIndex(null, 20, 200);result4.forEach(System.out::println);}
}

代码说明

  1. TableRow:表示表中的一行数据,包括三列 colA, colB, colC 和数据字段。

  2. BPlusTreeNode:用于模拟 B+ 树的节点,索引是由三列组成的联合索引。

  3. BPlusTree:用于管理 B+ 树的插入和查找操作。它根据最左原则从索引中查找行数据。

  4. Table:模拟一个简单的数据库表,包含表数据和 B+ 树索引。

  5. BPlusTreeExample:演示了如何根据最左原则进行查询,依次演示了不同的查询场景。

运行结果

Search (1, null, null):
A: 1, B: 10, C: 100, Data: Row 1
A: 1, B: 30, C: 300, Data: Row 3Search (2, 20, null):
A: 2, B: 20, C: 200, Data: Row 2
A: 2, B: 20, C: 400, Data: Row 4Search (1, 30, 300):
A: 1, B: 30, C: 300, Data: Row 3Search (null, 20, 200): (Should return nothing due to the left-most rule)

最左原则分析

  • 在联合索引 (A, B, C) 中,查询时必须先用 A 列来开始查找,才能利用索引。如果跳过 A 列而直接查 BC 列,索引就无法使用。

  • 在示例代码中,myTable.findByIndex(null, 20, 200) 将返回空结果,因为这违反了最左原则(没有使用 A 列),即使 BC 列匹配正确。

总结

  • 联合索引 必须遵循最左原则,必须从联合索引的最左列开始查询。
  • 优点:联合索引可以同时加速多列的查询,尤其是复杂的复合查询。
  • 缺点:当不使用最左列时,索引将无法被利用,可能导致性能下降。

http://www.ppmy.cn/devtools/128700.html

相关文章

MySQL 主从复制原理和配置流程

目录 一&#xff1a;MySQL 主从复制介绍二&#xff1a; 异步单线程主从复制1. 主服务器配置流程2. 从服务器配置 二&#xff1a;异步多线程主从复制1. 配置流程 一&#xff1a;MySQL 主从复制介绍 MySQL 主从复制是MySQL官方提供的一种数据备份容灾和负载均衡技术。 数据容灾&…

3D看车如何实现?全面解析其优势与特点

3D看车&#xff0c;作为汽车展示领域的一次革新&#xff0c;巧妙融合了三维建模与虚拟现实技术&#xff0c;为消费者带来前所未有的真实、立体观车体验。 一、3D看车的核心实现技术 三维建模技术&#xff1a; 通过高精度三维建模&#xff0c;精确复制汽车每一处细节&#xff…

【工具】新手礼包之git相关环境包括中文的一套流程{收集和整理},gitlab的使用

【工具】新手礼包之git相关环境包括中文的一套流程{收集和整理} git Git 详细安装教程&#xff08;详解 Git 安装过程的每一个步骤&#xff09; TortoiseGit 【TortoiseGit】TortoiseGit安装和配置详细说明

仕考网:2025年注册会计师考试报名

打算参加25年注册会计师的朋友们你真的做好准备了吗?如果是新手一定要提前了解这些! 1、时间节点安排: 报名时间:2025年4月8日8点-4月30日20点。 交费时间:2025年6月13日8点-6月28日20点。 准考证打印时间&#xff1a; 考试时间:2025年8月23日-25日。 2、考试科目难度 …

【MAC OS】rocketmq搭建可视化工具rocketmq-dashboard

【MAC OS】rocketmq搭建可视化工具rocketmq-dashboard 文章目录 【MAC OS】rocketmq搭建可视化工具rocketmq-dashboard一、安装1.安装dashboard2.将应用编译为可运行的 jar 包3.关闭dashborad 二、遇到的问题三、参考博客 一、安装 1.安装dashboard 官网&#xff1a;https://…

sortablejs(前端拖拽排序的实现)

源文档&#xff1a;sortablejs - npm 安装 npm install sortablejs --save 引入项目 import Sortable from sortablejs; 使用示例 <template><ul id"items"><li>item 1</li><li>item 2</li><li>item 3</li>&l…

新手向-C接口调用dbus

工作需要用c接口调用dbus&#xff0c;在这里写篇博客记录一下。 1. 方案比较 用C接口调用dbus一般来说有3种方案&#xff0c;分别是libdbus、GDBus&#xff08;GIO的一部分&#xff09;和sd-bus&#xff08;systemd的一部分&#xff09;&#xff0c;以下比较了3种方案的优劣&a…

Vue学习记录之十三 自定义指令directive

一、自定义指令的方法 Vue中有v-if、v-for、v-show、v-model等一些内置指令,其实我们也可以通过directive来自定义组件,但是他属于破坏性的更新。 必须以vNameOfDirective 的形式来命名本地自定义指令,以使得他们可以在模版中直接使用, 标签名称:v-NameofDirective 定义格…