微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

MySQL/MariaDB - 使用 C API 重复调用准备好的语句性能下降

如何解决MySQL/MariaDB - 使用 C API 重复调用准备好的语句性能下降

我有一个有点复杂的 sql 命令,它使用了十几个需要重复调​​用的常见表表达式和窗口函数。因此,我正在尝试使用准备好的语句。它有 10 个输入绑定和 6 个输出绑定。

它触及了几张表,最大的几GB有1500万条记录。查询的单次执行需要 50-200 毫秒。

当我将代码结构为:

    MysqL_STMT* statement = MysqL_stmt_init(db_connection);
    Assert(statement);
    char* sql = ...
    s32 status = MysqL_stmt_prepare(statement,sql,sql_length);
    Assert(status == 0);

    // ...setup input binding (10 params)...

    s32 input_bind_result = MysqL_stmt_bind_param(statement,input_bind);
    Assert(input_bind_result == 0);
    
    // ...setup output binding (6 columns)..
        
    s32 output_bind_result = MysqL_stmt_bind_result(statement,output_bind);
    Assert(output_bind_result == 0);

    for (int i = 0; i < 1000; i++)
    {
        s32 execute_result = MysqL_stmt_execute(statement);
        Assert(execute_result == 0);
        
        while (true)
        {
            s32 fetch_result = MysqL_stmt_fetch(statement);
            if (fetch_result == MysqL_NO_DATA)
                break;
            
            Assert(fetch_result == 0);
            
            // ...process row...
            // ...printf(timestamp and query output)...
        }

        // ...increment input parameters...
    }
    
    MysqL_stmt_close(statement);

每次执行查询时,它都会变得越来越慢,而且很快:

    2021-06-30 21:24:40: 0.996904
    2021-06-30 21:24:40: 0.995356
    2021-06-30 21:24:41: 0.000000
    2021-06-30 21:24:41: 0.000000
    2021-06-30 21:24:41: 0.000000
    2021-06-30 21:24:41: 0.000000
    <hangs indefinitely>

它在从 MysqL_stmt_execute() 返回时挂起。它不是确定性的。如果我重置查询缓存并重新启动,它可能会在第 5 次或第 8 次查询时挂起。

相比之下,如果我将代码结构化为:

    // ...setup input binding (10 params)...
    // ...setup output binding (6 columns)...
    
    for (int i = 0; i < 1000; i++)
    {
        MysqL_STMT* statement = MysqL_stmt_init(db_connection);
        Assert(statement);
        char* sql = ...
        s32 status = MysqL_stmt_prepare(statement,sql_length);
        Assert(status == 0);

        s32 input_bind_result = MysqL_stmt_bind_param(statement,input_bind);
        Assert(input_bind_result == 0);     
        
        s32 output_bind_result = MysqL_stmt_bind_result(statement,output_bind);
        Assert(output_bind_result == 0);
            
        s32 execute_result = MysqL_stmt_execute(statement);
        Assert(execute_result == 0);
        
        while (true)
        {
            s32 fetch_result = MysqL_stmt_fetch(statement);
            if (fetch_result == MysqL_NO_DATA)
                break;
            
            Assert(fetch_result == 0);
            
            // ...process row...
            // ...printf(timestamp and query output)...
        }

        // ...increment input parameters...
        
        MysqL_stmt_close(statement);
    }

也就是说,从字面上看,每次迭代都会创建和释放准备好的语句,不会出现这种降级,而且我会很快处理每次迭代:

    2021-06-30 21:26:59: 0.996904
    2021-06-30 21:27:00: 0.995356
    2021-06-30 21:27:00: 0.000000
    2021-06-30 21:27:00: 0.000000
    2021-06-30 21:27:00: 0.000000
    2021-06-30 21:27:00: 0.000000
    2021-06-30 21:27:00: 0.994969
    2021-06-30 21:27:00: 0.997291
    2021-06-30 21:27:00: 0.997678
    2021-06-30 21:27:00: 0.998452
    2021-06-30 21:27:00: 0.998452
    2021-06-30 21:27:00: 0.998452
    2021-06-30 21:27:00: 0.998839
    2021-06-30 21:27:01: 0.998839
    2021-06-30 21:27:01: 0.998839
    2021-06-30 21:27:01: 0.998454
    2021-06-30 21:27:01: 0.999230
    2021-06-30 21:27:01: 0.999230
    2021-06-30 21:27:01: 0.999230
    2021-06-30 21:27:01: 0.998459
    2021-06-30 21:27:01: 0.998844
    2021-06-30 21:27:01: 0.998844
    2021-06-30 21:27:02: 0.999230
    2021-06-30 21:27:02: 0.999231
    2021-06-30 21:27:02: 0.999231
    2021-06-30 21:27:02: 0.999231
    2021-06-30 21:27:02: 0.999615
    2021-06-30 21:27:02: 1.000000
    2021-06-30 21:27:02: 1.000000
    2021-06-30 21:27:02: 0.999232
    2021-06-30 21:27:02: 0.999617
    2021-06-30 21:27:02: 0.999617
    2021-06-30 21:27:02: 0.999617
    ...continues at this speed for 1000+ iterations...

但这对我来说没有多大意义,并且否定了使用准备好的语句的主要好处之一。关于可能导致这种情况的任何见解?

感觉有些资源没有被释放,但我尝试添加

 MysqL_stmt_free_result(statement);

 MysqL_stmt_reset(statement);

在每次迭代结束时,但退化仍然存在。

运行 MariaDB 10.5.10,mariadb-connector 3.1.13。

解决方法

向我们展示声明。

如果其中一个参数用于 OFFSET,请注意必须跨过所有“偏移量”行。

如果语句是 DELETE ... LIMIT,那么它可能会越来越远地搜索以找到所需的行。

等!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。