Oracle MySQL 的 JSON 数据类型在存储时用的紧凑的二进制格式,MariaDB 则傲娇的直接存原始的 JSON 文本串,从 MariaDB 10.2 开始兼容 MySQL 5.7,如今 MariaDB 10.4 稳定版都发布了,依然还是不支持 Oracle MySQL 的 JSON 类型

  • 使用 row based replication 时,不支持从 MySQL 5.7 复制包含 JSON 列的 binlog
  • 不支持就地读取包含 MySQL JSON 列的数据文件

MariaDB 从 10.2 开始大爆发:

  • 10.2:

    • Window function
    • Recursive Common Table Expressions
    • WITH statement
    • CHECK CONSTRAINT
    • DML-only flashback
  • 10.3:

    • System-versioned tables (也被称为 Temporal table)
    • Sequence
  • 10.4:

    • System-versioned table 支持 application-time period
    • Galera 4
    • 静态链接 WolfSSL (废了 OpenSSL 真好😄)
  • 10.5 (还未正式发布):

    • S3 storage engine

相比之下 MySQL 8.0 的步子真是太慢了,但是两家对于 JSON 数据类型的实现,恐怕是不指望双方主动做兼容层了。

由于非常馋 MariaDB 的 system-versioned table 功能以支持审计、调试、数据回滚、时序分析,因此魔改了下 MariaDB 10.4 分支,让其可以解析 MySQL 5.7 binlog 里的 MYSQL_TYPE_JSON 类型,这步依葫芦画瓢还是比较容易的,就是第一次看 MariaDB 代码,晕了好一阵子,还好有 GDB、LLDB 调试器在手,以及在 Wine 里跑 Source Insight 4(感谢这么好的源码阅读软件!),跌跌绊绊看明白了。

这一步搞定后,忽然想为啥不支持下就地读取包含 JSON 列的 MySQL 数据文件呢? 操起调试器大法,试验了几个小时,发现搞定了,还挺简单。。。然后又贪心不足,能不能支持就地写包含 JSON 列的 MySQL 数据文件了?花了十分钟 hack 了下,居然也可以了😂

MariaDB 代码里不少地方有一些疑问的注释,看的出来后来的代码维护者已经不知道为啥前人那么写了😓,但总的来说,MariaDB 代码做了些抽象和重构,比 MySQL 的源代码还是要规整些。

在 macOS 下很容易编译 MariaDB 的代码:

mkdir builddir &&
    cd builddir &&
    cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_SSL=bundled -DWITH_PCRE=bundled \
          -DWITH_UNIT_TESTS=OFF -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_general_ci \
          -DPLUGIN_TOKUDB=NO .. &&
    make &&
    make install DESTDIR=$HOME/tmp/mariadb

然后运行 MariaDB:

cd $HOME/tmp/mariadb/usr/local/mysql
bin/mysqld_safe --datadir=./data

macOS 下 clang 有个奇怪的行为,如果一次性的编译出可执行文件,那么 clang 会自动生产 xxx.dSYM 调试符号,而如果是先编译出 .o 再链接成可执行文件,则需要手动的搞一下:

dsymutil $HOME/tmp/mariadb/usr/local/mysql/bin/mysqld

然后就可以 lldb 调试了:

cd sources/mariadb-server
lldb -p PID
(lldb) breakpoint set -n FUNCTION
(lldb) continue

MySQL 8.0 加入了 JSON 的 partial update,默认没有开启,如果开启后,可能 binlog 格式有点变化,目前这个魔改的 MariaDB 版本没考虑这种情况,所以,MySQL 5.7 大法好!MariaDB 大法好!—— 哦,Percona 是谁啊?😄