Skip to content

OceanBase 索引类型与选择

索引基本概念

索引是数据库中用于提高查询性能的数据结构,通过创建索引可以减少数据扫描范围,加速查询速度。OceanBase 支持多种索引类型,每种索引有不同的特点和适用场景。

索引分类

1. 按数据结构分类

B+树索引

B+树是 OceanBase 默认的索引类型,适用于大多数查询场景:

sql
-- 创建 B+树索引
CREATE INDEX idx_name ON table_name(column_name);

-- 创建唯一 B+树索引
CREATE UNIQUE INDEX idx_unique_name ON table_name(column_name);

-- 创建复合 B+树索引
CREATE INDEX idx_composite ON table_name(column1, column2, column3);

特点

  • 适合范围查询和排序
  • 支持前缀匹配查询
  • 叶子节点包含完整数据或指向数据的指针
  • 支持多列复合索引

适用场景

  • 频繁的范围查询
  • 排序和分组操作
  • 前缀匹配的模糊查询
  • 多条件组合查询

哈希索引

哈希索引基于哈希表实现,适用于等值查询场景:

sql
-- 创建哈希索引
CREATE INDEX idx_hash ON table_name(column_name) USING HASH;

特点

  • 等值查询速度快
  • 不支持范围查询
  • 不支持排序
  • 适合高基数列

适用场景

  • 频繁的等值查询
  • 高基数列的查询
  • 不涉及范围操作的场景

位图索引

位图索引适用于低基数列的查询场景:

sql
-- 创建位图索引
CREATE BITMAP INDEX idx_bitmap ON table_name(column_name);

特点

  • 适合低基数列
  • 占用空间小
  • 支持多个位图索引的 AND/OR 操作
  • 不适合频繁更新的列

适用场景

  • 低基数列的查询
  • 多条件组合查询
  • 数据仓库和 OLAP 场景
  • 静态或更新不频繁的数据

2. 按功能分类

主键索引

主键索引是表的主键列上的索引,用于唯一标识表中的每一行:

sql
-- 创建表时指定主键
CREATE TABLE table_name (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT
);

-- 或通过 ALTER 语句添加主键
ALTER TABLE table_name ADD PRIMARY KEY (id);

特点

  • 唯一标识每行数据
  • 自动创建,无需手动创建
  • 通常是聚集索引
  • 不允许 NULL 值

适用场景

  • 唯一标识表中的记录
  • 作为外键引用的目标
  • 频繁用于单行查询

唯一索引

唯一索引确保索引列的值唯一:

sql
-- 创建唯一索引
CREATE UNIQUE INDEX idx_unique ON table_name(column_name);

-- 创建复合唯一索引
CREATE UNIQUE INDEX idx_unique_composite ON table_name(column1, column2);

特点

  • 确保索引列值唯一
  • 允许 NULL 值(但最多一个 NULL)
  • 加速等值查询

适用场景

  • 需要保证列值唯一性的场景
  • 如用户邮箱、手机号等唯一标识
  • 频繁用于等值查询的列

普通索引

普通索引是最基本的索引类型,没有唯一性限制:

sql
-- 创建普通索引
CREATE INDEX idx_normal ON table_name(column_name);

-- 创建复合普通索引
CREATE INDEX idx_normal_composite ON table_name(column1, column2, column3);

特点

  • 加速查询
  • 不限制列值唯一性
  • 可以创建多个

适用场景

  • 频繁用于查询的列
  • 范围查询和排序操作
  • 多条件组合查询

全文索引

全文索引用于文本内容的全文搜索:

sql
-- 创建全文索引
CREATE FULLTEXT INDEX idx_fulltext ON table_name(column_name);

-- 使用全文索引查询
SELECT * FROM table_name WHERE MATCH(column_name) AGAINST('keyword');

特点

  • 支持文本内容的全文搜索
  • 支持关键词匹配
  • 支持相关性排序

适用场景

  • 文本内容的搜索
  • 如文章、评论、产品描述等
  • 需要关键词匹配的场景

3. 按存储方式分类

聚集索引

聚集索引决定数据在物理存储上的顺序:

