注册
DM 索引优化高级技巧
培训园地/ 文章详情 /

DM 索引优化高级技巧

DM_356848 2026/06/15 737 0 0

DM 索引优化高级技巧
DM 索引优化高级技巧:索引
参考地址:https://eco.dameng.com/
一、引言:索引优化的艺术
索引是数据库性能优化的基石。一个设计良好的索引可以将查询性能提升数十倍甚至上百倍。达梦数据库提供了丰富的索引类型和优化技术,包括覆盖索引、函数索引、位图索引等高级特性。
1.1 MySQL vs DM 索引特性对比总览
特性 MySQL InnoDB DM 达梦 说明
B+ 树索引 ✅ 支持 ✅ 支持 两者都支持
唯一索引 ✅ 支持 ✅ 支持 两者都支持
复合索引 ✅ 支持 ✅ 支持 两者都支持
函数索引 ✅ 支持 (8.0+) ✅ 支持 DM 更成熟
位图索引 ❌ 不支持 ✅ 支持 DM 支持
索引提示 ✅ 支持 ✅ 支持 语法兼容

二、DM 索引体系深度剖析
2.1 DM 索引分类总览
DM 索引体系
├── 按数据结构分
│ ├── B+ 树索引(默认,适用于 OLTP)
│ ├── 位图索引(适用于 OLAP)

├── 按约束分
│ ├── 主键索引(自动创建)
│ ├── 唯一索引
│ └── 普通索引
2.2 索引存储结构
DM B+ 树索引结构:
┌─────────────┐
│ 根节点 │
│ (Root) │
└──────┬──────┘

┌─────────────────┼─────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ 分支节点 │ │ 分支节点 │ │ 分支节点 │
│ (Branch) │ │ (Branch) │ │ (Branch) │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ 叶子节点 │ ────▶│ 叶子节点 │ ────▶│ 叶子节点 │
│ (Leaf) │ │ (Leaf) │ │ (Leaf) │
│ [key,rowid] │ [key,rowid] │ [key,rowid]
└─────────┘ └─────────┘ └─────────┘

注:非聚簇索引其中 rowid 是数据行的物理地址(文件号 + 页号 + 行号),通过它可以直接定位到数据行
特点:

  • 所有数据存储在叶子节点
  • 叶子节点通过链表连接(范围查询优化)
  • 树高度通常为 2-4 层
  • 每个节点大小 = 页大小(默认 8KB)
    2.3 索引创建语法详解
    SQL
    -- 基础语法
    CREATE [UNIQUE] [BITMAP] INDEX index_name
    ON table_name (column1 [ASC|DESC] [, column2 [ASC|DESC]...])
    [COMPUTE STATISTICS]
    [ONLINE]
    [TABLESPACE tablespace_name]
    [STORAGE (INITIAL size NEXT size...)]
    [PARALLEL degree];

-- 完整示例
CREATE UNIQUE INDEX IDX_ORDER_NO
ON ORDERS(ORDER_NO ASC)
COMPUTE STATISTICS
ONLINE
TABLESPACE MAIN
STORAGE (INITIAL 1M NEXT 1M)
PARALLEL 4;
2.4 索引参数详解
参数 说明 推荐值 注意事项
UNIQUE 唯一索引 根据业务 主键自动创建
BITMAP 位图索引 OLAP 场景 不适用于频繁更新
COMPUTE STATISTICS 收集统计信息 推荐 创建后立即收集
ONLINE 在线创建 生产环境 不阻塞 DML
TABLESPACE 指定表空间 分离 IO 索引与数据分离
PARALLEL 并行度 CPU 核心数/2 大表推荐
NOLOGGING 减少日志 大批量创建 注意恢复能力

三、函数索引:突破索引限制的高级特性
3.1 函数索引原理
什么是函数索引?
函数索引(Function-Based Index)是基于表达式或函数结果创建的索引。当查询条件中包含函数或表达式时,普通索引会失效,而函数索引可以保持索引有效性。
普通索引失效场景:
SELECT * FROM ORDERS WHERE UPPER(ORDER_NO) = 'ABC123';
-- 索引失效,全表扫描

