【外汇网站 源码】【transient底层源码】【php记录源码】mysql内核源码_mysql源码及内核分析

时间:2024-11-30 14:32:03 来源:如何阅读源码 编辑:江恩网格源码

1.MySQL:如何编写UDF_MySQL
2.CentOS 8部署安装Zabbix6.0
3.技术分享 | MySQL 字段长度限制的核源核分计算方法
4.MySQL 优化器源码入门-内核实现 FULL JOIN 功能

mysql内核源码_mysql源码及内核分析

MySQL:如何编写UDF_MySQL

        bitsCN.com

        1.什么是UDF

        UDF顾名思义,就是User defined Function,用户定义函数。我们知道,MySQL本身支持很多内建的函数,此外还可以通过创建存储方法来定义函数。UDF为用户提供了一种更高效的方式来创建函数。

        UDF与普通函数类似,有参数,也有输出。分为两种类型:单次调用型和聚集函数。前者能够针对每一行数据进行处理,后者则用于处理Group By这样的情况。

        2.为什么用UDF

        既然MySQL本身提供了大量的函数,并且也支持定义函数,为什么我们还需要UDF呢?这主要基于以下几点:

        1)UDF的兼容性很好,这得益于MySQL的UDF基本上没有变动

        2)比存储方法具有更高的执行效率,并支持聚集函数

        3)相比修改代码增加函数,更加方便简单

        当然UDF也是有缺点的,这是因为UDF也处于mysqld的内存空间中,不谨慎的内存使用很容易导致mysqld crash掉。

        3.如何编写UDF

        UDF的API包括

        name_init():

        在执行SQL之前会被调用,主要做一些初始化的工作,比如分配后续用到的内存、初始化变量、检查参数是否合法等。

        name_deinit()

        在执行完SQL后调用,大多用于内存清理等工作。init和deinit这两个函数都是可选的

        name()

        UDF的主要处理函数,当为单次调用型时,可以处理每一行的数据;当为聚集函数时,则返回Group by后的聚集结果。

        name_add()

        在每个分组中每行调用

        name_clear()

        在每个分组之后调用

        为了便于理解,这里给出两种UDF类型的API调用图:

        下面将就上述几个API进行详细的讲解:

        1). name_init

        原型:

        my_boolname_init(UDF_INIT *initid, UDF_ARGS *args, char *message)

        UDF_INIT结构体如下:

        字段

        类型

        描述

        maybe_null

        my_bool

        如果为1表示该UDF可以返回NULL

        decimals

        unsigned int

        返回值为实数时,表示精度,范围0~

        max_length

        unsigned long

        对于返回值为INTEGER类型值为,对于REAL类型值为,对于字符串类型,存储函数最长参数的长度

        ptr

        char

*

        额外的指针,我们可以在这里分配内存。通过initd传递给其他API

        const_item

        my_bool

        为1表示函数总是返回相同的值

        extension

        void

*

        用于扩展?

        UDF_ARGS结构体如下:

        字段

        类型

        描述

        arg_count

        unsigned int

        参数个数

        arg_type

        enum Item_result

*

        参数类型数组,记录每一个参数的类型,可以是STRING_RESULT、REAL_RESULT、INT_RESULT以及DECIMAL_RESULT

        args

        char

**

        同样是一个数组,用于存储实际数据。

        STRING_RESULT与DECIMAL_RESULT类型为char*,INT_RESULT类型为long long*,REAL_RESULT类型为double*,或者一个NULL指针

        lengths

        unsigned long

*

        数组,用于存储每一个参数的长度

        maybe_null

        char

*

        该数组用于表明每个参数是否可以为NULL,例如

        attributes

        char

**

        每个参数的名字

        attribute_lengths

        unsigned long

*

        每个参数名字的长度

        extension

        void

