【问题标题】:Why is MEMBER OF() faster than JSON_CONTAINS()?为什么 MEMBER OF() 比 JSON_CONTAINS() 快?
【发布时间】:2020-04-19 15:12:11
【问题描述】:

我正在使用 MySQL 8 的新 JSON 功能,尤其是多值索引。

我注意到有两种方法可以检查 JSON 数组是否包含给定值:MEMBER OF() 运算符和JSON_CONTAINS() 函数。

对于我进行的每个查询,它们都返回相同的结果集,但令人惊讶的是,MEMBER OF 似乎比 JSON_CONTAINS 快​​ 3 倍。

以具有 200,000 条记录的表为例,catIds 字段中总共有大约 700,000 个值:

CREATE TABLE test (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  catIds JSON NOT NULL,
  PRIMARY KEY (id),
  KEY test_categories ((CAST(catIds AS UNSIGNED ARRAY)))
);

INSERT INTO test (catIds) VALUES('[123, 456]');
...

...稍后插入了大约 200,000 条记录:

mysql> SELECT count(*) FROM test WHERE 51 member of (catIds);
+----------+
| count(*) |
+----------+
|     7287 |
+----------+
1 row in set (0.11 sec)

mysql> SELECT count(*) FROM test WHERE JSON_CONTAINS(catIds, '51');
+----------+
| count(*) |
+----------+
|     7287 |
+----------+
1 row in set (0.36 sec)

如果最初认为这是因为字符串化的 JSON 值 '51' 可能在每次迭代时都被转换,所以我尝试先将其分配给变量;但这并没有让它变得更快:

mysql> SET @value = CAST(51 as JSON);
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT count(*) FROM test WHERE JSON_CONTAINS(catIds, @value);
+----------+
| count(*) |
+----------+
|     7287 |
+----------+
1 row in set (0.38 sec)

除非我弄错了,MEMBER OF()JSON_CONTAINS() 在功能方面是等效的。在这种情况下,为什么其中一个比另一个快?

【问题讨论】:

  • “除非我记错了,否则 MEMBER OF() 和 JSON_CONTAINS() 在功能方面是等效的。” 您是否比较了他们的文档页面来确认这一点?
  • @LightnessRacesBY-SA3.0 我确实说得有点快。

标签: mysql json mysql-8.0


【解决方案1】:

JSON_CONTAINS()MEMBER OF 做的工作更复杂。

JSON_CONTAINS() 必须解析它的第二个参数,即您在存储的 JSON 文档中搜索的候选 JSON 文档。

候选对象可能不是您在上面的示例中搜索的简单标量。它可能是一个更复杂的文档,有自己的嵌套数组和对象。

因此,将候选对象与存储的文档进行比较必须可能以更复杂的方式进行比较,而不仅仅是搜索单个标量值,而是递归地比较所有嵌套元素。

即使您的示例搜索是一个简单的标量值,它仍然会调用 可能 需要搜索复杂文档的相同代码路径。根据您的时序测量,该代码路径似乎有更多开销。

MEMBER OF 只搜索标量值,并且只搜索数组。它还可以通过使用缓存的预排序数组进行优化。

代码见https://github.com/mysql/mysql-server/blob/8.0/sql/item_json_func.cc#L3852

【讨论】:

    猜你喜欢
    • 2020-04-20
    • 2019-02-11
    • 2019-11-02
    • 2011-08-20
    • 1970-01-01
    • 2015-07-24
    相关资源
    最近更新 更多