函数索引解决方案:
CREATE INDEX IDX_UPPER_ORDER_NO ON ORDERS(UPPER(ORDER_NO));
SELECT * FROM ORDERS WHERE UPPER(ORDER_NO) = 'ABC123';
-- 索引生效,索引扫描
3.2 MySQL vs DM 函数索引对比
特性 MySQL 8.0+ DM 8 说明
语法支持 虚拟列 + 索引 直接函数索引 DM 更简洁
表达式索引 ✅ 支持 ✅ 支持 两者都支持
函数支持 部分函数 丰富函数 DM 支持更多
统计信息 自动收集 可配置 两者相当
维护成本 较高 中等 DM 优化更好
3.3 DM 函数索引创建语法
SQL
-- 基础语法
CREATE INDEX index_name
ON table_name (function_expression);

-- 单函数索引
CREATE INDEX IDX_UPPER_NAME
ON CUSTOMERS(UPPER(CUSTOMER_NAME));

-- 多列函数索引
CREATE INDEX IDX_DATE_RANGE
ON ORDERS(TO_CHAR(ORDER_DATE, 'YYYY-MM'), STATUS);

-- 表达式索引
CREATE INDEX IDX_CALC_AMOUNT
ON ORDERS(AMOUNT * (1 - DISCOUNT));

-- 包含 CASE 表达式
CREATE INDEX IDX_STATUS_PRIORITY
ON ORDERS(CASE WHEN STATUS = 'URGENT' THEN 1
WHEN STATUS = 'NORMAL' THEN 2
ELSE 3 END);
3.4 常用函数索引场景
场景 1:大小写不敏感查询
SQL
-- 创建函数索引
CREATE INDEX IDX_UPPER_EMAIL
ON CUSTOMERS(UPPER(EMAIL));

-- 查询(索引生效)
SELECT * FROM CUSTOMERS
WHERE UPPER(EMAIL) = UPPER('test@example.com');

-- 性能对比:
-- 无索引:全表扫描 50 万行,2.5 秒
-- 有索引:索引扫描,0.08 秒
-- 提升:31 倍
场景 2:日期范围查询
SQL
-- 创建函数索引(按年月分组)
CREATE INDEX IDX_ORDER_MONTH
ON ORDERS(TO_CHAR(ORDER_DATE, 'YYYY-MM'));

-- 查询(索引生效)
SELECT * FROM ORDERS
WHERE TO_CHAR(ORDER_DATE, 'YYYY-MM') = '2026-03';

-- 性能对比:
-- 普通索引(ORDER_DATE):范围扫描,0.35 秒
-- 函数索引:精确匹配,0.05 秒
-- 提升:7 倍
3.5 函数索引使用限制
⚠️ 注意事项:

  1. 函数确定性:函数必须是确定性的(相同输入=相同输出)
  2. 列引用限制:只能引用表中的列,不能引用其他表
  3. 更新成本:基列更新时,函数索引也需更新
  4. 统计信息:需要定期收集统计信息
    SQL
    -- 收集函数索引统计信息
    EXEC DBMS_STATS.GATHER_INDEX_STATS(
    OWNNAME => 'SHOP',
    INDNAME => 'IDX_UPPER_EMAIL',
    ESTIMATE_PERCENT => 100
    );

四、位图索引:OLAP 场景的杀手锏
4.1 位图索引原理
什么是位图索引?
位图索引(Bitmap Index)使用位图(0 和 1 的序列)来表示列值的存在性。每个不同的列值对应一个位图,位图中的每一位对应表中的一行。
位图索引结构示例:
表:ORDERS (10 行)
STATUS 列有 3 个不同值:'NEW', 'PROCESSING', 'COMPLETED'

位图索引:
STATUS = 'NEW' → 1001000100 (第 1,4,8 行为 NEW)
STATUS = 'PROCESSING' → 0100100010 (第 2,5,9 行为 PROCESSING)
STATUS = 'COMPLETED' → 0010011001 (第 3,6,7,10 行为 COMPLETED)