*

        用于扩展?

        Message:用于打印错误信息,该指针本身提供长度为MYSQL_ERRMSG_SIZE,来存储信息;

        2).name_deinit

        原型:

        void name_deinit(UDF_INIT*initid)

        该函数会进行一些内存释放和清理的工作,在之前我们提到initid->ptr,我们可以在该区域·è¿›è¡Œå†…存的动态分配,这里就可以直接进行内存释放。

        3).name()

        原型:针对不同的返回值类型,有不同的函数原型:

        返回值类型

        函数原型

        STRING or DECIMAL

        char *name(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)

        INTEGER

        long long name(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)

        REAL

        double name(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);

        当返回值为STRING类型时,参数result开辟一个buffer来存储返回值,但不超过字节,在length参数中存储了字符串的长度。

        每个函数原型还包括了is_null和error参数,当*is_null被设置为1时,返回值为NULL,设置*error为1,表明发生了错误。

        4).name_add()和name_clear()

        原型:

        void name_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error)

        void name_clear(UDF_INIT *initid, char *is_null, char *error)

        对于聚合类型的UDF,name_addd和name_clear会被反复调用。

        4. 两个例子

        下面将举两个简单的例子,一个单次调用型函数,一个聚集类型函数,来描述写一个UDF的过程。

        1)接受一个参数,并返回该参数的值

        //初始化

        my_booludf_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)

        {

        if (args->arg_count != 1){ //检查参数个数

        strcpy(message,

        "udf_intexample() can onlyaccept one argument");

        return 1;

        }

        if (args->arg_type[0] != INT_RESULT){ //检查参数类型

        strcpy(message,

        "udf_intexample() argumenthas to be an integer");

        return 1;

        }

        return 0;

        }

        //清理操作

        voidudf_int_deinit(UDF_INIT *initid)

        {

        }

        //主函数

        long long udf_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)

        {

        long long num = (*(long long *)args->args[0]); //获取第一个参数值

        return num;

        }

        2)接受一个浮点数类型的参数,并对每个分组进行求和

        //初始化

        my_booludf_floatsum_init(UDF_INIT *initid, UDF_ARGS *args, char *message)

        {

        double *total = (double *) malloc (sizeof(double));

        if (total == NULL){ //内存分配失败

        strcpy(message,"udf_floatsum:alloc mem failed!");

        return 1;

        }

        *total = 0;

        initid->ptr = (char *)total;

        if (args->arg_count != 1){ //检查参数个数

        strcpy(message, "too moreargs,only one!");

        return 1;

        }

        if (args->arg_type[0] != REAL_RESULT){ //检查参数类型

        strcpy(message, "wrongtype");

        return 1;

        }

        initid->decimals = 3; //设置返回值精度

        return 0;

        }

        //清理、释放在init函数中分配的内存

        voidudf_floatsum_deinit(UDF_INIT *initid)

        {

        free(initid->ptr);

        }

        //每一行都会调用到该函数

        voidudf_floatsum_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)

        {

        double* float_total;

        float_total = (double*)initid->ptr;

        if (args->args[0])

        *float_total += *(double*)args->args[0];

        }

        //每个分组完成后,返回结果

        doubleudf_floatsum(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)

        {

        double* float_total;

        float_total = (double *)initid->ptr;

        return *float_total;

        }

        //在进行下一个分组前调用,设置initid->ptr指向的值为0,以便下一次分组统计

        voidudf_floatsum_clear(UDF_INIT *initid, char *is_null, char *error)

        {

        double *float_total;

        float_total = (double *)initid->ptr;

        *float_total = 0;

        }

        3) Mysql-udf-/statuses/user_timeline/.json?count=1&source=')

        UDF具有非常高的自由度,你可以编写你任何想要实现的功能函数,甚至可以引用MySQL内核的代码和变量。

        当然,UDF也有着局限性,如下:

        a) 在mysql库下必须有func表,并且在‑‑skip‑grant‑tables开启的情况下,UDF会被禁止;

        b) 当UDF挂掉时,有可能会导致mysqld crash掉;

        c) 所有的UDF的函数必须是线程安全的,如果非要用全局变量,需要加互斥,尽量在name_init中分配资源,并在name_deinit中释放

        d) 需要有insert权限

        作者 zhaiwx

        bitsCN.com

CentOS 8部署安装Zabbix6.0

       一、检查Linux内核版本

       通过执行命令`uname -a`,源码可直接查看系统内核版本信息。及内

       使用`cat /etc/redhat-release`命令,核源核分适用于查看Redhat系Linux系统的源码版本信息。

       二、及内外汇网站 源码切换CentOS 8源至阿里源

       鉴于CentOS 8已停止维护,核源核分建议将源切换至阿里源以获取更新。源码

       需注释掉`mirrorlist`与`baseurl`,及内并在相应文件中加入`baseurl`指向阿里源的核源核分内容。具体路径如下:

       CentOS-AppStream.repo文件的源码`baseurl= mirrors.aliyun.com/cent...`

       CentOS-Base.repo文件的`baseurl= mirrors.aliyun.com/cent...`

       CentOS-Extras.repo文件的`baseurl= mirrors.aliyun.com/cent...`

       清除yum缓存,重新生成缓存。及内

       三、核源核分transient底层源码安装和配置MySQL数据库

       安装MySQL数据库,源码使用yum工具管理包。及内

       通过修改`/etc/yum.repos.d/mysql-community.repo`文件中的`baseurl`为清华源或阿里源。

       执行初始配置命令,修改root用户密码。

       四、安装Zabbix 6.0

       完成MySQL安装后,使用yum安装Zabbix。

       五、创建Zabbix初始数据库

       安装Zabbix后,根据指示创建用于Zabbix的数据库。

       六、php记录源码启动Zabbix Server与Agent

       确保Zabbix Server和Agent进程正常启动。

       七、登录Zabbix

       通过访问`.../zabbix`,使用用户名`Admin`与密码`zabbix`进行登录。

       本文由 mdnice 多平台发布

