欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MYSQL神秘的HANDLER命令与实现方法

程序员文章站 2024-02-15 09:24:58
mysql“自古以来”都有一个神秘的handler命令,而此命令非sql标准语法,可以降低优化器对于sql语句的解析与优化开销,从而提升查询性能。看到这里,可能有小伙伴...

MYSQL神秘的HANDLER命令与实现方法

mysql“自古以来”都有一个神秘的handler命令,而此命令非sql标准语法,可以降低优化器对于sql语句的解析与优化开销,从而提升查询性能。看到这里,可能有小伙伴不淡定了,这么好的东西为啥没广泛使用呢?这不是与几年前很夯的handlersocket插件类似吗?

那么,我们先来看看handler语法说明:

handler tbl_name open [ [as] alias]
handler tbl_name read index_name { = | <= | >= | < | > } (value1,value2,…) [ where where_condition ] [limit … ]
handler tbl_name read index_name { first | next | prev | last } [ where where_condition ] [limit … ]
handler tbl_name read { first | next } [ where where_condition ] [limit … ]
handler tbl_name close

首先从语法上看,handler可以通过指定的索引去访问数据。但此语法并不支持dml操作。此外,由于减少了sql解析,handler命令的性能真的非常不错,根据inside君的简单主键测试,handler命令比sql要快40%~45%。测试脚本如下:

set @id=floor(rand()*1000000);
handler sbtest.sbtest1 open as c;
handler c read `primary` = (@id);
handler c close;

在inside君的24c的测试服务器上,64线程主键查询跑到了近37w qps,还是非常令人印象深刻的。对比sql的select查询,整体测试结果如下图所示:

MYSQL神秘的HANDLER命令与实现方法

命令handler的主要实现在源码sql_handler.h、sql_handler.cc,设个断点就能观察到具体的流程。mysql上层及innodb存储引擎层主要实现函数入口为:

复制代码 代码如下:

sql_cmd_handler_open::execute
sql_cmd_handler_read::execute
sql_cmd_handler_close::execute
ha_innobase::init_table_handle_for_handler
ha_partition::init_table_handle_for_handler()(7版本支持handler操作分区表)

既然性能不错,为什么在生产环境中并不见到命令handler的使用呢?主要是因为handler命令存在以下几个主要问题:

非一致性读取???
返回聚集索引中的所有列(即使是二级索引访问),而不能返回某个具体列
二级索引不使用limit关键字,只能返回1行记录
知道命令handler的同学,可能会认为handler读取存在脏读问题。因为mysql官方文档对于handler读取的说明就是这么说的:

the handler interface does not have to provide a consistent look of the data (for example, dirty reads are permitted), so the storage engine can use optimizations that select does not normally permit.
然而需要特别注意的是,mysql文档中准确的说法是可以允许提供不一致的读取。但innodb存储引擎的handler实现是支持一致性读取的,inside君亲测的确不存在脏读问题。当然,源码说明一切,可以发现在函数init_table_handle_for_handler会对readview进行分配,而注释也说明了这点:

/* we let handler always to do the reads as consistent reads, even
if the trx isolation level would have been specified as serializable */
m_prebuilt->select_lock_type = lock_none;
m_prebuilt->stored_select_lock_type = lock_none;

貌似用handler命令来做主键的查询是不错的,减少了sql解析器的开销,性能提升杠杠的。但为此,应用要付出巨大的改动,而sql最大的优势就在于标准化。相信这也是目前nosql数据库遇到的最大的一个问题。比如mongodb,inside君每次写查询时都要打开官方的命令对照表……