在MySQL上以text类型字段为查找结果排序时踩到的坑

公司的同步功能后端接口,提供了一系列和文件操作相关的接口。其中一个接口的作用是,返回云端指定节点下所有子节点id的列表,且保证父节点id在列表中一定比子节点id先出现。
客户端会按顺序遍历这个列表,获取id对应的信息,插入一个树结构,就可以得到云端当前的文件结构。如果列表中的id顺序不对,或者只有子节点id没有父节点id,那么客户端就会通知云端数据出现错误,并重新调用这个接口,获取修复后的文件结构。
最近在回归测试同步功能时发现,当云端某个目录层级过深时,使用上面提到的那个接口获取id列表时,返回的id顺序会出现错乱。比较奇怪的是,数据库中这个目录及下列节点的数据均没有出现错乱的情况。使用其他接口来获取文件结构时也不会出现错误。难道是这个接口的实现有问题?
后端数据库表在设计时只记录了节点当前的直属父节点的id。后续迭代开发时,为了满足一系列的业务需求,增加了一个text类型的字段path_ids,表示从根节点到当前节点的完整路径。实际内容为以/分割的节点id。在新建、移动、删除节点时维护这个字段。看了一下这个接口的实现:

  1. 查找db中节点对应的path_ids,记为p
  2. 查找db中所有path_ids以p+/开头的节点,并以path_ids升序排序返回id

看着也没什么问题。但实际输出的列表中,层级比较深的几个目录节点,和下面的子节点,顺序始终是错的。直接连接mysql,查找db中所有path_ids以p+/开头的节点,并以path_ids升序排序返回id和path_ids,得到的结果也是错误的。难道是MySQL的错?
一顿Google之后,发现问题关键点了。按照The BLOB and TEXT Types中提到的。BLOB/TEXT类型的字段只有前max_sort_length个字节被用于排序。max_sort_length默认值为1024。在我们这个场景中,因为路径比较深,节点和下面的子节点的path_ids字段长度超过了1024。MySQL在排序时,无法正确处理这些节点的先后顺序。
找到问题原因后,解决方案就比较多了。

  1. 接口本身不对节点id做排序。客户端在拿到子节点id和对应的节点信息后,根据节点信息中的父子关系,去重新构建文件树。
  2. 业务层从MySQL中获取不排序的数据,然后在业务代码中排序。
  3. 增大max_sort_length值,继续让MySQL执行排序。

综合性能及兼容性的考虑,最终我们选择了

  1. 被线上老版客户端调用的原有接口,使用增大max_sort_length值的方案。
  2. 新开一个新版客户端调用的接口,使用方案1。