特点

  • 数据行的物理顺序与索引顺序一致
  • 每个表只能有一个聚集索引
  • 通常是主键索引
  • 查询速度快

适用场景

  • 频繁根据主键查询
  • 范围查询和排序操作

非聚集索引

非聚集索引的索引顺序与数据物理存储顺序无关:

特点

  • 索引顺序与数据物理顺序无关
  • 每个表可以有多个非聚集索引
  • 索引包含指向数据行的指针
  • 适合频繁查询的列

适用场景

  • 频繁用于查询的非主键列
  • 范围查询和排序操作
  • 多条件组合查询

索引选择原则

1. 考虑查询模式

  • 等值查询:优先选择哈希索引或 B+树索引
  • 范围查询:必须选择 B+树索引
  • 排序和分组:选择 B+树索引
  • 全文搜索:选择全文索引
  • 低基数列:考虑位图索引

2. 考虑列的基数

  • 高基数列:适合 B+树索引或哈希索引
  • 低基数列:适合位图索引
  • 中等基数列:适合 B+树索引

3. 考虑更新频率

  • 频繁更新的列

    • 尽量少创建索引
    • 避免创建位图索引
    • 考虑索引维护成本
  • 不频繁更新的列

    • 可以创建多个索引
    • 适合创建各种类型的索引

4. 考虑索引维护成本

  • 索引会占用额外存储空间
  • 插入、更新、删除操作会维护索引
  • 索引越多,维护成本越高
  • 需要平衡查询性能和维护成本

5. 考虑复合索引的顺序

  • 将选择性高的列放在前面
  • 将频繁用于查询的列放在前面
  • 考虑最左前缀原则

索引使用示例

1. B+树索引示例

sql
-- 表结构
CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    department_id INT,
    hire_date DATE,
    salary DECIMAL(10,2)
);

-- 创建单列 B+树索引
CREATE INDEX idx_department ON employees(department_id);

-- 创建复合 B+树索引
CREATE INDEX idx_name ON employees(last_name, first_name);

-- 创建包含列的索引
CREATE INDEX idx_hire_salary ON employees(hire_date) INCLUDE (salary);

-- 使用 B+树索引的查询
SELECT * FROM employees WHERE department_id = 10;
SELECT * FROM employees WHERE last_name = 'Smith' AND first_name = 'John';
SELECT * FROM employees WHERE hire_date BETWEEN '2020-01-01' AND '2021-01-01' ORDER BY hire_date;

2. 哈希索引示例

sql
-- 创建哈希索引
CREATE INDEX idx_emp_id_hash ON employees(emp_id) USING HASH;

-- 使用哈希索引的查询
SELECT * FROM employees WHERE emp_id = 1001;

3. 位图索引示例

sql
-- 创建低基数列的表
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    status VARCHAR(20), -- 低基数列:'pending', 'shipped', 'delivered'
    order_date DATE
);

-- 创建位图索引
CREATE BITMAP INDEX idx_order_status ON orders(status);

-- 使用位图索引的查询
SELECT * FROM orders WHERE status = 'shipped';
SELECT * FROM orders WHERE status = 'shipped' AND order_date > '2023-01-01';

4. 全文索引示例

sql
-- 创建包含文本内容的表
CREATE TABLE articles (
    article_id INT PRIMARY KEY,
    title VARCHAR(100),
    content TEXT,
    publish_date DATE
);

-- 创建全文索引
CREATE FULLTEXT INDEX idx_article_content ON articles(content);

-- 使用全文索引查询
SELECT * FROM articles WHERE MATCH(content) AGAINST('database performance optimization');

-- 使用全文索引并按相关性排序
SELECT *, MATCH(content) AGAINST('database performance') AS relevance 
FROM articles 
WHERE MATCH(content) AGAINST('database performance') 
ORDER BY relevance DESC;

索引选择最佳实践

1. 优先考虑 B+树索引

B+树索引是最通用的索引类型,适用于大多数查询场景。在不确定使用哪种索引类型时,优先选择 B+树索引。

2. 根据查询模式选择索引

  • 等值查询:B+树索引或哈希索引
  • 范围查询:必须使用 B+树索引
  • 全文搜索:使用全文索引
  • 低基数列:考虑位图索引