查询:STATUS = 'NEW' AND STATUS = 'PROCESSING'
位图运算:1001000100 AND 0100100010 = 0000000000 (无匹配)
4.2 MySQL vs DM 位图索引
特性 MySQL DM 说明
原生支持 ❌ 不支持 ✅ 支持 DM 独有优势
适用场景 N/A OLAP/数据仓库 低基数字段
压缩率 N/A 高(90%+) 位图压缩
并发更新 N/A 低 不适合 OLTP
多列组合 N/A 优秀 位图运算高效
4.3 位图索引创建语法
SQL
-- 基础语法
CREATE BITMAP INDEX index_name
ON table_name (column_name);

-- 示例
CREATE BITMAP INDEX IDX_ORDER_STATUS
ON ORDERS(STATUS);

CREATE BITMAP INDEX IDX_CUSTOMER_LEVEL
ON CUSTOMERS(CUSTOMER_LEVEL); -- VIP/GOLD/SILVER/BRONZE
4.4 位图索引适用场景
✅ 推荐使用:
• 低基数(Low Cardinality)列:不同值数量少(<100)
• OLAP/数据仓库场景:读多写少
• 多条件组合查询:位图运算高效
• 统计报表查询:COUNT/SUM 等聚合
❌ 不推荐使用:
• 高基数字段:如主键、时间戳
• OLTP 场景:频繁更新
• 唯一性要求高:使用唯一索引
• 长字符串列:位图过大
五、索引失效场景与避免方法
5.1 常见索引失效场景
场景 示例 是否失效 解决方案
函数操作 WHERE UPPER(name) = 'ABC' ❌ 失效 创建函数索引
类型转换 WHERE phone = 13800138000 (phone 是字符串) ❌ 失效 保持类型一致
模糊查询前缀% WHERE name LIKE '%张%' ❌ 失效 使用全文索引
OR 条件 WHERE id = 1 OR name = '张三' ❌ 失效 使用 UNION ALL
NOT/!= 操作 WHERE status != 'DELETE' ❌ 失效 改写为 IN 或 EXISTS
计算操作 WHERE amount * 2 > 1000 ❌ 失效 改写为 amount > 500
最左前缀不匹配 复合索引 (a,b,c),查询 WHERE b = 1 ❌ 失效 遵循最左前缀
IS NULL WHERE col IS NULL ⚠️ 部分失效 包含 NULL 值的索引可用
5.2 索引失效避免技巧
技巧 1:避免在索引列上使用函数
SQL
-- ❌ 错误写法(索引失效)
SELECT * FROM ORDERS WHERE TO_CHAR(ORDER_DATE, 'YYYY') = '2026';

-- ✅ 正确写法(索引生效)
SELECT * FROM ORDERS
WHERE ORDER_DATE >= '2026-01-01' AND ORDER_DATE < '2027-01-01';
技巧 2:优化 OR 条件
SQL
-- ❌ 错误写法(索引失效)
SELECT * FROM ORDERS WHERE ORDER_ID = 1001 OR CUSTOMER_ID = 2002;

-- ✅ 正确写法(UNION ALL)
SELECT * FROM ORDERS WHERE ORDER_ID = 1001
UNION ALL
SELECT * FROM ORDERS WHERE CUSTOMER_ID = 2002;

六、索引优化最佳实践
6.1 索引设计原则

  1. 选择性原则:索引列的选择性越高越好
    SQL
    -- 选择性 = 不同值数量 / 总行数
    -- 推荐:选择性 > 10%
    SELECT COUNT(DISTINCT CUSTOMER_ID) * 100.0 / COUNT(*)
    FROM ORDERS;
  2. 覆盖查询原则:索引应覆盖高频查询的所有列
  3. 最左前缀原则:复合索引遵循最左前缀匹配
  4. 适度原则:索引不是越多越好(影响写入性能)
  5. 分离原则:索引与数据表空间分离(IO 优化)
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服