1、背景
InnoDB引擎存储int类型时使用big-endian, 而MySQL使用litter-endian, 导致一个问题是在两个层之间拷贝int类型数据的时候必须用一个循环来处理,而不能直接memcpy。 在引擎层返回数据量很大的情况下,很耗cpu。
在报表类的一些查询中,会访问大量的数据。我们有个项目的一个查询需要访问到1.4w个bigint,这个时候cpu的消耗就体现出来了。
2、相关代码
目前使用的转换代码就是使用循环。
row_sel_field_store_in_mysql_format这个函数的作用是把数据从InnoDB格式转成MySQL格式,
如下:
ptr = dest + len;
for (;;) { ptr--; *ptr = *data; if (ptr == dest) { break; } data++; } |
这里如果是bigint就需要循环8次。
反过来的转换代码在row_mysql_store_col_in_innobase_format,也是类似的需要一个循环。
3、改进和效果
这一坨循环,O3编译以后的汇编代码下,如果是bigint,需要40条指令。而显然我们使用的时候,int和bigint会很多。
因此考虑当len=4或8的时候,使用bswap和bswapq实现。
修改后再用oprofile观察上面说到的一个统计查询压力下的结果,发现row_sel_field_store_in_mysql_format这个函数cpu占用率从50%下降到44%.
DB的多数情况下压力还是在io,因此这个改进的效果需要在特定场景下才能体现。 最近跟Oracle InnoDB工程师讨论的时候了解到会有一些专门针对减少汇编结果做的优化,就凑热闹把这个提了。
Patch内容: http://bugs.mysql.com/file.php?id=18018&text=1 基于5.5.22