簡體   English   中英

MySQL 5.7 - JSON 索引 - 生成具有非標量值的列

[英]MySQL 5.7 - JSON Indexing - Generated Columns with non-scalar values

我一直在研究 MySQL 5.7 中的 JSON 支持。 我對出於索引目的生成的列有幾個問題。 https://dev.mysql.com/doc/refman/5.7/en/create-table.html#create-table-secondary-indexes-virtual-columns

具體參考這一行:

無法為 JSON 列編制索引。 您可以通過在從 JSON 列中提取量值的生成列上創建索引來解決此限制。

這對我來說似乎是一個很大的限制。 無論我在哪里,人們都建議使用生成的列。 但該解決方法適用於非常有限的一組用例。 或者,我理解錯了。

搭建舞台

讓我解釋一下我的用例。 假設您有一個名為standards的表。 它具有以下結構:

CREATE TABLE `standards` (
  `id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `sections` json DEFAULT NULL,
  `subjects` json DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

sections列包含一個 JS 對象數組:

[
  {
    "id": 90491,
    "name": "A",
  },
  {
    "id": 90494,
    "name": "B",
  }
]

subjects列包含一個嵌套的 JS 對象:

{
  "576845": {
    "id": 576845,
    "name": "Computer Education"
  },
  "576848": {
    "id": 576848,
    "name": "English Language"
  },
  "576854": {
    "id": 576854,
    "name": "Environmental Science"
  },
  "576860": {
    "id": 576860,
    "name": "Mathematics"
  }
}

示例查詢

查詢 1

要查找section ID90494Standard記錄,查詢將是:

SELECT * from standards WHERE JSON_CONTAINS( sections->>'$[*].id', '90494' );

查詢 2

要查找subject ID576854Standard記錄,查詢將是:

SELECT * from standards WHERE JSON_CONTAINS_PATH( subjects, 'one', '$."576854"');

要么

SELECT * from standards WHERE JSON_CONTAINS( subjects->>'$.*.id', '576854' );

問題

現在,以上所有的工作。 問題是查詢執行全表掃描。

考慮上面的查詢 1,我如何生成一個包含所有section IDs標量數據的虛擬列?

每個Standard記錄都有多個sections ,具有多個 ID。 所以,我不能只創建一個整數虛擬列來存儲單個值。 它必須是一個節 ID 數組,我們需要通過它進行搜索。

因此,我生成的列如下所示:

ALTER TABLE standards
ADD section_ids json GENERATED ALWAYS AS (sections->>'$[*].id') VIRTUAL NOT NULL;

生成的列現在將僅存儲部分 ID 數組。 但是我不能在生成的列上添加索引,因為它又是一個 JSON 列。

問題 - 如何使用索引?

所以,問題歸結為 - 對於上面顯示的查詢,我如何避免全表掃描?

任何建議,將不勝感激。

我不會說 MySQL 5.7 是不可能的——因為它有笨重的變通方法和限制——但我不會討論如何使用該版本,因為它要困難得多,而且在許多方面都會有限制情況下,如果可以將大量項目添加到數組中,則可以達到。

但是,從現在支持多值索引的 MySQL 8.0.17開始是可能的。

ALTER TABLE standards
  ADD INDEX section_ids ( (CAST(sections->'$[*].id' AS UNSIGNED ARRAY)) ),
  ADD INDEX subject_ids ( (CAST(subjects->'$.*.id'AS UNSIGNED ARRAY)) );

** 請注意$.*將采用所有對象屬性並返回每個格式化為數組的查詢值 ( .id )。

EXPLAIN SELECT * from standards WHERE JSON_CONTAINS( sections->'$[*].id', '90494' );
EXPLAIN SELECT * from standards WHERE JSON_CONTAINS( subjects->'$.*.id', 576854 );

您將看到索引用於這些查詢。

我會在舊版本中通過手動創建一個單獨的索引表並使用觸發器使其保持最新來解決這個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM