在 JSON 提供的时间戳上创建索引 - 不正确的日期时间值

Create index on timestamp delivered by JSON - incorrect datetime value

我经常从一些 API 中检索 JSON 数据,并将这些数据放入 MariaDB table。 JSON 带有一个时间戳,我想在上面放置一个索引,因为这个属性用于查询 table.

JSON 看起来像这样(已剥离):

{
    "time": "2021-12-26T14:00:00.007294Z",
    "some_measure": "0.10031"
}

我创建一个 table:

CREATE TABLE some_table (
    my_json JSON NOT NULL,
    time TIMESTAMP AS (JSON_VALUE(my_json , '$.time')),
    some_measure DOUBLE AS (JSON_VALUE(my_json , '$.some_measure'))
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;

my_json 包含整个 JSON 代码段,timesome_measure 是虚拟列,可以动态正确提取相应的 JSON 值。

现在,尝试在 TIMESTAMP 属性上添加索引:

CREATE INDEX some_index ON some_table (time);

这失败了:

SQL Error [1292] [22007]: (conn=454) Incorrect datetime value:
'2021-12-26T14:00:00.007294Z' for column `some_db`.`some_table`.`time` at row 1

如何在该时间戳上添加索引?

这里的问题是将字符串(JSON 时间戳)转换为 TIMESTAMP 是不确定的,因为它涉及服务器端设置(sql_mode)和时区设置。

不支持索引不确定的虚拟列。

您可能希望改用 VARCHAR 数据类型并为其编制索引:

CREATE TABLE some_table (
    my_json JSON NOT NULL,
    time VARCHAR(100) AS (JSON_VALUE(my_json , '$.time')),
    some_measure DOUBLE AS (JSON_VALUE(my_json , '$.some_measure'))
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;

您应该能够创建索引:

CREATE INDEX some_index ON some_table (`time`);

您仍然可以查询时间,因为如果针对 VARCHAR 使用 MariaDB 会自动转换 DATETIME:

SELECT
  *
FROM some_table
WHERE time > '2008-12-31 23:59:59' + INTERVAL 1 SECOND;

查询将使用索引:

我终于想出了一个适合我的解决方案。 变化是:

  • 使用 STR_TO_DATE() 从 JSON 时间戳
  • 创建一个有效的 DATETIME
  • 创建生成的(虚拟)列PERSISTENT
  • 使用数据类型 DATETIME 而不是 TIMESTAMP

因此新代码如下所示:

CREATE TABLE some_table (
    my_json JSON NOT NULL,
    time DATETIME AS (STR_TO_DATE((JSON_VALUE(my_json , '$.time')), '%Y-%m-%d%@%T%.%#%@')) PERSISTENT,
    some_measure DOUBLE AS (JSON_VALUE(my_json , '$.some_measure'))
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;

CREATE INDEX some_index ON some_table (`time`);