Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql Optimize—从循环内的临时表中进行选择以获得JSON值的平均值的函数_Mysql_Json_Query Optimization_Query Performance - Fatal编程技术网

Mysql Optimize—从循环内的临时表中进行选择以获得JSON值的平均值的函数

Mysql Optimize—从循环内的临时表中进行选择以获得JSON值的平均值的函数,mysql,json,query-optimization,query-performance,Mysql,Json,Query Optimization,Query Performance,我有一个Mysql函数,它作为读取几百万条记录的更大查询的一部分运行。为了检测异常,我要计算出随时间的平均变化。表中的数据存储为JSON对象,UNIX时间戳作为键,最长可存储30天 例如,input_数组的外观如下所示: [{"1532944806": 16}, {"1533031206": 14}, {"1533117605": 13}, {"1533204305": 12}, {"1533290708": 10}, {"1533463506": 9}, {"1533549907": 9},

我有一个Mysql函数,它作为读取几百万条记录的更大查询的一部分运行。为了检测异常,我要计算出随时间的平均变化。表中的数据存储为JSON对象,UNIX时间戳作为键,最长可存储30天

例如,input_数组的外观如下所示:

[{"1532944806": 16}, {"1533031206": 14}, {"1533117605": 13}, {"1533204305": 12}, {"1533290708": 10}, {"1533463506": 9}, {"1533549907": 9}, {"1533636306": 9}, {"1533722707": 9}, {"1533809108": 9}, {"1533895506": 9}, {"1533981906": 8}, {"1534068306": 7}, {"1534154706": 7}, {"1534241108": 7}, {"1534590304": 7}, {"1534673106": 12}, {"1534759508": 6}, {"1534845905": 7}, {"1534932306": 7}, {"1535018707": 5}, {"1535105106": 3}, {"1535191505": 7}, {"1535277907": 6}, {"1535364305": 7}, {"1535450706": 2}, {"1535537107": 1}]
我只关注平均减少的变化,而不是一天内增加的任何变化

我正在检查前一天的值是否存在,如果存在,我将计算更改并将其添加到一个临时表中,在该临时表中查询以选择平均值

到目前为止,我已经:

CREATE FUNCTION `daily_averages`(input_array JSON) RETURNS int(4)
READS SQL DATA
DETERMINISTIC
BEGIN

    DECLARE array_length INTEGER(2);
    DECLARE prev_value INTEGER(4);
    DECLARE idx INTEGER(4);

    DROP TEMPORARY TABLE IF EXISTS collection;
    CREATE TEMPORARY TABLE collection (change INTEGER(4) SIGNED DEFAULT 0);

    SELECT JSON_LENGTH(input_array) INTO array_length;

    SET idx = 0;

    WHILE idx < array_length DO

        SELECT 

        IF(idx-1 > -1,
            CONVERT(
                JSON_EXTRACT(
                    JSON_EXTRACT(
                        JSON_EXTRACT( input_array, CONCAT( '$[', idx-1, ']' ) )
                        , '$.*'
                    )
                    , '$[0]'
                ), SIGNED INTEGER
            ) 
            , -1
        )

        INTO prev_value;


        INSERT INTO collection
        SELECT (prev_value - 
            (
                CONVERT(
                    JSON_EXTRACT(
                        JSON_EXTRACT(
                            JSON_EXTRACT( input_array, CONCAT( '$[', idx, ']' ) )
                            , '$.*'
                        )
                        , '$[0]'
                    ), SIGNED INTEGER
                )
            )
       )
       FROM DUAL
       WHERE prev_value > 0;

       SET idx = idx + 1;

    END WHILE;

    RETURN (SELECT AVG(change) FROM collection WHERE change > -1);

END

目前大约有270万条记录,运行大约需要20分钟。我希望通过避免删除/创建开销来优化或重新编写它。

创建一个表只是为了计算平均值似乎是不必要的,在循环中这样做很简单。不要将每个值插入表中,而是将其添加到总变量中。最后,返回总计/计数

因为你要计算价值观之间的差异

您也可以使用SET语句来分配变量,而不是选择。。。变为变量


挖掘一百万个JSON字符串。我很惊讶只花了20分钟

插入行时,进行一些计算并将结果存储在某个位置。然后用它来做监控

即使在插入行时无法执行此操作,也只能对“新”行执行此操作。再次将以前的信息保存到某个地方

至于删除/创建。。。通过拥有一个永久表,然后在每次proc调用开始时只使用TRUNCATE table,可以加快速度


整数4中的4没有任何意义。您将始终得到一个32位整数。此注释可能对过程没有影响。

prev\u值必须在循环内。它不是数组的第一个值,而是当前数组的前一个值。但除此之外,这可能有效。将进行测试。循环从idx=1开始,因此第一个数组元素是初始prev_值。这样,当prev_值尚未设置时,循环不需要IF语句对第一次迭代进行特殊处理。Ahh。对现在我明白了。聪明。一旦编辑被接受,我会接受这个答案。
DECLARE array_length INTEGER(2);
DECLARE prev_value INTEGER(4);
DECLARE idx INTEGER(4);
DECLARE total INTEGER(4);
DECLARE counter INTEGER(4);
DECLARE cur_value INTEGER(4);

SET array_length = JSON_LENGTH(input_array);
SET total = 0;
SET counter = 0;
-- Initialize prev_value to the first element
SET prev_value = CONVERT(
                JSON_EXTRACT(
                    JSON_EXTRACT(
                        JSON_EXTRACT( input_array, '$[0]' )
                        , '$.*'
                    )
                    , '$[0]'
                ), SIGNED INTEGER
            );
SET idx = 1;

WHILE idx < array_length DO
    SET cur_value = CONVERT(
                JSON_EXTRACT(
                    JSON_EXTRACT(
                        JSON_EXTRACT( input_array, CONCAT( '$[', idx, ']' ) )
                        , '$.*'
                    )
                    , '$[0]'
                ), SIGNED INTEGER
            );
    IF cur_value < prev_value
    THEN
        SET total = total + (prev_value - cur_value);
        SET counter = counter + 1;
    END IF;
    SET prev_value = cur_value;
    SET idx = idx + 1;
END WHILE;

RETURN total / counter;