在 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 代码段,time
和 some_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`);
我经常从一些 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 代码段,time
和 some_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 时间戳 创建一个有效的 - 创建生成的(虚拟)列
PERSISTENT
- 使用数据类型
DATETIME
而不是TIMESTAMP
DATETIME
因此新代码如下所示:
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`);