MyRocks collation 限制

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS Agent(兼容OpenClaw),2核4GB
简介: --- title: MySQL · myrocks · collation 限制 author: 张远 --- # 背景 MyRocks中的数据是按索引列以memcmp方式进行排序的。对于一些数字类型,需要进行转化才能直接通过memcmp进行比较, 例如有符号数在计算机中是用补码表示的,那么如果负数和正数直接按字节比较,结果负数会比正数大,实际存储时会将符号会反转存储,读取时再转

title: MySQL · myrocks · collation 限制

author: 张远

背景

MyRocks中的数据是按索引列以memcmp方式进行排序的。对于一些数字类型,需要进行转化才能直接通过memcmp进行比较, 例如有符号数在计算机中是用补码表示的,那么如果负数和正数直接按字节比较,结果负数会比正数大,实际存储时会将符号会反转存储,读取时再转化回来。对于字符类型,处理更加复杂,涉及到字符集的转换。 记录格式可以参考[1],

MyRocks索引字段如果包含字符类型,默认只支持binary collation,binary、latin1_bin、 utf8_bin其中的一种

# Error
create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set gbk;
ERROR 3046 (HY000): Unsupported collation on string indexed column test.t1.c2 Use binary collation (binary, latin1_bin, utf8_bin).

# Error
create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set utf8 collate utf8_general_ci;
ERROR 3046 (HY000): Unsupported collation on string indexed column test.t1.c2 Use binary collation (binary, latin1_bin, utf8_bin).

# OK
create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set utf8 collate utf8_bin;
Query OK, 0 rows affected (0.00 sec)

通过设置rocksdb_strict_collation_check参数为OFF可以跳出binary collation的限制

set global rocksdb_strict_collation_check=OFF;

# OK
create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set gbk;
Query OK, 0 rows affected (0.01 sec)

问题

MyRocks和InnoDB一样支持covering index. MyRocks在使用二级索引查询的时候,应尽量使用covering index, 因为MyRocks回表通过主键随机查询数据的开销比较大。

例如以下场景,idx1作为convering index被使用


create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set utf8 collate utf8_bin;

insert into t1 values(1,'ab');
insert into t1 values(2,'cd');

# covering index
explain select c2 from t1 where c2='ab';
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------------+
|  1 | SIMPLE      | t1    | const | c2            | c2   | 33      | const |    1 | Using index |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------------+

然而设置set global rocksdb_strict_collation_check=OFF;在某些情况下会导致我们无法使用covering index.

set global rocksdb_strict_collation_check=ON;

#Error
create table t1(c1 int primary key, c2 int, c3 varchar(10), key idx1(c2,c3)) engine =rocksdb  character set utf8 collate utf8_general_ci;
ERROR 3046 (HY000): Unsupported collation on string indexed column test.t1.c3 Use binary collation (binary, latin1_bin, utf8_bin).

set global rocksdb_strict_collation_check=OFF;

# OK
create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set utf8 collate utf8_general_ci;
Query OK, 0 rows affected (0.00 sec)

insert into t1 values(1,1,'ab');
insert into t1 values(2,2,'cd');


insert into t1 values(1,'ab');
insert into t1 values(2,'cd');

# non-covering index
explain select c2 from t1 where c2='ab';
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------+
|  1 | SIMPLE      | t1    | const | c2            | c2   | 33      | const |    1 | NULL  |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

原因

MyRocks二级索引由于collation的关系导致查询没有走covering index. MyRocks中索引列需要转化为memcomparable的形式,转化分为以下三种情况

  • 1) 直接转换,不需要存储额外信息

    例如 binary、latin1_bin、 utf8_bin三种collation可以直接转换

    这种情况二级索引列数据可以完整的从二级索引中取到,不影响covering index使用

  • 2) 间接转换,需在value中增加unpack_info

    例如latin1_general_ci,latin2_general_ci, ascii_general_ci,greek_general_ci等collation,具体可以参考函数rdb_is_collation_supported

    这种情况二级索引列数据可以从key和unpack_info中解析取到,也不影响covering index使用

create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set latin1 collate latin1_general_ci;

insert into t1 values(1,'ab');
insert into t1 values(2,'cd');

# covering index
explain select c2 from t1 where c2='ab';
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------------+
|  1 | SIMPLE      | t1    | const | c2            | c2   | 13      | const |    1 | Using index |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)
  • 3) 无法转换

    除1,2两种情况外的collation, 例如utf8_general_ci

    此时从二级索引中获取不到key的完整信息,需要从主键索引上获取,因此不能走covering index

create table t1(c1 int primary key, c2 varchar(10) unique) engine =rocksdb character set utf8 collate utf8_general_ci;

 insert into t1 values(1,'ab');
 insert into t1 values(2,'cd');

# non-covering index
explain select c2 from t1 where c2='ab';
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------+
|  1 | SIMPLE      | t1    | const | c2            | c2   | 33      | const |    1 | NULL  |
+----+-------------+-------+-------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

