1. 来自深海的性能谜题

作为金融级分布式数据库,OceanBase每秒处理的交易量能达到百万级。记得去年双十一期间,某电商平台的订单表查询突然变慢,DBA团队发现虽然创建了索引,但查询计划却选择了全表扫描。这个典型案例暴露了索引选择性(Index Selectivity)对性能影响的关键作用——就像潜艇的声呐系统,选择性差的索引反而会成为探测数据的累赘。

2. 索引选择性的底层密码

2.1 数据指纹的数学表征

索引选择性的计算公式看似简单:

-- OceanBase计算单个字段选择性的标准方法
SELECT 
    COUNT(DISTINCT column_name) * 1.0 / COUNT(*) AS selectivity 
FROM 
    user_orders;

但当处理复合索引时,情况会变得有趣。假设我们有个复合索引(region, city):

-- 复合索引选择性应分层计算
SELECT 
    (COUNT(DISTINCT region) + COUNT(DISTINCT city)) * 0.5 / COUNT(*) 
FROM 
    user_addresses;

这里的0.5调节因子需要根据实际查询模式动态调整,就像咖啡师调整奶泡的绵密程度。

2.2 索引质量的黄金标准

在OceanBase的优化器眼中:

  • 小于5%的高选择性索引是黄金搭档
  • 20%-30%的选择性如同鸡肋
  • 超过50%的索引就像是穿晚礼服去晨跑

来看具体的场景对比:

-- 创建不同选择性的测试索引(示例表:product_skus)
CREATE INDEX idx_high_selectivity ON product_skus(vendor_code); -- 供应商编码唯一性高
CREATE INDEX idx_low_selectivity ON product_skus(product_color); -- 颜色字段重复值多

EXPLAIN 
SELECT * 
FROM product_skus 
WHERE vendor_code = 'V2023' AND product_color = 'Red';

查询计划会清晰显示优化器如何选择索引,通常表现为类似如下的执行路径:

| =======================================
| ID | OPERATOR  | NAME                |
|----|-----------|---------------------|
| 0  | TABLE SCAN| idx_high_selectivity |
| =======================================

这说明优化器优先选择了选择性更高的索引作为访问路径。

3. 索引性能的调校工坊

假设我们有个用户行为日志表:

-- 创建测试表(技术栈:OceanBase 4.x)
CREATE TABLE user_behavior (
    log_id BIGINT PRIMARY KEY,
    user_id INT NOT NULL,
    action_type VARCHAR(20),
    device_hash CHAR(32),
    log_time DATETIME 
) PARTITION BY HASH(log_id) PARTITIONS 16;

-- 插入模拟数据(约1亿条)
DELIMITER //
BEGIN
  FOR i IN 1..100 DO
    INSERT INTO user_behavior VALUES(...); -- 批量插入逻辑
  END LOOP;
END;
//

案例1:时间范围查询优化

-- 原始低效查询
SELECT * 
FROM user_behavior 
WHERE log_time BETWEEN '2023-01-01' AND '2023-12-31';

-- 查看当前索引状态
SHOW INDEX FROM user_behavior;

-- 计算时间字段选择性
SELECT 
    (MAX(log_time) - MIN(log_time)) / COUNT(DISTINCT log_time) AS time_density 
FROM 
    user_behavior;

当发现时间密度值较低时,考虑创建函数索引:

CREATE INDEX idx_log_date ON user_behavior (DATE_FORMAT(log_time, '%Y%m%d'));

案例2:组合索引顺序优化

处理组合查询条件时:

SELECT user_id, COUNT(*) 
FROM user_behavior 
WHERE action_type = 'payment' AND device_hash LIKE 'a1b2%'
GROUP BY user_id;

通过选择性分析确定索引顺序:

SELECT 
    COUNT(DISTINCT action_type)/COUNT(*) AS action_selectivity,
    COUNT(DISTINCT LEFT(device_hash,4))/COUNT(*) AS device_selectivity
FROM 
    user_behavior;

根据计算结果创建最优顺序的复合索引:

CREATE INDEX idx_action_device ON user_behavior (device_hash, action_type);

4. 多维场景的索引策略

4.1 典型业务场景适配

  • 金融交易系统:对交易流水号创建唯一索引,选择性接近100%
  • 社交网络图谱:对用户兴趣标签使用位图索引,提高多值查询效率
  • 物联网时序数据:采用时间分段索引,解决海量数据扫描问题

4.2 存储成本与查询效率的天平

在某电商订单表的优化中:

-- 测试不同索引的存储开销
SELECT 
    index_name, 
    ROUND(index_length/(1024*1024),2) AS size_mb
FROM 
    INFORMATION_SCHEMA.STATISTICS 
WHERE 
    table_name = 'order_main';

-- 输出示例:
-- idx_order_no       120MB
-- idx_user_status    850MB

发现虽然status字段的查询频率高,但其索引占用了7倍的存储空间,需要平衡业务需求和硬件成本。

5. 避坑指南与高阶技巧

5.1 索引维护的隐藏成本

批量数据加载时的索引维护对比测试:

-- 关闭自动索引维护
SET GLOBAL sql_require_primary_key = OFF;

-- 测试数据导入速度
IMPORT TABLE user_behavior 
    FROM 'oss://data-bucket/user_behavior.parquet' 
    THREADS 32;

-- 耗时对比:
-- 无索引:3分12秒
-- 有5个索引:11分45秒

这说明在数据迁移窗口期,合理控制索引数量能显著提升效率。

5.2 统计信息的保鲜秘诀

定期更新统计信息的策略:

-- 自动收集配置
ALTER TABLE user_behavior 
    SET STATS_AUTO_RECALC = ON 
    STATS_SAMPLE_PAGES = 128;

-- 手动刷新关键表
ANALYZE TABLE user_behavior 
    UPDATE HISTOGRAM ON log_time, action_type 
    WITH 256 BUCKETS;

6. 智能时代的索引进化

随着OceanBase 4.x版本推出AI索引推荐功能,可以通过工作负载分析自动生成索引建议:

-- 使用内置分析工具
CALL DBMS_STATS.GATHER_DATABASE_STATS(
    method_opt => 'FOR ALL COLUMNS SIZE AUTO',
    cascade => TRUE);

SELECT * FROM TABLE(DBMS_ADVISOR.GET_INDEX_RECOMMENDATIONS());

该功能会输出类似如下的建议报告:

推荐索引1:
字段组合:log_time + device_hash
预期查询性能提升:68%
预估存储成本:420MB

7. 实践索引优化

在真实业务系统中,某银行核心交易表通过选择性调优实现了惊人的效果:

优化阶段 查询延迟 索引体积 CPU利用率
原始状态 850ms 320GB 78%
选择性优化后 210ms 89GB 43%
智能索引加持 156ms 102GB 36%

这个案例印证了选择性的精准把控带来的多重收益,就像给数据库引擎安装了涡轮增压器。