技术分享 | MySQL 字段长度限制的计算方法

       本文由kay撰写,擅长Oracle、MySQL、PostgresSQL等领域,专注于Oracle和MySQL性能优化、数据库架构设计、故障修复、数据迁移和恢复,关系卡源码热衷于研究MySQL内核源码,并拥有Oracle OCP认证。目前在江苏国泰新点软件有限公司担任DBA技术团队成员。

       一、MySQL限制回顾

       之前在《MySQL Text字段的限制》一文中提及了MySQL在Server层和InnoDB层的限制,但未详细阐述限制计算方法。本文将对MySQL的两个限制进行补充说明:1. MySQL Server层限制单条记录大小不超过字节;2. InnoDB层限制不能超过innodb_page_size的一半,以默认K设置为例,限制为。下文内容基于MySQL 5.7.进行说明。

       二、Server层限制的乐趣iapp源码计算方法

       2.1 计算过程

       若MySQL Server层面限制,则会返回特定报错信息。关键代码路径在于`pack_header`中,具体在于判断`reclength`值是否大于。因此,了解`reclength`的计算过程至关重要。

       2.2 小结

       根据上述计算方式,MySQL Server层计算长度的公式为:`total_length <= `。满足此条件即可通过MySQL Server层的检查。

       三、InnoDB层限制的计算方法

       3.1 计算过程

       InnoDB层面限制的报错信息中,关键代码路径在于判断`page_rec_max`值。根据源码定义,`srv_page_size`默认值为1<<即,配置也是。而`UNIV_PAGE_SIZE_MAX`值为1<<即。因此,`srv_page_size`不等于`UNIV_PAGE_SIZE_MAX`。计算`page_rec_max`值为`page_get_free_space_of_empty(comp) / 2`。进一步分析,一条记录实际长度(`rec_max_size`)的计算公式如下。

       3.2 小结

       在InnoDB层计算长度的公式为:`rec_max_size < `。满足此条件即可通过InnoDB层的检查。

       四、总结

       1. 必须同时满足MySQL Server层和InnoDB层的限制条件,才能成功创建表。

       2. 遇到上述报错情况时,多数原因在于varchar等字段设置过大。建议对字段逐步缩小或使用text替代。

MySQL 优化器源码入门-内核实现 FULL JOIN 功能

       本文以实现MySQL内核的FULL JOIN功能为目标,深入解析了MySQL源码的优化器工作流程。首先,作者通过环境和知识准备,明确将重点放在Server执行流程的探索上,从语法规则的修改开始,如在`sql_yacc.yy`中添加新支持,以及在`parse_tree_nodes.cc`中处理FULL JOIN的语法树解析和打印。接着,作者逐步解析了词法、语法分析后的Query_expression、Query_block和Query_term结构,并在关键函数中设置了断点以跟踪执行流程。

       在探索了JOIN的优化工作流程后,作者选择在hypergraph_optimizer中实现FULL JOIN,该部分涉及RelationalExpression、JoinHypergraph的构建和AccessPath的生成。尽管过程复杂,但作者通过逐步调试和修改,成功在HashJoinIterator中添加了对FULL JOIN的支持,包括添加新数据成员和状态标记,以及在LEFT JOIN后执行ANTI JOIN流程。

       在测试阶段,作者确认了FULL JOIN功能的正确性,通过在代码关键位置的断点观察,确认了FULL OUTER_JOIN的出现,并展示了改造后的迭代器结构。整个过程中,作者强调了在实现过程中面临的挑战和对MySQL历史的参考,最终决定以最少改动的方式完成任务,以保持代码的简洁和性能。

       通过这个项目,作者不仅深入理解了MySQL源码,还实现了FULL JOIN功能,为读者提供了一个从零开始实现新功能的实例。

copyright © 2016 powered by 皮皮网   sitemap