3. 合理设计复合索引

  • 将选择性高的列放在前面
  • 考虑最左前缀原则
  • 避免创建过多的复合索引
  • 考虑索引覆盖查询

4. 避免过度索引

  • 索引越多,维护成本越高
  • 插入、更新、删除操作会变慢
  • 占用更多存储空间
  • 优化器选择索引的成本增加

5. 定期维护索引

  • 定期分析表,更新统计信息
  • 定期重建碎片较多的索引
  • 删除不再使用的索引
  • 监控索引使用情况

6. 考虑索引覆盖

  • 设计包含查询所需所有列的索引
  • 避免回表查询,提高查询性能
  • 适合频繁执行的查询

索引使用注意事项

1. 最左前缀原则

复合索引遵循最左前缀原则,只有使用索引的最左列或连续的前缀列才能使用索引:

sql
-- 创建复合索引
CREATE INDEX idx_a_b_c ON table_name(a, b, c);

-- 可以使用索引的查询
SELECT * FROM table_name WHERE a = 1;
SELECT * FROM table_name WHERE a = 1 AND b = 2;
SELECT * FROM table_name WHERE a = 1 AND b = 2 AND c = 3;

-- 无法使用索引的查询
SELECT * FROM table_name WHERE b = 2;
SELECT * FROM table_name WHERE c = 3;
SELECT * FROM table_name WHERE b = 2 AND c = 3;

2. 避免索引失效

以下情况可能导致索引失效:

sql
-- 1. 使用函数操作索引列
SELECT * FROM table_name WHERE UPPER(column_name) = 'VALUE';

-- 2. 使用不等于操作符
SELECT * FROM table_name WHERE column_name != 'VALUE';

-- 3. 使用 LIKE 以通配符开头
SELECT * FROM table_name WHERE column_name LIKE '%VALUE';

-- 4. 对索引列进行计算
SELECT * FROM table_name WHERE column_name + 1 = 10;

-- 5. 使用 OR 连接条件,其中一个条件没有索引
SELECT * FROM table_name WHERE indexed_column = 1 OR non_indexed_column = 2;

3. 索引列的数据类型

  • 确保索引列的数据类型与查询条件的数据类型一致
  • 避免隐式类型转换
  • 选择合适的数据类型,减少存储空间

4. 索引与分区表

  • 分区表的索引可以是本地索引或全局索引
  • 本地索引与分区一一对应
  • 全局索引跨越所有分区
  • 根据查询模式选择合适的索引类型

常见问题(FAQ)

Q1: 如何选择合适的索引类型?

A1: 选择索引类型的方法:

  • 分析查询模式,确定是等值查询还是范围查询
  • 考虑列的基数,高基数列适合 B+树或哈希索引,低基数列适合位图索引
  • 考虑更新频率,频繁更新的列尽量少创建索引
  • 考虑查询性能和维护成本的平衡

Q2: 每个表应该创建多少个索引?

A2: 索引数量建议:

  • 没有固定的数量限制,但建议每个表不超过 5-10 个索引
  • 根据查询需求创建必要的索引
  • 定期清理不再使用的索引
  • 平衡查询性能和维护成本

Q3: 复合索引的列顺序如何确定?

A3: 复合索引列顺序的确定原则:

  • 将选择性高的列放在前面
  • 将频繁用于查询的列放在前面
  • 考虑最左前缀原则
  • 根据查询条件的组合顺序调整

Q4: 哈希索引和 B+树索引有什么区别?

A4: 哈希索引和 B+树索引的区别:

  • 哈希索引适合等值查询,不支持范围查询
  • B+树索引支持等值查询和范围查询
  • 哈希索引查询速度快,但适用场景有限
  • B+树索引适用场景广泛,是默认的索引类型

Q5: 如何监控索引的使用情况?

A5: 监控索引使用情况的方法:

  • 使用 EXPLAIN 分析查询计划,查看是否使用索引
  • 查看索引的统计信息
  • 监控索引的维护成本
  • 使用数据库自带的索引使用监控工具
  • 定期审计索引使用情况