此时的数据获取路径如下

0  myrocks::ha_rocksdb::convert_record_from_storage_format 
1  myrocks::ha_rocksdb::get_row_by_rowid
2  myrocks::ha_rocksdb::get_row_by_rowid
3  myrocks::ha_rocksdb::read_row_from_secondary_key 
4  myrocks::ha_rocksdb::index_read_map_impl
5  myrocks::ha_rocksdb::index_read_map
6  handler::index_read_idx_map
7  handler::ha_index_read_idx_map
8  join_read_const
9  join_read_const_table
10 make_join_statistics
11 JOIN::optimize
12 mysql_execute_select
13 mysql_select
14 handle_select
15 execute_sqlcom_select
16 mysql_execute_command

转换的具体实现可以参考函数Rdb_field_packing::setup

MyRocks从索引读取数据时,不能仅通过keyread_only来判断是否可以使用covering index, 还需要判断是否存在collation列数据转换的问题,如果访问的列无法转换就不能使用covering index.

MyRocks会在value中存储covered_bitmap,表示索引列是否可以转换, read_row_from_secondary_key/secondary_index_read读取时会根据covered_bitmap来决定是否能使用covering index

bool Rdb_key_def::covers_lookup(TABLE *const table,
                                const rocksdb::Slice *const unpack_info,
                                const MY_BITMAP *const lookup_bitmap) const {
  DBUG_ASSERT(lookup_bitmap != nullptr);
  if (!use_covered_bitmap_format() || lookup_bitmap->bitmap == nullptr) {
    return false;
  }

  Rdb_string_reader unp_reader = Rdb_string_reader::read_or_empty(unpack_info);

  // Check if this unpack_info has a covered_bitmap
  const char *unpack_header = unp_reader.get_current_ptr();
  const bool has_covered_unpack_info =
      unp_reader.remaining_bytes() &&
      unpack_header[0] == RDB_UNPACK_COVERED_DATA_TAG;
  if (!has_covered_unpack_info ||
      !unp_reader.read(RDB_UNPACK_COVERED_HEADER_SIZE)) {
    return false;
  }

  MY_BITMAP covered_bitmap;
  my_bitmap_map covered_bits;
  bitmap_init(&covered_bitmap, &covered_bits, MAX_REF_PARTS, false);
  covered_bits = rdb_netbuf_to_uint16((const uchar *)unpack_header +
                                      sizeof(RDB_UNPACK_COVERED_DATA_TAG) +
                                      RDB_UNPACK_COVERED_DATA_LEN_SIZE);

  return bitmap_is_subset(lookup_bitmap, &covered_bitmap);
}

总结

MyRocks在字符collation上的限制需要引起我们关注,使用不当会影响查询效率。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
17天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
6090 30
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
2天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
574 135
|
11天前
|
存储 定位技术 数据库
CodeGraph 如何让 Claude Code减少 7 成工具调用?
CodeGraph 为 Coding Agent 提供本地代码知识图谱,把函数、类、调用链和框架路由提前整理成“项目地图”,减少盲目搜索和文件读取。它不是新 Agent,而是上下文基础设施,让 Agent 更快找到正确代码路径,平均减少 7 成工具调用。
1202 3
|
9天前
|
人工智能 安全 定位技术
CodeGraph深度解析 让Claude Code工具调用直降七成的核心原理与实操教程
如今以Claude Code为代表的AI编程智能体已经成为开发者日常编码、项目重构、漏洞修复的必备工具。但在长期使用过程中,几乎所有开发者都会遇到同一个明显痛点:AI虽然具备强大的代码生成与分析能力,却常常陷入盲目探索的循环中。
1021 1
|
18天前
|
人工智能 自然语言处理 供应链
|
9天前
|
人工智能 弹性计算 安全
阿里云618活动时间、活动入口、优惠活动详细解读
2026年阿里云618创新加速季已全面开启,作为年度力度最大的云产品促销活动,本次大促覆盖轻量应用服务器、ECS云服务器、GPU云服务器、数据库、AI算力、安全服务、CDN等全品类产品,推出5亿元算力补贴、新用户限时秒杀、普惠满减、企业专享、免费试用、云大使返佣等多重福利,个人开发者、中小企业、AI团队均可享受专属低价。本文将系统梳理2026年阿里云618活动的完整时间节点、官方参与入口、各类优惠细则、使用规则、热门产品推荐及实操代码,帮助用户精准参与、高效省钱,以最低成本完成上云部署。
845 5
|
7天前
|
人工智能 自然语言处理 安全
Vibe Coding 实战:别盲目跟风,先分清 vibe coding 适合什么场景
本文系统总结vibe coding实战经验:明确其适用场景(原型、小工具、标准化模块),剖析5步落地流程(场景判定→结构化提示词→目录初始化→分模块生成→自动化校验),指出四大常见误区,并推荐适配工具Trae。强调“场景匹配+规则前置”是提效关键,避免盲目套用。
673 1